(* 10 The Unbounded Character String (continued) An unbounded implementation of the String abstraction, described in Chapter 8, is presented here. This particular form has the properties: Sequential, Unbounded, Managed, and Non-Iterator, describing specific aspects of the implementation as follows: Sequential: Can only be used in a non-tasking environment, or by only one task. Unbounded: The size of a string varies dynamically as items are inserted and removed from the string. Managed: Memory space for items and objects is returned to the system when no longer needed. Non-Iterator: Routines for looping over each of the string items are provided. As noted in the previous chapter on the bounded string form, strings are nearly always formed of characters, or items that can be represented using characters, we use the Character Items module instead of the more generic Items module. There is one limitation in the implementation presented here: strings are limited to a maximum length of 32,000 characters. This is primarily due to the TML Modula-2 compiler excluding the type LONGINT and LONGCARD as array index types. Section 10.3 contains the interface to the unbounded string module while the implementation follows in Section 10.4. 10.3 StringCSUMN Interface *) DEFINITION MODULE StrCSUMN; (*============================================================ Version : 1.00 29 Apr 1989 C. Lins Compiler : TopSpeed Modula-2 Compiler Component: Monolithic Structure - String Character Sequential Unbounded Managed Non-Iterator THE ABSTRACTION This module provides a String abstraction limited to CHARs REVISION HISTORY v1.00 29 Apr 1989 C. Lins: Initial JPI Modula-2 implementation. ============================================================*) FROM ErrorHandling IMPORT (*--Type*) HandlerProc; FROM CharItems IMPORT (*--Type*) Item; FROM Relations IMPORT (*--Type*) Relation; FROM StrEnum IMPORT (*--Type*) Exceptions; (*-----------------------*) TYPE String; TYPE Position = [ 1 .. 32000 ]; CONST NullString = String(NIL); (* 10.3.1 Exceptions The ModuleID is used by the exception handling mechanism to distinguish this module from all other modules. StringError returns the exception code from the most recent string operation. A result of noerr indicates successful completion of the operation. GetHandler returns the exception handler routine associated with the given exception. Though the routine is a function procedure returning a procedure as its result, the HandlerProc may not be called from within the GetHandler call itself. The procedure result must be first assigned to a procedure variable before invocation. Exception handlers are given an initial value of ExitOnError except for the handler for noerr which is initialized to the null exception handler. For example, the statement GetHandler(overflow)(someErrorCode); would be flagged as an error by the compiler. SetHandler associates an exception handler routine with the given exception and is the inverse of GetHandler. This routine may be used to override the default settings for the exception handlers. *) CONST ModuleID = 4; PROCEDURE StringError () : Exceptions (*-- out *); PROCEDURE GetHandler ( ofError : Exceptions (*-- in *)) : HandlerProc (*-- out *); PROCEDURE SetHandler ( ofError : Exceptions (*-- in *); toHandler : HandlerProc (*-- in *)); (* 10.3.2 Constructors The Create operation attempts to generate a new, empty, unbounded string. Since this module uses character items all the standard operations, (such as assignment and comparison), can be done directly; user-defined routines are not needed. Create will return the new string upon successful completion of the routine. If it not possible for the string to be created, the constant NullString will be returned instead. Destroy takes the given string, clears it of any items, and then destroys the string itself. Where Create defines a string, Destroy is its inverse, making the string undefined. Clear takes the given string and removes all of its items. Clearing the string returns it to the empty state. The Assign operation attempts to generate a duplicate of the source string (theString) in the target string (toString). The target string is automatically created, if necessary, otherwise the target is simply cleared of its present contents. Prepend adds the first string to the beginning of the second string, Append adds the first string to the end of the second string, while Insert adds adds the first string to the second string at the given string index position. Delete removes characters from the given string between the given index positions, inclusive. Replace removes characters from the given string from the given index position to the end of the string and then inserts the replacement string at the end of the given source string. The length of the source string may grow due to the effects of the replacement. SetItem changes a single character of the source string at the specified index position. Construct allows one to build a dynamic string from the usual Modula-2 string form. *) PROCEDURE Create () : String (*-- out *); PROCEDURE Destroy (VAR theString : String (*-- inout *)); PROCEDURE Clear (VAR theString : String (*-- inout *)); PROCEDURE Assign ( theString : String (*-- in *); VAR toString : String (*-- inout *)); PROCEDURE Prepend ( theString : String (*-- in *); VAR toString : String (*-- inout *)); PROCEDURE Append ( theString : String (*-- in *); VAR toString : String (*-- inout *)); PROCEDURE Insert ( theString : String (*-- in *); VAR toString : String (*-- inout *); theIndex : Position (*-- in *)); PROCEDURE Delete (VAR theString : String (*-- inout *); fromIndex : Position (*-- in *); toIndex : Position (*-- in *)); PROCEDURE Replace (VAR theString : String (*-- inout *); theIndex : Position (*-- in *); withString : String (*-- in *)); PROCEDURE SetItem (VAR theString : String (*-- inout *); theIndex : Position (*-- in *); theItem : Item (*-- in *)); PROCEDURE Construct (VAR theString : String (*-- inout *); theSubstring: ARRAY OF Item (*-- in *)); (* 10.3.3 Selectors IsDefined attempts to determine whether the given string is valid, e.g., has been created and not yet destroyed. How this is accomplished may be as simple or complicated as the implementer desires and the requirements of the application. IsEmpty returns true if the given string contains no items, and false otherwise. Undefined strings are considered empty. LengthOf returns the number of characters present in the string. The function result is declared CARDINAL (instead of Position) as an undefined string returns zero. Compare establishes the ordering relation between two strings. IsEqual returns true if two strings contain the same items. ItemOf retrieves a single item at the given index position from the string; SliceOf returns a contiguous sequence of characters from a string between two index positions; and SubstringOf returns the whole string as a contiguous sequence of characters. Both SliceOf and SubstringOf terminate their results with 0C if necessary by the rules of Modula-2. *) PROCEDURE IsDefined ( theString : String (*-- in *)) : BOOLEAN (*-- out *); PROCEDURE IsEmpty ( theString : String (*-- in *)) : BOOLEAN (*-- out *); PROCEDURE LengthOf ( theString : String (*-- in *)) : CARDINAL (*-- out *); PROCEDURE Compare ( left : String (*-- in *); right : String (*-- in *)) : Relation (*-- out *); PROCEDURE IsEqual ( left : String (*-- in *); right : String (*-- in *)) : BOOLEAN (*-- out *); PROCEDURE ItemOf ( theString : String (*-- in *); theIndex : Position (*-- in *)) : Item (*-- out *); PROCEDURE SliceOf ( theString : String (*-- in *); fromIndex : Position (*-- in *); toIndex : Position (*-- in *); VAR theSlice : ARRAY OF Item (*-- out *)); PROCEDURE SubstringOf( theString : String (*-- in *); VAR toSubstring: ARRAY OF Item (*-- out *)); END StrCSUMN.