<<>> <> <> <> <> <> <> <> DIRECTORY RefText, Rope, UXStrings; UXStringsImpl: CEDAR MONITOR IMPORTS RefText, Rope EXPORTS UXStrings ~ BEGIN OPEN UXStrings; ToRope: PUBLIC PROC [from: CString, maxLength: INT ¬ LAST[INT]] RETURNS [r: Rope.ROPE] = TRUSTED { len, pos: INT ¬ 0; PerChar: PROC RETURNS [c: CHAR] = TRUSTED { c ¬ from­[pos]; pos ¬ pos+1; }; IF from=NIL THEN RETURN[NIL]; WHILE from­[len]#'\000 AND len < maxLength DO len ¬ len + 1 ENDLOOP; IF len = 0 THEN RETURN[NIL]; RETURN [Rope.FromProc[len, PerChar]]; }; CharSequence: TYPE ~ RECORD[ seq: PACKED SEQUENCE COMPUTED CARD OF CHAR ]; Create: PUBLIC PROC [from: REF] RETURNS [string: CString] = { WITH from SELECT FROM r: Rope.ROPE => { len: INT ¬ Rope.Length[r]; rtn: REF CharSequence ¬ NEW[CharSequence[len+1]]; TRUSTED { FOR i: INT IN [0..len) DO rtn[i] ¬ r.Fetch[i] ENDLOOP; rtn[len] ¬ '\000; }; string ¬ LOOPHOLE[rtn]; }; r: REF TEXT => { len: INT ¬ RefText.Length[r]; rtn: REF CharSequence ¬ NEW[CharSequence[len+1]]; TRUSTED { FOR i: INT IN [0..len) DO rtn[i] ¬ r[i] ENDLOOP; rtn[len] ¬ '\000; }; string ¬ LOOPHOLE[rtn]; }; ENDCASE => IF from=NIL THEN TRUSTED { rtn: REF CharSequence ¬ NEW[CharSequence[1]]; rtn[0] ¬ '\000; string ¬ LOOPHOLE[rtn]; } ELSE ERROR; --not implemented type }; CreateSpace: PUBLIC PROC [size: INT] RETURNS [string: CString] ~ { rtn: REF CharSequence ¬ NEW[CharSequence[size+1]]; string ¬ LOOPHOLE[rtn]; }; CopyRefToString: PUBLIC UNSAFE PROC [ref: REF, string: CString] ~ UNCHECKED { rtn: REF CharSequence ¬ LOOPHOLE[string]; WITH ref SELECT FROM r: Rope.ROPE => { len: INT ¬ Rope.Length[r]; TRUSTED { FOR i: INT IN [0..len) DO rtn[i] ¬ r.Fetch[i] ENDLOOP; rtn[len] ¬ '\000; }; }; r: REF TEXT => { len: INT ¬ RefText.Length[r]; TRUSTED { FOR i: INT IN [0..len) DO rtn[i] ¬ r[i] ENDLOOP; rtn[len] ¬ '\000; }; }; ENDCASE => IF ref=NIL THEN TRUSTED { rtn[0] ¬ '\000; } ELSE ERROR; --not implemented type }; ViewRefText: PUBLIC UNSAFE PROC [from: REF TEXT] RETURNS [string: CString] ~ { RETURN[ LOOPHOLE[LOOPHOLE[from, CARD]+UNITS[TEXT[0]]]] }; <> StringIndex: TYPE = [0..1]; StringMaxLength: ARRAY StringIndex OF INT = [100, 512]; NStringsToAllocate: ARRAY StringIndex OF NAT = [8, 2]; available: ARRAY StringIndex OF LIST OF CString ¬ ALL[NIL]; reserved: ARRAY StringIndex OF LIST OF CString ¬ ALL[NIL]; InterestingQuantity: TYPE = {obtainCalled, nCharsTooLarge, availEmpty}; Counts: ARRAY InterestingQuantity OF INT ¬ ALL[0]; Bump: INTERNAL PROC [q: InterestingQuantity] = INLINE { Counts[q] ¬ Counts[q] + 1 }; Error: PUBLIC ERROR [ec: ErrorCode] = CODE; CreateScratch: PUBLIC PROC [from: REF] RETURNS [string: CString] ~ { WITH from SELECT FROM r: Rope.ROPE => { len: INT ¬ Rope.Length[r]; rtn: POINTER TO CharSequence ¬ LOOPHOLE[ObtainScratch[len]]; TRUSTED { FOR i: INT IN [0..len) DO rtn[i] ¬ r.Fetch[i] ENDLOOP; rtn[len] ¬ '\000; }; string ¬ LOOPHOLE[rtn]; }; r: REF TEXT => { len: INT ¬ RefText.Length[r]; rtn: POINTER TO CharSequence ¬ LOOPHOLE[ObtainScratch[len]]; TRUSTED { FOR i: INT IN [0..len) DO rtn[i] ¬ r[i] ENDLOOP; rtn[len] ¬ '\000; }; string ¬ LOOPHOLE[rtn]; }; ENDCASE => IF from=NIL THEN TRUSTED { rtn: POINTER TO CharSequence ¬ LOOPHOLE[ObtainScratch[0]]; rtn[0] ¬ '\000; string ¬ LOOPHOLE[rtn]; } ELSE ERROR; --not implemented type }; <<>> ObtainScratch: PUBLIC ENTRY PROC [nChars: INT] RETURNS [CString] = TRUSTED { i: StringIndex ¬ 0; avail: LIST OF CString; Bump[obtainCalled]; FOR i IN [0 .. LAST[StringIndex]] DO IF nChars <= StringMaxLength[i] THEN EXIT; REPEAT FINISHED => { <> Bump[nCharsTooLarge]; RETURN [CreateSpace[nChars]]; }; ENDLOOP; IF (avail ¬ available[i].rest) = NIL THEN { <> r: LIST OF CString; Bump[availEmpty]; r ¬ reserved[i]; UNTIL r.rest.rest = NIL DO r ¬ r.rest ENDLOOP; avail ¬ r.rest; r.rest ¬ NIL; avail.first ¬ CreateSpace[StringMaxLength[i]] }; <> available[i].rest ¬ avail.rest; avail.rest ¬ reserved[i].rest; reserved[i].rest ¬ avail; IF avail.first[0] # '\000 THEN RETURN WITH ERROR Error[clientModifiedReleasedString]; RETURN [avail.first]; }; ReleaseScratch: PUBLIC ENTRY PROC [s: CString] = TRUSTED { i: StringIndex ¬ 0; r, l: LIST OF CString; IF s = NIL THEN RETURN; FOR i IN [0 .. LAST[StringIndex]] DO r ¬ reserved[i]; WHILE (l ¬ r.rest) # NIL DO IF l.first = s THEN { r.rest ¬ l.rest; l.rest ¬ available[i].rest; available[i].rest ¬ l; s[0] ¬ '\000; RETURN; }; r ¬ l; ENDLOOP; ENDLOOP; }; InitializeScratchPool: ENTRY PROC [] = { FOR i: StringIndex IN StringIndex DO reserved[i] ¬ CONS[NIL, NIL]; <> FOR j: NAT IN [0..NStringsToAllocate[i]] DO available[i] ¬ CONS[NIL, available[i]]; ENDLOOP; ENDLOOP; FOR i: StringIndex IN StringIndex DO <> l: LIST OF CString ¬ available[i].rest; WHILE l # NIL DO l.first ¬ CreateSpace[StringMaxLength[i]]; l ¬ l.rest; ENDLOOP; ENDLOOP; }; InitializeScratchPool[]; END. <> <>