home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Programming / Misc / OB3.2D2.DMS / in.adf / Module / STRING.mod < prev    next >
Encoding:
Text File  |  1994-08-05  |  12.2 KB  |  728 lines

  1. (*-------------------------------------------------------------------------*)
  2. (*                                                                         *)
  3. (*  Amiga Oberon Interface Module: STRING             Date: 02-Nov-92      *)
  4. (*                                                                         *)
  5. (*   © 1992 by Fridtjof Siebert                                            *)
  6. (*                                                                         *)
  7. (*-------------------------------------------------------------------------*)
  8.  
  9. MODULE STRING;
  10.  
  11. IMPORT BT * := BasicTypes, Strings, SYSTEM;
  12.  
  13. TYPE
  14.   STRING * = POINTER TO STRINGDesc;
  15.  
  16.   STRINGDesc * = RECORD (BT.COMPAREABLEDesc)
  17.  
  18.     chars-: BT.DynString;   (* The characters of this string *)
  19.  
  20.     len: LONGINT;
  21.  
  22.   (*
  23.    * invariant
  24.    *   chars#NIL;
  25.    *   len>=0;
  26.    *   (len<LEN(chars^)) IMPLIES (chars[len]=0X)
  27.    *)
  28.  
  29.   END;
  30.  
  31. CONST
  32.   Blank * = " ";
  33.  
  34.  
  35. PROCEDURE Create * (n: LONGINT): STRING;
  36. (*
  37.  * Allocate Space for at least n characters
  38.  *
  39.  * require
  40.  *   n>=0
  41.  *
  42.  * ensure
  43.  *   Result.Capacity() >= n;
  44.  *   Result.Empty();
  45.  *
  46.  *)
  47.  
  48. VAR
  49.   s: STRING;
  50.  
  51. BEGIN
  52.   NEW(s);
  53.   NEW(s.chars,n);
  54.   s.len := 0;
  55.   RETURN s;
  56. END Create;
  57.  
  58.  
  59. PROCEDURE CreateString * (s: ARRAY OF CHAR): STRING;
  60. (*
  61.  * Create new STRING and copy a to it.
  62.  *
  63.  * ensure
  64.  *   Result.Capacity() >= LEN(s);
  65.  *   Result.chars^ = s;
  66.  *)
  67.  
  68. VAR
  69.   a: STRING;
  70.  
  71. BEGIN
  72.   NEW(a);
  73.   NEW(a.chars,LEN(s)+1);
  74.   a.len := 0;
  75.   WHILE (a.len<LEN(s)) & (s[a.len]#0X) DO
  76.     a.chars[a.len] := s[a.len];
  77.     INC(a.len)
  78.   END;
  79.   a.chars[a.len] := 0X;
  80.   RETURN a;
  81. END CreateString;
  82.  
  83.  
  84. PROCEDURE (a: STRING) Capacity * (): LONGINT;
  85. (*
  86.  * Number of characters that fit in a.chars^.
  87.  *
  88.  * ensure
  89.  *   Result >= 0;
  90.  *)
  91.  
  92. BEGIN
  93.   RETURN LEN(a.chars^);
  94. END Capacity;
  95.  
  96.  
  97. PROCEDURE (a: STRING) Compare * (b: BT.COMPAREABLE): LONGINT;
  98. (*
  99.  * Compare strings a and b
  100.  *
  101.  * ensure
  102.  *   a.chars^ = b.chars^ IMPLIES Result = 0
  103.  *   a.chars^ < b.chars^ IMPLIES Result < 0
  104.  *   a.chars^ > b.chars^ IMPLIES Result > 0
  105.  *)
  106.  
  107. VAR
  108.   i,l: LONGINT;
  109.  
  110. BEGIN
  111.   WITH b: STRING DO
  112.     i := -1; l := a.len; IF l>b.len THEN l := b.len END;
  113.     REPEAT
  114.       INC(i);
  115.     UNTIL (i=l) OR (a.chars[i]#b.chars[i]);
  116.     IF i=a.len THEN
  117.       IF i=b.len THEN RETURN  0
  118.                  ELSE RETURN -1 END;
  119.     ELSIF i=b.len THEN
  120.       RETURN 1
  121.     ELSE
  122.       RETURN ORD(a.chars[i])-ORD(b.chars[i]);
  123.     END;
  124.   END;
  125. END Compare;
  126.  
  127.  
  128. PROCEDURE (a: STRING) Equal   * (b: BT.COMPAREABLE): BOOLEAN; (* a = b *)
  129. (*
  130.  * are both strings equal?
  131.  *
  132.  * ensure
  133.  *   Result = (a.chars^ = b.chars^)
  134.  *)
  135.  
  136. BEGIN
  137.   RETURN a.chars^ = b(STRING).chars^;
  138. END Equal;
  139.  
  140.  
  141. PROCEDURE (a: STRING) Count * (): LONGINT;
  142. (*
  143.  * Determine length of a.
  144.  *
  145.  * ensure
  146.  *   Result>=0;
  147.  *)
  148.  
  149. BEGIN
  150.   RETURN a.len;
  151. END Count;
  152.  
  153.  
  154. PROCEDURE ^ (a: STRING) Enlarge * (newsize: LONGINT);
  155.  
  156.  
  157. PROCEDURE (a: STRING) Adapt * (s: ARRAY OF CHAR);
  158. (*
  159.  * copy s to a
  160.  *
  161.  * ensure
  162.  *   a.chars^ = s;
  163.  *)
  164.  
  165. BEGIN
  166.   a.Enlarge(LEN(s));
  167.   COPY(s,a.chars^);
  168.   a.len := 0;
  169.   WHILE (a.len<LEN(a.chars^)) & (a.chars[a.len]#0X) DO INC(a.len) END;
  170. END Adapt;
  171.  
  172.  
  173. PROCEDURE (a: STRING) Append * (b: STRING);
  174. (*
  175.  * Append a copy of b to a.
  176.  *
  177.  * require
  178.  *   b#NIL;
  179.  *
  180.  * ensure
  181.  *   a.Count() = OLD a.Count() + b.Count;
  182.  *)
  183.  
  184. VAR
  185.   i: LONGINT;
  186. BEGIN
  187.   a.Enlarge(a.len + b.len);
  188.   FOR i:=0 TO b.len-1 DO
  189.     a.chars[a.len] := b.chars[i];
  190.     INC(a.len);
  191.   END;
  192.   IF a.len<LEN(a.chars^) THEN a.chars[a.len] := 0X END;
  193. END Append;
  194.  
  195.  
  196. PROCEDURE (a: STRING) Clear *;
  197. (*
  198.  * ensure
  199.  *   a.Count() = 0
  200.  *)
  201.  
  202. BEGIN
  203.   a.len := 0;
  204.   a.chars[0] := 0X;
  205. END Clear;
  206.  
  207.  
  208. PROCEDURE (a: STRING) Copy * (b: STRING);
  209. (*
  210.  * Copy b to a.
  211.  *
  212.  * require
  213.  *   b#NIL;
  214.  *
  215.  * ensure
  216.  *   a.Equal(b);
  217.  *)
  218.  
  219. BEGIN
  220.   a.Enlarge(b.len);
  221.   COPY(b.chars^,a.chars^);
  222.   a.len := b.len;
  223. END Copy;
  224.  
  225.  
  226. PROCEDURE (a: STRING) Empty * (): BOOLEAN;
  227. (*
  228.  * Is string empty?
  229.  *
  230.  * ensure
  231.  *   Result = (a.Count()=0)
  232.  *)
  233. BEGIN
  234.   RETURN a.len=0;
  235. END Empty;
  236.  
  237.  
  238. PROCEDURE (a: STRING) Extend * (c: CHAR);
  239. (*
  240.  * Add c at end;
  241.  *
  242.  * require
  243.  *   c#0X;
  244.  *
  245.  * ensure
  246.  *   a.Count() = old a.Count()+1;
  247.  *   a.chars[a.Count()-1] = c;
  248.  *)
  249.  
  250. BEGIN
  251.   a.Enlarge(a.len+1);
  252.   a.chars[a.len] := c;
  253.   INC(a.len);
  254.   IF a.len<LEN(a.chars^) THEN a.chars[a.len] := 0X END;
  255. END Extend;
  256.  
  257.  
  258. PROCEDURE (a: STRING) ExtendString * (s: ARRAY OF CHAR);
  259. (*
  260.  * Appen s at end;
  261.  *
  262.  * ensure
  263.  *   a.Count() = old a.Count() + String.Length(s);
  264.  *   for all i: 0..Strings.Length[s]-1, a.chars[a.Count()-str.Length(s)+i] = s[i];
  265.  *)
  266.  
  267. VAR
  268.   l,i: LONGINT;
  269.  
  270. BEGIN
  271.   l := Strings.Length(s);
  272.   a.Enlarge(a.len+l);
  273.   i := l;
  274.   WHILE i>0 DO
  275.     DEC(i);
  276.     a.chars[a.len+i] := s[i];
  277.   END;
  278.   INC(a.len,l);
  279.   IF a.len<LEN(a.chars^) THEN a.chars[a.len] := 0X END;
  280. END ExtendString;
  281.  
  282.  
  283. PROCEDURE (a: STRING) FillBlank *;
  284. (*
  285.  * fill a with blanks
  286.  *
  287.  * ensure
  288.  *   -- for all i: 0..a.Capacity()-1, a.chars[i] = Blank;
  289.  *)
  290.  
  291. VAR
  292.   i: LONGINT;
  293. BEGIN
  294.   FOR i:=0 TO LEN(a.chars^)-1 DO
  295.     a.chars[i] := Blank;
  296.   END;
  297.   a.len := LEN(a.chars^);
  298. END FillBlank;
  299.  
  300.  
  301. PROCEDURE (a: STRING) HashCode * (): LONGINT;
  302. (*
  303.  * Determine Hash code value for current string.
  304.  *
  305.  * ensure
  306.  *   Result >= 0;
  307.  *)
  308.  
  309. VAR
  310.   i: LONGINT;
  311.   Result: LONGINT;
  312.   Temp: LONGINT;
  313. BEGIN
  314.   Result := 0;
  315.   FOR i := 0 TO a.len DO
  316.     Temp := Result * 80H + ORD(a.chars[i]);
  317.     Result := Temp DIV 800000H + Temp MOD 800000H;
  318.   END;
  319.   RETURN Result;
  320. END HashCode;
  321.  
  322.  
  323. PROCEDURE (a: STRING) Head * (n: LONGINT);
  324. (*
  325.  * Remove all but the first n characters of the string.
  326.  * Do nothing for n >= a.Count();
  327.  *
  328.  * require
  329.  *   n >= 0;
  330.  * ensure
  331.  *   n <  OLD a.Count() IMPLIES a.Count() = n;
  332.  *   n >= OLD a.Count() IMPLIES a.Count() = OLD a.Count;
  333.  *)
  334.  
  335. BEGIN
  336.   IF n<a.len THEN
  337.     a.len := n;
  338.     a.chars[n] := 0X;
  339.   END;
  340. END Head;
  341.  
  342.  
  343. PROCEDURE (a: STRING) IndexOf * (c: CHAR; i: LONGINT): LONGINT;
  344. (*
  345.  * index of first occurence of c, starting at position i.
  346.  * <0 if not fount.
  347.  *
  348.  * require
  349.  *   i>=0;
  350.  *   i< a.Capacity();
  351.  * ensure
  352.  *   (Result = -1) OR (a.chars[Result] = c);
  353.  *)
  354. VAR
  355.   Result: LONGINT;
  356. BEGIN
  357.   Result := -1;
  358.   WHILE (i<a.len) & (Result<0) DO
  359.     IF a.chars[i]=c THEN
  360.       Result := i;
  361.     END;
  362.     INC(i);
  363.   END;
  364.   RETURN Result;
  365. END IndexOf;
  366.  
  367.  
  368. PROCEDURE (a: STRING) LeftAdjust * ;
  369. (*
  370.  * Remove leading blanks
  371.  *
  372.  * ensure
  373.  *   (a.Count()=0) OR (a.chars[0]#Blank);
  374.  *)
  375.  
  376. VAR
  377.   i,j: LONGINT;
  378. BEGIN
  379.   i := 0;
  380.   WHILE (i<a.len) & (a.chars[i]=Blank) DO
  381.     INC(i);
  382.   END;
  383.   IF i>0 THEN
  384.     FOR j:=i TO a.len-1 DO
  385.       a.chars[j-i] := a.chars[j];
  386.     END;
  387.     DEC(a.len,i);
  388.     a.chars[a.len] := 0X;
  389.   END;
  390. END LeftAdjust;
  391.  
  392.  
  393. PROCEDURE (a: STRING) Precede * (c: CHAR);
  394. (*
  395.  * Add c at front
  396.  *
  397.  * require
  398.  *   c#0X;
  399.  * ensure
  400.  *   a.chars[0] = c;
  401.  *   a.Count() = OLD a.Count() + 1
  402.  *)
  403.  
  404. VAR
  405.   i: LONGINT;
  406. BEGIN
  407.   a.Enlarge(a.len+1);
  408.   FOR i := a.len TO 1 BY -1 DO
  409.     a.chars[i] := a.chars[i-1];
  410.   END;
  411.   a.chars[0] := c;
  412.   INC(a.len);
  413.   IF a.len<LEN(a.chars^) THEN a.chars[a.len] := 0X END;
  414. END Precede;
  415.  
  416.  
  417. PROCEDURE (a: STRING) Prepend * (b: STRING);
  418. (*
  419.  * prepend a copy of s at front of a
  420.  *
  421.  * require
  422.  *   b#NIL
  423.  * ensure
  424.  *   a.Count() = OLD a.Count() + b.Count();
  425.  *)
  426.  
  427. VAR
  428.   i: LONGINT;
  429. BEGIN
  430.   a.Enlarge(a.len+b.len);
  431.   FOR i:=a.len-1 TO 0 BY -1 DO
  432.     a.chars[i+b.len] := a.chars[i];
  433.   END;
  434.   FOR i:=0 TO b.len-1 DO
  435.     a.chars[i] := b.chars[i];
  436.   END;
  437.   INC(a.len,b.len);
  438.   IF a.len<LEN(a.chars^) THEN a.chars[a.len] := 0X END;
  439. END Prepend;
  440.  
  441.  
  442. PROCEDURE (a: STRING) Put * (c: CHAR; i: LONGINT);
  443. (*
  444.  * Set character at position i to c.
  445.  *
  446.  * require
  447.  *   i >= 0;
  448.  *   i < a.Count();
  449.  *   c # 0X;
  450.  * ensure
  451.  *   a.chars[i] = c;
  452.  *)
  453.  
  454. BEGIN
  455.   a.chars[i] := c;
  456. END Put;
  457.  
  458.  
  459. PROCEDURE (a: STRING) Remove * (i: LONGINT);
  460. (*
  461.  * Remove i-th Character.
  462.  *
  463.  * require
  464.  *   i >= 0;
  465.  *   i < a.Count();
  466.  * ensure
  467.  *   a.Count() = OLD a.Count() - 1
  468.  *)
  469.  
  470. BEGIN
  471.   DEC(a.len);
  472.   FOR i := i TO a.len-1 DO
  473.     a.chars[i] := a.chars[i+1];
  474.   END;
  475.   a.chars[a.len] := 0X;
  476. END Remove;
  477.  
  478.  
  479. PROCEDURE (a: STRING) RemoveAllOccurences * (c: CHAR);
  480. (*
  481.  * remove all occurences of c
  482.  *
  483.  * ensure
  484.  *   for all i: 0..a.Count()-1, a.chars[i]#c;
  485.  *   a.Count() = OLD a.Count() - # of occurences of c within initial a.
  486.  *)
  487.  
  488. VAR
  489.   i,d: LONGINT;
  490. BEGIN
  491.   i := 0; d := 0;
  492.   REPEAT
  493.     WHILE (i+d<a.len) & (a.chars[i+d]=c) DO                             INC(d) END;
  494.     WHILE (i+d<a.len) & (a.chars[i+d]#c) DO a.chars[i] := a.chars[i+d]; INC(i) END;
  495.   UNTIL i+d>=a.len;
  496.   IF d>0 THEN
  497.     DEC(a.len,d);
  498.     a.chars[a.len] := 0X;
  499.   END;
  500. END RemoveAllOccurences;
  501.  
  502.  
  503. PROCEDURE (a: STRING) Resize * (newsize: LONGINT);
  504. (*
  505.  * Reallocate if needed to accommodate at least newsize characters.
  506.  *
  507.  * require
  508.  *   newsize >= 0;
  509.  * ensure
  510.  *   a.Capacity() >= newsize
  511.  *)
  512.  
  513. VAR
  514.   new: BT.DynString;
  515. BEGIN
  516.   IF newsize>LEN(a.chars^) THEN
  517.     NEW(new,newsize);
  518.     COPY(a.chars^,new^);
  519.     a.chars := new;
  520.   END;
  521. END Resize;
  522.  
  523.  
  524. PROCEDURE (a: STRING) Enlarge * (newsize: LONGINT);
  525. (*
  526.  * Reallocate if needed to accommodate at least newsize characters.
  527.  * This routine allocates more chars than are actually needed, so many
  528.  * calls to Enlarge() don't end in too many allocates.
  529.  *
  530.  * require
  531.  *   newsize >= 0;
  532.  * ensure
  533.  *   a.Capacity() >= newsize
  534.  *)
  535.  
  536. VAR
  537.   new: BT.DynString;
  538. BEGIN
  539.   IF newsize>LEN(a.chars^) THEN
  540.     a.Resize(newsize + newsize DIV 2);
  541.   END;
  542. END Enlarge;
  543.  
  544.  
  545. PROCEDURE (a: STRING) RightAdjust *;
  546. (*
  547.  * Remove trailing Blanks.
  548.  *
  549.  * ensure
  550.  *   (a.Count()=0) OR (a.chars[a.Count()-1]#Blank)
  551.  *)
  552.  
  553. BEGIN
  554.   WHILE (a.len>0) & (a.chars[a.len-1]=Blank) DO
  555.     DEC(a.len);
  556.     a.chars[a.len] := 0X;
  557.   END;
  558. END RightAdjust;
  559.  
  560.  
  561. PROCEDURE (a: STRING) Shrink * (t: STRING; n1,n2: LONGINT);
  562. (*
  563.  * remove characters outside of interval n1..n2
  564.  *
  565.  * require
  566.  *   t#NIL;
  567.  *   0  <= n1;
  568.  *   n1 <= n2;
  569.  *   n2 <  t.Count();
  570.  * ensure
  571.  *   a.Equal(t.Substring(n1,n2));
  572.  *)
  573.  
  574. VAR
  575.   i: LONGINT;
  576. BEGIN
  577.   a.Enlarge(n2-n1+1);
  578.   FOR i := 0 TO n2-n1 DO
  579.     a.chars[i] := t.chars[n1+i];
  580.   END;
  581.   a.len := n2-n1+1;
  582.   IF a.len<LEN(a.chars^) THEN a.chars[a.len] := 0X END;
  583. END Shrink;
  584.  
  585.  
  586. PROCEDURE (a: STRING) Substring * (n1,n2: LONGINT): STRING;
  587. (*
  588.  * Copy of substring of current string containing all characters
  589.  * at indices between n1 and n2.
  590.  *
  591.  * require
  592.  *   0  <= n1;
  593.  *   n1 <= n2;
  594.  *   n2 <  t.Count()
  595.  * ensure
  596.  *   Result.Count = n2 - n1 + 1;
  597.  *   for all i: 0 .. n2-n1, Result.chars[i] = a.chars[n1+i]
  598.  *)
  599.  
  600. VAR
  601.   new: STRING;
  602.   i: LONGINT;
  603. BEGIN
  604.   new := Create(n2-n1+2);
  605.   FOR i := 0 TO n2-n1 DO
  606.     new.chars[i] := a.chars[n1+i];
  607.   END;
  608.   new.len := n2-n1+1;
  609.   new.chars[new.len] := 0X;
  610.   RETURN new;
  611. END Substring;
  612.  
  613.  
  614. PROCEDURE (a: STRING) Tail * (n: LONGINT);
  615. (*
  616.  * Remove all but the last n characters of the string.
  617.  * Do nothing for n >= a.Count();
  618.  *
  619.  * require
  620.  *   n >= 0;
  621.  * ensure
  622.  *   n <  OLD a.Count() IMPLIES a.Count() = n;
  623.  *   n >= OLD a.Count() IMPLIES a.Count() = OLD a.Count;
  624.  *)
  625.  
  626. VAR
  627.   i: LONGINT;
  628.  
  629. BEGIN
  630.   IF n<a.len THEN
  631.     FOR i:=0 TO n-1 DO
  632.       a.chars[i] := a.chars[a.len - n + i];
  633.     END;
  634.     a.len := n;
  635.     a.chars[n] := 0X;
  636.   END;
  637. END Tail;
  638.  
  639.  
  640. PROCEDURE (a: STRING) ToC * (): SYSTEM.ADDRESS;
  641. (*
  642.  * Address of the string that a C function may cast into a pointer to a
  643.  * C form of the string. Useful only for interfacing with C software.
  644.  *)
  645.  
  646. BEGIN
  647.   a.Enlarge(a.len+1);
  648.   RETURN SYSTEM.ADR(a.chars^);
  649. END ToC;
  650.  
  651.  
  652. PROCEDURE (a: STRING) ToInteger * (): LONGINT;
  653. (*
  654.  * Integer value of current string, assumed to contain digits only.
  655.  * When applied to "123", will yield 123.
  656.  *
  657.  * require
  658.  *   for all i: 0..a.Count()-1, ("0"<=a.chars[i]) & (a.chars[i]<="9")
  659.  *)
  660.  
  661. VAR
  662.   Result: LONGINT;
  663.   i: LONGINT;
  664.   negative: BOOLEAN;
  665.  
  666. BEGIN
  667.   Result := 0; negative := FALSE;
  668.   IF a.len>0 THEN
  669.     CASE a.chars[0] OF
  670.     | "-": i := 1; negative := TRUE;
  671.     | "+": i := 1;
  672.     ELSE   i := 0;
  673.     END;
  674.     WHILE (i<a.len) DO
  675.       CASE a.chars[i] OF
  676.       | "0".."9":
  677.         IF Result < (MAX(LONGINT) - (ORD(a.chars[i]) - ORD("0"))) DIV 10 THEN
  678.           Result := 10 * Result + (ORD(a.chars[i]) - ORD("0"));
  679.         END;
  680.       ELSE END;
  681.       INC(i);
  682.     END;
  683.   END;
  684.   RETURN Result;
  685. END ToInteger;
  686.  
  687.  
  688. PROCEDURE (a: STRING) ToLower *;
  689. (*
  690.  * Convert a to lower case
  691.  *)
  692.  
  693. VAR
  694.   i: LONGINT;
  695. BEGIN
  696.   FOR i:=0 TO a.len-1 DO
  697.     CASE a.chars[i] OF
  698.     | "A".."Z","À".."Ö","Ø".."þ": a.chars[i] := CHR(ORD(a.chars[i]) + 32)
  699.     ELSE END;
  700.   END;
  701. END ToLower;
  702.  
  703.  
  704. PROCEDURE (a: STRING) ToUpper *;
  705. (*
  706.  * Convert a to lower case
  707.  *)
  708.  
  709. VAR
  710.   i: LONGINT;
  711. BEGIN
  712.   FOR i:=0 TO a.len-1 DO
  713.     CASE a.chars[i] OF
  714.     | "a".."z","à".."ö","ø".."þ": a.chars[i] := CHR(ORD(a.chars[i]) - 32)
  715.     ELSE END;
  716.   END;
  717. END ToUpper;
  718.  
  719.  
  720. END STRING.
  721.  
  722.  
  723.  
  724.  
  725.  
  726.  
  727.  
  728.