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;
IF Heap.OwnerChecking[z] THEN SetOwner[temp, GetGF[Runtime.GetCaller[]]]
};
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 Heap.OwnerChecking[z] THEN SetOwner[temp, GetGF[Runtime.GetCaller[]]]
};
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;
IF Heap.OwnerChecking[z] THEN SetOwner[temp, GetGF[Runtime.GetCaller[]]]
};
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];
IF Heap.OwnerChecking[z] THEN SetOwner[to^, GetGF[Runtime.GetCaller[]]];
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;
IF Heap.OwnerChecking[z] THEN
LOOPHOLE[(newS - 1), LONG POINTER]^ ← GetGF[Runtime.GetCaller[]];
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;
IF Heap.OwnerChecking[z] THEN
LOOPHOLE[(newS - 1), LONG POINTER]^ ← GetGF[Runtime.GetCaller[]];
END;
GetGF: PRIVATE PROCEDURE [p: PROGRAM] RETURNS [POINTER] = INLINE {
RETURN[Inline.LowHalf[LOOPHOLE[p]]]};
SetOwner: PRIVATE PROCEDURE [
node: LONG STRING, owner: UNSPECIFIED] = INLINE {
IF node#NIL THEN LOOPHOLE[node - 1, LONG POINTER]^ ← owner};
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....