DIRECTORY Basics USING [Comparison], PrincOps USING [zLI1, zLI0, zBNDCK], Rope USING [ActionType, Compare, Equal, Find, Map, Match, SkipOver, SkipTo, ROPE, Text]; RefText: CEDAR DEFINITIONS IMPORTS Rope = BEGIN ROPE: TYPE = Rope.ROPE; MaxLen: NAT = NAT.LAST; New: PROC [nChars: NAT] RETURNS [REF TEXT]; ObtainScratch: PROC [nChars: NAT] RETURNS [REF TEXT]; line: NAT = 100; page: NAT = 512; Error: ERROR [ec: ErrorCode]; ErrorCode: TYPE = { clientModifiedReleasedText }; ReleaseScratch: PROC [t: REF TEXT]; Append: PROC [ to: REF TEXT, from: REF READONLY TEXT, start: NAT _ 0, len: NAT _ MaxLen] RETURNS [REF TEXT]; AppendTextRope: PROC [ to: REF TEXT, from: Rope.Text, start: NAT _ 0, len: NAT _ MaxLen] RETURNS [REF TEXT] = INLINE { RETURN[Append[to, TrustTextRopeAsText[from], start, len]]; }; AppendRope: PROC [ to: REF TEXT, from: ROPE, start: NAT _ 0, len: NAT _ MaxLen] RETURNS [REF TEXT]; AppendChar: PROC [to: REF TEXT, from: CHAR] RETURNS [REF TEXT]; InlineAppendChar: PROC [to: REF TEXT, from: CHAR] RETURNS [REF TEXT] = INLINE { IF to.length >= to.maxLength THEN RETURN [AppendChar[to, from]]; to[to.length] _ from; to.length _ to.length + 1; RETURN [to]; }; ReserveChars: PROC [to: REF TEXT, nChars: NAT] RETURNS [REF TEXT]; InlineReserveChars: PROC [to: REF TEXT, nChars: NAT] RETURNS [REF TEXT] = INLINE { IF LOOPHOLE[to.maxLength, INTEGER]-LOOPHOLE[nChars, INTEGER] < LOOPHOLE[to.length, INTEGER] THEN RETURN [ReserveChars[to, nChars]]; RETURN [to]; }; Compare: PROC [s1, s2: REF READONLY TEXT, case: BOOL _ TRUE] RETURNS [Basics.Comparison] = INLINE { RETURN [Rope.Compare[TrustTextAsRope[s1], TrustTextAsRope[s2], case]]}; Equal: PROC [s1, s2: REF READONLY TEXT, case: BOOL _ TRUE] RETURNS [BOOL] = INLINE { RETURN [Rope.Equal[TrustTextAsRope[s1], TrustTextAsRope[s2], case]]}; Fetch: PROC [base: REF READONLY TEXT, index: NAT] RETURNS [CHAR] = INLINE { IF base = NIL OR index > base.length THEN BoundsFault[]; RETURN [base[index]]}; Find: PROC [s1, s2: REF READONLY TEXT, pos1: NAT _ 0, case: BOOL _ TRUE] RETURNS [INTEGER] = INLINE { RETURN [Rope.Find[TrustTextAsRope[s1], TrustTextAsRope[s2], pos1, case]]}; Length: PROC [base: REF READONLY TEXT] RETURNS [NAT] = INLINE { RETURN [IF base = NIL THEN 0 ELSE base.length]}; Map: PROC [s: REF READONLY TEXT, start: NAT _ 0, len: NAT _ MaxLen, action: ActionType] RETURNS [quit: BOOL] = INLINE { RETURN [Rope.Map[TrustTextAsRope[s], start, len, action]]}; ActionType: TYPE = PROC [CHAR] RETURNS [BOOL]; Match: PROC [pattern, object: REF READONLY TEXT, case: BOOL _ TRUE] RETURNS [BOOL] = INLINE { RETURN [Rope.Match[TrustTextAsRope[pattern], TrustTextAsRope[object], case]]}; SkipTo: PROC [s: REF READONLY TEXT, pos: NAT _ 0, skip: REF READONLY TEXT] RETURNS [NAT] = INLINE { RETURN [Rope.SkipTo[TrustTextAsRope[s], pos, TrustTextAsRope[skip]]]}; SkipOver: PROC [s: REF READONLY TEXT, pos: NAT _ 0, skip: REF READONLY TEXT] RETURNS [NAT] = INLINE { RETURN [Rope.SkipOver[TrustTextAsRope[s], pos, TrustTextAsRope[skip]]]}; TrustTextAsRope: PROC [text: REF READONLY TEXT] RETURNS [Rope.Text] = INLINE { TRUSTED {RETURN [LOOPHOLE[text]]}}; TrustTextRopeAsText: PROC [rope: Rope.Text] RETURNS [REF READONLY TEXT] = INLINE { TRUSTED {RETURN [LOOPHOLE[rope]]}}; BoundsFault: PROC = TRUSTED MACHINE CODE { PrincOps.zLI1; PrincOps.zLI0; PrincOps.zBNDCK}; END. ΊRefText.mesa This interface contains procedures for manipulating mutable garbage-collected strings (REF TEXT). It is largely parallel to the Rope interface. Last edited by: MBrown on September 16, 1983 2:52 pm Paul Rovner on August 8, 1983 11:48 am Russ Atkinson on August 26, 1982 5:35 pm This interface includes some simple procedures for REF TEXT. As much as possible the operations are parallel to the Rope interface's operations on ROPE. When reading from a REF TEXT, the package treats NIL and "" equivalently (Length[NIL] = 0, Fetch[NIL, 0] raises BoundsFault). But Appending to a NIL REF TEXT raises PointerFault. Only the New operation below allocates collectable storage. If you are doing large numbers of REF TEXT allocations, maybe you should be using ROPE. In a "piece" defined by [s: REF TEXT, start: NAT, len: NAT], len is interpreted as follows: IF start > s.length THEN BoundsFault ELSE len _ MIN[len, s.length-start]. The resulting len value is called the "effective len" below. A boolean "case" parameter should be understood to mean "case significant". If case, upper case characters are treated as distinct from lower case characters. If ~case, upper case characters are converted to lower case before comparison. Creating TEXT Allocates a TEXT with length = 0, maxLength = nChars, and returns a REF to it. Some programs allocate and discard TEXT frequently. To improve the performance of these programs, the RefText package manages a small pool of "scratch" TEXTs. The expected usage of this pool is for a client to get a scratch TEXT using the ObtainScratch procedure, manipulate this TEXT for awhile, and then return it to the pool using ReleaseScratch. A client who retains a REF to a scratch TEXT after releasing it is not playing by the rules (the same TEXT will surely be handed out to someone else), but this is still "safe" in the Cedar sense (the storage invariants are not compromised by the error). ! Error [clientModifiedReleasedText] Returns a REF to a TEXT from with length = 0, maxLength >= nChars. This TEXT is generally obtained from a pool of TEXTs. A call to ObtainScratch is less expensive than New, but ObtainScratch should only be called with the expectation of calling ReleaseScratch (below) later on the resulting TEXT. (It is ok for a client to occasionally "forget" to release a TEXT obtained with this procedure, so for instance there is no need to call ReleaseScratch in UNWIND catch phrases unless UNWIND is expected most of the time!) Raises Error [clientModifiedReleasedText] if the TEXT it wanted to return has been tampered with (in a detectable way) since it was released with ReleaseScratch; this indicates that some client is not playing by the rules. Caller asserts that it has no further interest in the TEXT pointed to by t. Noop if t was not obtained from scratch pool. Writing TEXT ! PointerFault (if to = NIL) ! BoundsFault (if to.length > to.maxLength or length of result text would exceed MaxLen) ! PointerFault (if to = NIL) ! BoundsFault (if to.length > to.maxLength or length of result text would exceed MaxLen) ! PointerFault (if to = NIL) ! BoundsFault (if to.length > to.maxLength or length of result text would exceed MaxLen) ! PointerFault (if to = NIL) ! BoundsFault (if to.length > to.maxLength or length of result text would exceed MaxLen) ! PointerFault (if to = NIL) ! BoundsFault (if to.length > to.maxLength or length of result text would exceed MaxLen) ! PointerFault (if to = NIL) ! BoundsFault (if length of result text would exceed MaxLen) The client wishes to append nChars characters to the REF TEXT to without overflowing it. The result text t satisfies (1) Compare[to, t] = $equal, and (2) to.maxLength >= to.length + nChars. ! PointerFault (if to = NIL) ! BoundsFault (if length of result text would exceed MaxLen) Reading TEXT returns lexicographic comparison of the REF TEXT contents case => case of characters is significant returns s1 = s2 (true iff s1 and s2 contain same sequence of characters, modulo the case parameter) ! BoundsFault (if base = NIL or index > base.length) fetches indexed character from given REF TEXT. returns position in s1 where s2 occurs (starts looking at pos1) does NOT do *-matching (use Match below for this) returns -1 if not found (including pos1 >= Length[s1]) returns the length of the REF TEXT (0 if NIL). ! BoundsFault (if start > s.length) Applies the action to each char in the given piece of s, in ascending order, until action[char] = TRUE or no more chars. Returns TRUE iff stopped by action[char] = TRUE. Returns TRUE iff object matches the pattern, where the pattern may contain * to indicate that 0 or more characters will match. If case is true, then case matters. Examine s[pos .. s.length), and return the lowest index in this range such that s[i] is contained in the "skip" string. If no such character exists, return s.length. Examine s[pos .. s.length), and return the lowest index in this range such that s[i] is NOT contained in the skip string. If no such character exists, return s.length. Miscellaneous it is sometimes OK to treat a REF TEXT as a ROPE you will be surprised only when looking at the type at runtime OR when you alter the text it is sometimes OK to treat a Rope.Text as a REF TEXT. you must promise not to modify it! Κ˜headšœ ™ bodyšœWΟkœ1™šœ™Jšœ$™$Jšœ&™&Jšœ(™(———˜š ˜ Jšœœ˜Jšœ œ˜$šœœBœ˜XJ˜———š Πblœœ œœ˜/Jšœœœ˜—˜Jšœ3œYœ™™J˜Jš œœœœ œ.œœ™³J˜Jšœ_œ(œ™”J˜Jšœœ7™[JšœI™IJšœ<™™N—J™Jšœ#œrœEœ4œZœœ:œ“™ήš Ÿ œœ œœœœ˜5Jšœ$™$Jš œ œœ2œ&œ™yJš œͺœ@œZœœ™Jšœ1œͺ™ίMšœœ˜Jšœœ˜—Mšœœ˜Jšœ œ"˜1šŸœœœœ˜#Jšœ6œ™KJ™-J˜—J™Jšœ™ J˜šŸœœ˜Jšœœœœœœ œ œ ˜IJšœœœ˜Jšœ™JšœX™X—šŸœœ˜Jš œœœœ œ ˜AJšœœœœ˜Jšœ™JšœX™XJšœ4˜:J˜—šŸ œœ˜Jš œœœœ œ œ ˜Jšœ œ œ˜D—Jšœ˜ Jšœ˜—J™Jšœ™ šŸœ˜ Jš œ œœœœœ˜.Jšœœ˜&Jšœ(œ ™9Jšœ)™)JšœA˜G—šŸœ˜ Jšœ œœœœœœœœ˜HJšœH™HJšœ™Jšœ@˜F—šŸœ˜ Jšœœœœ œœœœ˜?Jšœ4™4Jšœ%œ™.Jšœœœœ˜8Jšœ˜—šŸœ˜ Jš œ œœœœ œœ˜=Jšœœœ˜Jšœ?™?Jšœ1™1Jšœ6™6JšœE˜K—šŸœœœœœœœœ˜?Jšœœ ™.Jš œœ œœœ˜1—šŸœ˜ Jš œœœœ œ œ˜MJšœœœ˜Jšœ#™#Jšœx™xJšœ0™0Jšœ5˜;Jš Ÿ œœœœœœ˜.—šŸœ˜ Jš œœœœœœ˜7Jšœœœ˜Jšœ~™~Jšœ$™$JšœH˜N—šŸœ˜ Jšœœœœœ œœœ˜=Jšœœœ˜Jšœ¦™¦JšœA˜G—šŸœ˜Jšœœœœœ œœœ˜=Jšœœœ˜Jšœ¨™¨JšœB˜H—J™J™ šŸœœœœœœœ˜NJšœœœ ˜#Jšœœ™0JšœY™Y—šŸœœœœœœœ˜RJšœœœ ˜#Jšœ-œ™6J™"—š Ÿ œœœœœ˜*Jšœ/˜/J˜—Jšœ˜J˜J˜——…— *C