home *** CD-ROM | disk | FTP | other *** search
- (*-------------------------------------------------------------------------*)
- (* *)
- (* Amiga Oberon Interface Module: STRING Date: 02-Nov-92 *)
- (* *)
- (* © 1992 by Fridtjof Siebert *)
- (* *)
- (*-------------------------------------------------------------------------*)
-
- MODULE STRING;
-
- IMPORT BT * := BasicTypes, Strings, SYSTEM;
-
- TYPE
- STRING * = POINTER TO STRINGDesc;
-
- STRINGDesc * = RECORD (BT.COMPAREABLEDesc)
-
- chars-: BT.DynString; (* The characters of this string *)
-
- len: LONGINT;
-
- (*
- * invariant
- * chars#NIL;
- * len>=0;
- * (len<LEN(chars^)) IMPLIES (chars[len]=0X)
- *)
-
- END;
-
- CONST
- Blank * = " ";
-
-
- PROCEDURE Create * (n: LONGINT): STRING;
- (*
- * Allocate Space for at least n characters
- *
- * require
- * n>=0
- *
- * ensure
- * Result.Capacity() >= n;
- * Result.Empty();
- *
- *)
-
- VAR
- s: STRING;
-
- BEGIN
- NEW(s);
- NEW(s.chars,n);
- s.len := 0;
- RETURN s;
- END Create;
-
-
- PROCEDURE CreateString * (s: ARRAY OF CHAR): STRING;
- (*
- * Create new STRING and copy a to it.
- *
- * ensure
- * Result.Capacity() >= LEN(s);
- * Result.chars^ = s;
- *)
-
- VAR
- a: STRING;
-
- BEGIN
- NEW(a);
- NEW(a.chars,LEN(s)+1);
- a.len := 0;
- WHILE (a.len<LEN(s)) & (s[a.len]#0X) DO
- a.chars[a.len] := s[a.len];
- INC(a.len)
- END;
- a.chars[a.len] := 0X;
- RETURN a;
- END CreateString;
-
-
- PROCEDURE (a: STRING) Capacity * (): LONGINT;
- (*
- * Number of characters that fit in a.chars^.
- *
- * ensure
- * Result >= 0;
- *)
-
- BEGIN
- RETURN LEN(a.chars^);
- END Capacity;
-
-
- PROCEDURE (a: STRING) Compare * (b: BT.COMPAREABLE): LONGINT;
- (*
- * Compare strings a and b
- *
- * ensure
- * a.chars^ = b.chars^ IMPLIES Result = 0
- * a.chars^ < b.chars^ IMPLIES Result < 0
- * a.chars^ > b.chars^ IMPLIES Result > 0
- *)
-
- VAR
- i,l: LONGINT;
-
- BEGIN
- WITH b: STRING DO
- i := -1; l := a.len; IF l>b.len THEN l := b.len END;
- REPEAT
- INC(i);
- UNTIL (i=l) OR (a.chars[i]#b.chars[i]);
- IF i=a.len THEN
- IF i=b.len THEN RETURN 0
- ELSE RETURN -1 END;
- ELSIF i=b.len THEN
- RETURN 1
- ELSE
- RETURN ORD(a.chars[i])-ORD(b.chars[i]);
- END;
- END;
- END Compare;
-
-
- PROCEDURE (a: STRING) Equal * (b: BT.COMPAREABLE): BOOLEAN; (* a = b *)
- (*
- * are both strings equal?
- *
- * ensure
- * Result = (a.chars^ = b.chars^)
- *)
-
- BEGIN
- RETURN a.chars^ = b(STRING).chars^;
- END Equal;
-
-
- PROCEDURE (a: STRING) Count * (): LONGINT;
- (*
- * Determine length of a.
- *
- * ensure
- * Result>=0;
- *)
-
- BEGIN
- RETURN a.len;
- END Count;
-
-
- PROCEDURE ^ (a: STRING) Enlarge * (newsize: LONGINT);
-
-
- PROCEDURE (a: STRING) Adapt * (s: ARRAY OF CHAR);
- (*
- * copy s to a
- *
- * ensure
- * a.chars^ = s;
- *)
-
- BEGIN
- a.Enlarge(LEN(s));
- COPY(s,a.chars^);
- a.len := 0;
- WHILE (a.len<LEN(a.chars^)) & (a.chars[a.len]#0X) DO INC(a.len) END;
- END Adapt;
-
-
- PROCEDURE (a: STRING) Append * (b: STRING);
- (*
- * Append a copy of b to a.
- *
- * require
- * b#NIL;
- *
- * ensure
- * a.Count() = OLD a.Count() + b.Count;
- *)
-
- VAR
- i: LONGINT;
- BEGIN
- a.Enlarge(a.len + b.len);
- FOR i:=0 TO b.len-1 DO
- a.chars[a.len] := b.chars[i];
- INC(a.len);
- END;
- IF a.len<LEN(a.chars^) THEN a.chars[a.len] := 0X END;
- END Append;
-
-
- PROCEDURE (a: STRING) Clear *;
- (*
- * ensure
- * a.Count() = 0
- *)
-
- BEGIN
- a.len := 0;
- a.chars[0] := 0X;
- END Clear;
-
-
- PROCEDURE (a: STRING) Copy * (b: STRING);
- (*
- * Copy b to a.
- *
- * require
- * b#NIL;
- *
- * ensure
- * a.Equal(b);
- *)
-
- BEGIN
- a.Enlarge(b.len);
- COPY(b.chars^,a.chars^);
- a.len := b.len;
- END Copy;
-
-
- PROCEDURE (a: STRING) Empty * (): BOOLEAN;
- (*
- * Is string empty?
- *
- * ensure
- * Result = (a.Count()=0)
- *)
- BEGIN
- RETURN a.len=0;
- END Empty;
-
-
- PROCEDURE (a: STRING) Extend * (c: CHAR);
- (*
- * Add c at end;
- *
- * require
- * c#0X;
- *
- * ensure
- * a.Count() = old a.Count()+1;
- * a.chars[a.Count()-1] = c;
- *)
-
- BEGIN
- a.Enlarge(a.len+1);
- a.chars[a.len] := c;
- INC(a.len);
- IF a.len<LEN(a.chars^) THEN a.chars[a.len] := 0X END;
- END Extend;
-
-
- PROCEDURE (a: STRING) ExtendString * (s: ARRAY OF CHAR);
- (*
- * Appen s at end;
- *
- * ensure
- * a.Count() = old a.Count() + String.Length(s);
- * for all i: 0..Strings.Length[s]-1, a.chars[a.Count()-str.Length(s)+i] = s[i];
- *)
-
- VAR
- l,i: LONGINT;
-
- BEGIN
- l := Strings.Length(s);
- a.Enlarge(a.len+l);
- i := l;
- WHILE i>0 DO
- DEC(i);
- a.chars[a.len+i] := s[i];
- END;
- INC(a.len,l);
- IF a.len<LEN(a.chars^) THEN a.chars[a.len] := 0X END;
- END ExtendString;
-
-
- PROCEDURE (a: STRING) FillBlank *;
- (*
- * fill a with blanks
- *
- * ensure
- * -- for all i: 0..a.Capacity()-1, a.chars[i] = Blank;
- *)
-
- VAR
- i: LONGINT;
- BEGIN
- FOR i:=0 TO LEN(a.chars^)-1 DO
- a.chars[i] := Blank;
- END;
- a.len := LEN(a.chars^);
- END FillBlank;
-
-
- PROCEDURE (a: STRING) HashCode * (): LONGINT;
- (*
- * Determine Hash code value for current string.
- *
- * ensure
- * Result >= 0;
- *)
-
- VAR
- i: LONGINT;
- Result: LONGINT;
- Temp: LONGINT;
- BEGIN
- Result := 0;
- FOR i := 0 TO a.len DO
- Temp := Result * 80H + ORD(a.chars[i]);
- Result := Temp DIV 800000H + Temp MOD 800000H;
- END;
- RETURN Result;
- END HashCode;
-
-
- PROCEDURE (a: STRING) Head * (n: LONGINT);
- (*
- * Remove all but the first n characters of the string.
- * Do nothing for n >= a.Count();
- *
- * require
- * n >= 0;
- * ensure
- * n < OLD a.Count() IMPLIES a.Count() = n;
- * n >= OLD a.Count() IMPLIES a.Count() = OLD a.Count;
- *)
-
- BEGIN
- IF n<a.len THEN
- a.len := n;
- a.chars[n] := 0X;
- END;
- END Head;
-
-
- PROCEDURE (a: STRING) IndexOf * (c: CHAR; i: LONGINT): LONGINT;
- (*
- * index of first occurence of c, starting at position i.
- * <0 if not fount.
- *
- * require
- * i>=0;
- * i< a.Capacity();
- * ensure
- * (Result = -1) OR (a.chars[Result] = c);
- *)
- VAR
- Result: LONGINT;
- BEGIN
- Result := -1;
- WHILE (i<a.len) & (Result<0) DO
- IF a.chars[i]=c THEN
- Result := i;
- END;
- INC(i);
- END;
- RETURN Result;
- END IndexOf;
-
-
- PROCEDURE (a: STRING) LeftAdjust * ;
- (*
- * Remove leading blanks
- *
- * ensure
- * (a.Count()=0) OR (a.chars[0]#Blank);
- *)
-
- VAR
- i,j: LONGINT;
- BEGIN
- i := 0;
- WHILE (i<a.len) & (a.chars[i]=Blank) DO
- INC(i);
- END;
- IF i>0 THEN
- FOR j:=i TO a.len-1 DO
- a.chars[j-i] := a.chars[j];
- END;
- DEC(a.len,i);
- a.chars[a.len] := 0X;
- END;
- END LeftAdjust;
-
-
- PROCEDURE (a: STRING) Precede * (c: CHAR);
- (*
- * Add c at front
- *
- * require
- * c#0X;
- * ensure
- * a.chars[0] = c;
- * a.Count() = OLD a.Count() + 1
- *)
-
- VAR
- i: LONGINT;
- BEGIN
- a.Enlarge(a.len+1);
- FOR i := a.len TO 1 BY -1 DO
- a.chars[i] := a.chars[i-1];
- END;
- a.chars[0] := c;
- INC(a.len);
- IF a.len<LEN(a.chars^) THEN a.chars[a.len] := 0X END;
- END Precede;
-
-
- PROCEDURE (a: STRING) Prepend * (b: STRING);
- (*
- * prepend a copy of s at front of a
- *
- * require
- * b#NIL
- * ensure
- * a.Count() = OLD a.Count() + b.Count();
- *)
-
- VAR
- i: LONGINT;
- BEGIN
- a.Enlarge(a.len+b.len);
- FOR i:=a.len-1 TO 0 BY -1 DO
- a.chars[i+b.len] := a.chars[i];
- END;
- FOR i:=0 TO b.len-1 DO
- a.chars[i] := b.chars[i];
- END;
- INC(a.len,b.len);
- IF a.len<LEN(a.chars^) THEN a.chars[a.len] := 0X END;
- END Prepend;
-
-
- PROCEDURE (a: STRING) Put * (c: CHAR; i: LONGINT);
- (*
- * Set character at position i to c.
- *
- * require
- * i >= 0;
- * i < a.Count();
- * c # 0X;
- * ensure
- * a.chars[i] = c;
- *)
-
- BEGIN
- a.chars[i] := c;
- END Put;
-
-
- PROCEDURE (a: STRING) Remove * (i: LONGINT);
- (*
- * Remove i-th Character.
- *
- * require
- * i >= 0;
- * i < a.Count();
- * ensure
- * a.Count() = OLD a.Count() - 1
- *)
-
- BEGIN
- DEC(a.len);
- FOR i := i TO a.len-1 DO
- a.chars[i] := a.chars[i+1];
- END;
- a.chars[a.len] := 0X;
- END Remove;
-
-
- PROCEDURE (a: STRING) RemoveAllOccurences * (c: CHAR);
- (*
- * remove all occurences of c
- *
- * ensure
- * for all i: 0..a.Count()-1, a.chars[i]#c;
- * a.Count() = OLD a.Count() - # of occurences of c within initial a.
- *)
-
- VAR
- i,d: LONGINT;
- BEGIN
- i := 0; d := 0;
- REPEAT
- WHILE (i+d<a.len) & (a.chars[i+d]=c) DO INC(d) END;
- WHILE (i+d<a.len) & (a.chars[i+d]#c) DO a.chars[i] := a.chars[i+d]; INC(i) END;
- UNTIL i+d>=a.len;
- IF d>0 THEN
- DEC(a.len,d);
- a.chars[a.len] := 0X;
- END;
- END RemoveAllOccurences;
-
-
- PROCEDURE (a: STRING) Resize * (newsize: LONGINT);
- (*
- * Reallocate if needed to accommodate at least newsize characters.
- *
- * require
- * newsize >= 0;
- * ensure
- * a.Capacity() >= newsize
- *)
-
- VAR
- new: BT.DynString;
- BEGIN
- IF newsize>LEN(a.chars^) THEN
- NEW(new,newsize);
- COPY(a.chars^,new^);
- a.chars := new;
- END;
- END Resize;
-
-
- PROCEDURE (a: STRING) Enlarge * (newsize: LONGINT);
- (*
- * Reallocate if needed to accommodate at least newsize characters.
- * This routine allocates more chars than are actually needed, so many
- * calls to Enlarge() don't end in too many allocates.
- *
- * require
- * newsize >= 0;
- * ensure
- * a.Capacity() >= newsize
- *)
-
- VAR
- new: BT.DynString;
- BEGIN
- IF newsize>LEN(a.chars^) THEN
- a.Resize(newsize + newsize DIV 2);
- END;
- END Enlarge;
-
-
- PROCEDURE (a: STRING) RightAdjust *;
- (*
- * Remove trailing Blanks.
- *
- * ensure
- * (a.Count()=0) OR (a.chars[a.Count()-1]#Blank)
- *)
-
- BEGIN
- WHILE (a.len>0) & (a.chars[a.len-1]=Blank) DO
- DEC(a.len);
- a.chars[a.len] := 0X;
- END;
- END RightAdjust;
-
-
- PROCEDURE (a: STRING) Shrink * (t: STRING; n1,n2: LONGINT);
- (*
- * remove characters outside of interval n1..n2
- *
- * require
- * t#NIL;
- * 0 <= n1;
- * n1 <= n2;
- * n2 < t.Count();
- * ensure
- * a.Equal(t.Substring(n1,n2));
- *)
-
- VAR
- i: LONGINT;
- BEGIN
- a.Enlarge(n2-n1+1);
- FOR i := 0 TO n2-n1 DO
- a.chars[i] := t.chars[n1+i];
- END;
- a.len := n2-n1+1;
- IF a.len<LEN(a.chars^) THEN a.chars[a.len] := 0X END;
- END Shrink;
-
-
- PROCEDURE (a: STRING) Substring * (n1,n2: LONGINT): STRING;
- (*
- * Copy of substring of current string containing all characters
- * at indices between n1 and n2.
- *
- * require
- * 0 <= n1;
- * n1 <= n2;
- * n2 < t.Count()
- * ensure
- * Result.Count = n2 - n1 + 1;
- * for all i: 0 .. n2-n1, Result.chars[i] = a.chars[n1+i]
- *)
-
- VAR
- new: STRING;
- i: LONGINT;
- BEGIN
- new := Create(n2-n1+2);
- FOR i := 0 TO n2-n1 DO
- new.chars[i] := a.chars[n1+i];
- END;
- new.len := n2-n1+1;
- new.chars[new.len] := 0X;
- RETURN new;
- END Substring;
-
-
- PROCEDURE (a: STRING) Tail * (n: LONGINT);
- (*
- * Remove all but the last n characters of the string.
- * Do nothing for n >= a.Count();
- *
- * require
- * n >= 0;
- * ensure
- * n < OLD a.Count() IMPLIES a.Count() = n;
- * n >= OLD a.Count() IMPLIES a.Count() = OLD a.Count;
- *)
-
- VAR
- i: LONGINT;
-
- BEGIN
- IF n<a.len THEN
- FOR i:=0 TO n-1 DO
- a.chars[i] := a.chars[a.len - n + i];
- END;
- a.len := n;
- a.chars[n] := 0X;
- END;
- END Tail;
-
-
- PROCEDURE (a: STRING) ToC * (): SYSTEM.ADDRESS;
- (*
- * Address of the string that a C function may cast into a pointer to a
- * C form of the string. Useful only for interfacing with C software.
- *)
-
- BEGIN
- a.Enlarge(a.len+1);
- RETURN SYSTEM.ADR(a.chars^);
- END ToC;
-
-
- PROCEDURE (a: STRING) ToInteger * (): LONGINT;
- (*
- * Integer value of current string, assumed to contain digits only.
- * When applied to "123", will yield 123.
- *
- * require
- * for all i: 0..a.Count()-1, ("0"<=a.chars[i]) & (a.chars[i]<="9")
- *)
-
- VAR
- Result: LONGINT;
- i: LONGINT;
- negative: BOOLEAN;
-
- BEGIN
- Result := 0; negative := FALSE;
- IF a.len>0 THEN
- CASE a.chars[0] OF
- | "-": i := 1; negative := TRUE;
- | "+": i := 1;
- ELSE i := 0;
- END;
- WHILE (i<a.len) DO
- CASE a.chars[i] OF
- | "0".."9":
- IF Result < (MAX(LONGINT) - (ORD(a.chars[i]) - ORD("0"))) DIV 10 THEN
- Result := 10 * Result + (ORD(a.chars[i]) - ORD("0"));
- END;
- ELSE END;
- INC(i);
- END;
- END;
- RETURN Result;
- END ToInteger;
-
-
- PROCEDURE (a: STRING) ToLower *;
- (*
- * Convert a to lower case
- *)
-
- VAR
- i: LONGINT;
- BEGIN
- FOR i:=0 TO a.len-1 DO
- CASE a.chars[i] OF
- | "A".."Z","À".."Ö","Ø".."þ": a.chars[i] := CHR(ORD(a.chars[i]) + 32)
- ELSE END;
- END;
- END ToLower;
-
-
- PROCEDURE (a: STRING) ToUpper *;
- (*
- * Convert a to lower case
- *)
-
- VAR
- i: LONGINT;
- BEGIN
- FOR i:=0 TO a.len-1 DO
- CASE a.chars[i] OF
- | "a".."z","à".."ö","ø".."þ": a.chars[i] := CHR(ORD(a.chars[i]) - 32)
- ELSE END;
- END;
- END ToUpper;
-
-
- END STRING.
-
-
-
-
-
-
-
-