<> <> <> <> DIRECTORY Ascii, ByteBlt, Inline, String; StringImpl: PROGRAM IMPORTS ByteBlt, Inline, String EXPORTS String = PUBLIC BEGIN OPEN String; StringBoundsFault: SIGNAL [s: LONG STRING] RETURNS [ns: LONG STRING] = CODE; AppendChar: PROCEDURE [s: LONG STRING, c: CHARACTER] = BEGIN IF s = NIL THEN RETURN; UNTIL s.length < s.maxlength DO temp: LONG STRING _ SIGNAL StringBoundsFault[s]; IF temp = NIL THEN RETURN; s _ temp; ENDLOOP; s[s.length] _ c; s.length _ s.length + 1; RETURN END; AppendString: PROCEDURE [to: LONG STRING, from: LONG STRING] = BEGIN n: CARDINAL; IF to = NIL OR from = NIL THEN RETURN; WHILE from.length + to.length > to.maxlength DO temp: LONG STRING _ SIGNAL StringBoundsFault[to]; IF temp = NIL THEN EXIT; -- just fill in as much as fits to _ temp; ENDLOOP; n _ MIN[from.length, LOOPHOLE[to.maxlength - to.length, CARDINAL]]; IF to.length MOD 2 = 0 THEN Inline.LongCOPY[ from: @from.text, to: to + SIZE[StringBody[to.length]], nwords: SIZE[StringBody[n]]-SIZE[StringBody[0]]] ELSE [] _ ByteBlt.ByteBlt[ from: [ blockPointer: LOOPHOLE[@from.text], startIndex: 0, stopIndexPlusOne: n], to: [ blockPointer: LOOPHOLE[@to.text], startIndex: to.length, stopIndexPlusOne: to.length + n]]; to.length _ to.length + n; RETURN END; Equal: PROCEDURE [s1, s2: LONG STRING] RETURNS [BOOLEAN] = BEGIN i: CARDINAL; IF s1 = NIL AND s2 = NIL THEN RETURN[TRUE]; IF s1 = NIL OR s2 = NIL OR s1.length # s2.length THEN RETURN[FALSE]; FOR i IN [0..s1.length) DO IF s1[i] # s2[i] THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE] END; Equivalent: PROCEDURE [s1, s2: LONG STRING] RETURNS [BOOLEAN] = BEGIN OPEN Inline; i: CARDINAL; casebit: WORD = 40B; IF s1 = NIL AND s2 = NIL THEN RETURN[TRUE]; IF s1 = NIL OR s2 = NIL OR s1.length # s2.length THEN RETURN[FALSE]; FOR i IN [0..s1.length) DO IF BITOR[s1[i], casebit] # BITOR[s2[i], casebit] THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE] END; AppendSubString: PROCEDURE [to: LONG STRING, from: SubString] = BEGIN i, j, n: CARDINAL; s: LONG STRING; IF to = NIL OR (s _ from.base) = NIL THEN RETURN; WHILE from.length + to.length > to.maxlength DO temp: LONG STRING _ SIGNAL StringBoundsFault[to]; IF temp = NIL THEN EXIT; -- just fill in as much as fits to _ temp; ENDLOOP; i _ to.length; j _ from.offset; n _ MIN[from.length, LOOPHOLE[to.maxlength - to.length, CARDINAL]]; WHILE n > 0 DO to[i] _ s[j]; i _ i + 1; j _ j + 1; n _ n - 1; ENDLOOP; to.length _ i; RETURN END; EqualSubString: PROCEDURE [s1, s2: SubString] RETURNS [BOOLEAN] = BEGIN i1, i2, n: CARDINAL; b1, b2: LONG STRING; IF s1.length # s2.length THEN RETURN[FALSE]; b1 _ s1.base; i1 _ s1.offset; b2 _ s2.base; i2 _ s2.offset; FOR n _ s1.length, n - 1 WHILE n > 0 DO IF b1[i1] # b2[i2] THEN RETURN[FALSE]; i1 _ i1 + 1; i2 _ i2 + 1; ENDLOOP; RETURN[TRUE] END; EquivalentSubString: PROCEDURE [s1, s2: SubString] RETURNS [BOOLEAN] = BEGIN OPEN Inline; casebit: WORD = 40B; i1, i2, n: CARDINAL; b1, b2: LONG STRING; IF s1.length # s2.length THEN RETURN[FALSE]; b1 _ s1.base; i1 _ s1.offset; b2 _ s2.base; i2 _ s2.offset; FOR n _ s1.length, n - 1 WHILE n > 0 DO IF BITOR[b1[i1], casebit] # BITOR[b2[i2], casebit] THEN RETURN[FALSE]; i1 _ i1 + 1; i2 _ i2 + 1; ENDLOOP; RETURN[TRUE] END; Copy: PROCEDURE [to, from: LONG STRING] = { n: CARDINAL; IF to = NIL OR from = NIL THEN RETURN; WHILE from.length > to.maxlength DO temp: LONG STRING _ SIGNAL StringBoundsFault[to]; IF temp = NIL THEN EXIT; -- just fill in as much as fits to _ temp; ENDLOOP; n _ MIN[from.length, to.maxlength]; Inline.LongCOPY[ from: @from.text, to: @to.text, nwords: SIZE[StringBody[n]]-SIZE[StringBody[0]]]; to.length _ n; RETURN}; DeleteSubString: PROCEDURE [s: SubString] = BEGIN b: LONG STRING = s.base; i: CARDINAL _ s.offset; j: CARDINAL _ i + s.length; WHILE j < b.length DO b[i] _ b[j]; i _ i + 1; j _ j + 1; ENDLOOP; b.length _ i; RETURN END; AppendCharAndGrow: PROCEDURE [ to: LONG POINTER TO LONG STRING, c: CHARACTER, z: UNCOUNTED ZONE] = BEGIN extra: CARDINAL _ 6; temp: LONG STRING _ to^; IF temp = NIL OR temp.length = temp.maxlength THEN { temp _ CopyToNewString[temp, z, extra]; FreeString[z, to^]; to^ _ temp; <> }; temp[temp.length] _ c; temp.length _ temp.length + 1; END; AppendExtensionIfNeeded: PROCEDURE [ to: LONG POINTER TO LONG STRING, extension: LONG STRING, z: UNCOUNTED ZONE] RETURNS [done: BOOLEAN] = BEGIN i, nCharsToAdd: CARDINAL; temp: LONG STRING _ to^; done _ FALSE; IF EmptyString[temp] THEN RETURN[FALSE]; FOR i DECREASING IN [1..temp.length) DO SELECT temp[i] FROM '., Ascii.SP, Ascii.TAB => temp.length _ temp.length - 1; ENDCASE => EXIT; ENDLOOP; FOR i DECREASING IN [0..temp.length) DO IF temp[i] = '. THEN RETURN[FALSE]; ENDLOOP; nCharsToAdd _ extension.length + (IF extension[0] # '. THEN 1 ELSE 0); IF temp.length + nCharsToAdd > temp.maxlength THEN { temp _ CopyToNewString[temp, z, nCharsToAdd]; FreeString[z, to^]; to^ _ temp; <> }; IF extension[0] # '. THEN AppendChar[temp, '.]; AppendString[temp, extension]; done _ TRUE; END; AppendStringAndGrow: PROCEDURE [ to: LONG POINTER TO LONG STRING, from: LONG STRING, z: UNCOUNTED ZONE, extra: CARDINAL _ 0] = BEGIN temp: LONG STRING _ to^; IF temp = NIL OR temp.length + from.length >= temp.maxlength THEN { temp _ CopyToNewString[temp, z, from.length + extra]; FreeString[z, to^]; to^ _ temp; <> }; AppendString[to: temp, from: from]; END; Replace: PROCEDURE [ to: LONG POINTER TO LONG STRING, from: LONG STRING, z: UNCOUNTED ZONE] = BEGIN IF to = NIL THEN RETURN[]; IF to^ # NIL THEN {FreeString[z, to^]; to^ _ NIL}; IF from # NIL THEN to^ _ CopyToNewString[from, z]; <> RETURN END; CopyToNewString: PROCEDURE [ s: LONG STRING, z: UNCOUNTED ZONE, longer: CARDINAL _ 0] RETURNS [newS: LONG STRING] = BEGIN l: CARDINAL = (IF s = NIL THEN 0 ELSE s.length); IF s = NIL AND longer = 0 THEN RETURN[NIL]; newS _ MakeString[z, l + longer]; Inline.LongCOPY[ from: @s.text, to: @newS.text, nwords: SIZE[StringBody[l]]-SIZE[StringBody[0]]]; newS.length _ l; <> <> END; ExpandString: PROCEDURE [ s: LONG POINTER TO LONG STRING, longer: CARDINAL, z: UNCOUNTED ZONE] = BEGIN newS: LONG STRING _ CopyToNewString[ s^, z, longer + (IF s^ = NIL THEN 0 ELSE s.maxlength - s.length)]; FreeString[z, s^]; s^ _ newS; <> <> END; <> <> <<>> <> <> <> <<>> Overflow: SIGNAL = CODE; InvalidNumber: SIGNAL = CODE; NUL: CHARACTER = 0C; Space: CHARACTER = ' ; UpperCase: PROCEDURE [c: CHARACTER] RETURNS [CHARACTER] = BEGIN IF c IN ['a..'z] THEN c _ c + ('A - 'a); RETURN[c] END; LowerCase: PROCEDURE [c: CHARACTER] RETURNS [CHARACTER] = BEGIN IF c IN ['A..'Z] THEN c _ c + ('a - 'A); RETURN[c] END; Compare: PROCEDURE [s1, s2: LONG STRING, ignoreCase: BOOLEAN _ TRUE] RETURNS [INTEGER] = BEGIN i: CARDINAL; l1: CARDINAL = s1.length; l2: CARDINAL = s2.length; c1, c2: CHARACTER; FOR i IN [0..MIN[l1, l2]) DO c1 _ s1[i]; c2 _ s2[i]; IF ignoreCase THEN BEGIN c1 _ UpperCase[c1]; c2 _ UpperCase[c2]; END; SELECT c1 FROM < c2 => RETURN[-1]; > c2 => RETURN[1]; ENDCASE; ENDLOOP; RETURN[SELECT l1 FROM < l2 => -1, > l2 => 1, ENDCASE => 0] END; StringToDecimal: PROCEDURE [s: LONG STRING] RETURNS [INTEGER] = { RETURN[StringToNumber[s, 10]]}; StringToOctal: PROCEDURE [s: LONG STRING] RETURNS [CARDINAL] = { RETURN[StringToNumber[s, 8]]}; StringToNumber: PROCEDURE [s: LONG STRING, radix: CARDINAL] RETURNS [v: UNSPECIFIED] = BEGIN OPEN Inline; char: CHARACTER; cp: CARDINAL _ 0; v8, v10: CARDINAL _ 0; neg: BOOLEAN _ FALSE; getchar: PROCEDURE = BEGIN char _ IF cp >= s.length THEN NUL ELSE s[cp]; cp _ cp + 1; END; getchar[]; WHILE char <= Space DO IF char = NUL THEN SIGNAL InvalidNumber; getchar[]; ENDLOOP; IF char = '- THEN BEGIN neg _ TRUE; getchar[] END; WHILE char IN ['0..'9] DO v10 _ v10*10 + (char - '0); v8 _ v8*8 + (char - '0); getchar[]; ENDLOOP; BEGIN SELECT LOOPHOLE[BITAND[char, 137B], CHARACTER] FROM NUL => GOTO noexponent; 'B => BEGIN v _ v8; radix _ 8; END; 'D => BEGIN v _ v10; radix _ 10; END; ENDCASE => GOTO noexponent; getchar[]; v10 _ 0; WHILE char IN ['0..'9] DO v10 _ v10*10 + char - '0; getchar[]; ENDLOOP; THROUGH [1..v10] DO v _ v*radix ENDLOOP; EXITS noexponent => v _ IF radix = 8 THEN v8 ELSE v10; END; IF char # NUL THEN SIGNAL InvalidNumber; IF neg THEN RETURN[-v]; END; AppendNumber: PROCEDURE [s: LONG STRING, n: CARDINAL, radix: CARDINAL] = BEGIN ps: POINTER TO LONG STRING = @s; xn: PROCEDURE [n: CARDINAL] = BEGIN r: CARDINAL; [n, r] _ Inline.DIVMOD[n, radix]; IF n # 0 THEN xn[n]; IF r > 9 THEN r _ r + 'A - '0 - 10; AppendChar[s, r + '0]; END; xn[n ! StringBoundsFault => RESUME[ps^ _ StringBoundsFault[s]]]; END; AppendDecimal: PROCEDURE [s: LONG STRING, n: INTEGER] = BEGIN IF n < 0 THEN BEGIN ps: POINTER TO LONG STRING = @s; IF n = LAST[INTEGER] THEN BEGIN AppendString[s, "-32768"L]; RETURN END; AppendChar[s, '- ! StringBoundsFault => RESUME[ps^ _ StringBoundsFault[s]]]; n _ -n END; AppendNumber[s, n, 10]; END; AppendOctal: PROCEDURE [s: LONG STRING, n: UNSPECIFIED] = BEGIN AppendNumber[s, n, 8]; AppendChar[s, 'B]; END; AppendLongDecimal: PROCEDURE [s: LONG STRING, n: LONG INTEGER] = BEGIN IF n < 0 THEN BEGIN ps: POINTER TO LONG STRING = @s; IF n = LAST[LONG INTEGER] THEN BEGIN AppendString[s, "-2147483648"L]; RETURN END; AppendChar[s, '- ! StringBoundsFault => RESUME[ps^ _ StringBoundsFault[s]]]; n _ -n END; AppendLongNumber[s, n, 10]; END; AppendLongNumber: PROCEDURE [ s: LONG STRING, n: LONG UNSPECIFIED, radix: CARDINAL] = BEGIN ps: POINTER TO LONG STRING = @s; xn: PROCEDURE [n: LONG CARDINAL] = BEGIN lr: LONG CARDINAL; r: CARDINAL; [n, lr] _ Inline.UDDivMod[n, radix]; IF n # 0 THEN xn[n]; IF (r _ Inline.LowHalf[lr]) > 9 THEN r _ r + 'A - '0 - 10; AppendChar[s, r + '0]; END; xn[n ! StringBoundsFault => RESUME[ps^ _ StringBoundsFault[s]]]; END; StringToLongNumber: PROCEDURE [s: LONG STRING, radix: CARDINAL] RETURNS [v: LONG CARDINAL] = BEGIN OPEN Inline; char: CHARACTER; cp: CARDINAL _ 0; exp: CARDINAL; v8, v10: LONG INTEGER _ 0; neg: BOOLEAN _ FALSE; getchar: PROCEDURE = BEGIN char _ IF cp >= s.length THEN NUL ELSE s[cp]; cp _ cp + 1; END; getchar[]; WHILE char <= Space DO IF char = NUL THEN SIGNAL InvalidNumber; getchar[]; ENDLOOP; IF char = '- THEN BEGIN neg _ TRUE; getchar[] END; WHILE char IN ['0..'9] DO v10 _ v10*10 + CARDINAL[char - '0]; v8 _ v8*8 + CARDINAL[char - '0]; getchar[]; ENDLOOP; BEGIN SELECT LOOPHOLE[BITAND[char, 137B], CHARACTER] FROM NUL => GOTO noexponent; 'B => BEGIN v _ v8; radix _ 8; END; 'D => BEGIN v _ v10; radix _ 10; END; ENDCASE => GOTO noexponent; getchar[]; exp _ 0; WHILE char IN ['0..'9] DO exp _ exp*10 + char - '0; getchar[]; ENDLOOP; THROUGH [1..exp] DO v _ v*radix ENDLOOP; EXITS noexponent => v _ IF radix = 8 THEN v8 ELSE v10; END; IF char # NUL THEN SIGNAL InvalidNumber; IF neg THEN RETURN[-v]; END; END....