home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 549a.lha / M2P_v1.0 / mods.lzh / Strings.mod < prev    next >
Text File  |  1991-08-10  |  13KB  |  468 lines

  1. (*======================================================================*)
  2. (*               Standard Modula-2 Libraries -- Strings                 *)
  3. (*======================================================================*)
  4. (*  Version:  0.00              Author:   Dennis Brueni                 *)
  5. (*  Date:     06-21-91          Changes:  original                      *)
  6. (*======================================================================*)
  7. (*  Refs:  --Portable Modula-2 Programming -- Woodman, Griffith,        *)
  8. (*           Souter, and Davies                                         *)
  9. (*         --Interim Version of 4th Working Draft Modula-2 Standard     *)
  10. (*======================================================================*)
  11. (* Notes:  (implementation specific)                                    *)
  12. (*                                                                      *)
  13. (* This is the portable version which is coded in Modula-2 rather than  *)
  14. (* assembly.  The only implementation dependent feature used is the     *)
  15. (* choice of StrTerm (StringTerminator) as ASCII.NUL.                   *)
  16. (*======================================================================*)
  17.  
  18. IMPLEMENTATION MODULE Strings;
  19.  
  20. IMPORT
  21.     ASCII;
  22.  
  23.  
  24.  
  25. (*----------------------------------------------------------------------*)
  26.  
  27. CONST
  28.     StrTerm = ASCII.NUL;
  29.  
  30.  
  31.        (* I trust this code, although it relies on     *)
  32.      (* boolean expression short circuiting          *)
  33.  
  34. (*----------------------------------------------------------------------*)
  35.  
  36.  
  37.  
  38. PROCEDURE Length(StringVal: ARRAY OF CHAR) : CARDINAL;
  39.  
  40. VAR
  41.     i: CARDINAL;
  42. BEGIN
  43.     i:=0;
  44.     WHILE (i<=HIGH(StringVal)) AND (StringVal[i] # StrTerm) DO
  45.         INC(i);
  46.     END;
  47.       (* Postcondition:       *)
  48.     RETURN(i);                      (* i=HIGH+1 OR S[i]=NUL *)
  49. END Length;
  50.  
  51. (*----------------------------------------------------------------------*)
  52.  
  53.  
  54.  
  55. PROCEDURE Assign(Source: ARRAY OF CHAR; VAR Destination: ARRAY OF CHAR);
  56.  
  57. VAR
  58.     len,siz,i: CARDINAL;
  59. BEGIN
  60.     siz:=HIGH(Destination)+1;       (* Capacity of Destination      *)
  61.     len:=Length(Source);            (* Length of Source             *)
  62.     IF len >= siz THEN
  63.         len:=siz;               (* Truncate of too big          *)
  64.     ELSE
  65.         Destination[len]:=StrTerm;
  66.                     (* Else insert Terminator       *)
  67.     END;
  68.     i:=len;
  69.     WHILE (i#0) DO
  70.         DEC(i);
  71.         Destination[i]:=Source[i];
  72.     END;
  73. END Assign;
  74.  
  75. (*----------------------------------------------------------------------*)
  76.  
  77.  
  78.  
  79. PROCEDURE Extract(Source: ARRAY OF CHAR; StartIndex, NumberToExtract:CARDINAL; VAR Destination:ARRAY OF CHAR);
  80.  
  81. VAR
  82.     len,i: CARDINAL;
  83.  
  84. BEGIN
  85.     IF NumberToExtract > HIGH(Destination) THEN
  86.                     (* Truncate if size is  *)
  87.         NumberToExtract:=HIGH(Destination)+1;
  88.                     (* too big to fit.      *)
  89.     END;
  90.     len:=Length(Source);
  91.     IF StartIndex > len THEN        (* Invalid Start Index  *)
  92.         NumberToExtract:=0;
  93.     ELSIF NumberToExtract+StartIndex >= len THEN
  94.                     (* If trying to extract *)
  95.         NumberToExtract:=len-StartIndex;
  96.                     (* more than there is   *)
  97.     END;
  98.     i:=0;
  99.     WHILE (i<NumberToExtract) DO
  100.         Destination[i]:=Source[StartIndex+i];
  101.         INC(i);
  102.     END;
  103.     IF HIGH(Destination) >= NumberToExtract THEN
  104.                     (* If There's room,     *)
  105.         Destination[NumberToExtract]:=StrTerm;
  106.                     (* append terminator    *)
  107.     END;
  108. END Extract;
  109.  
  110. (*----------------------------------------------------------------------*)
  111.  
  112. PROCEDURE Delete(VAR StringValue: ARRAY OF CHAR; StartIndex, NumberToDelete: CARDINAL);
  113.  
  114. VAR
  115.     len,i: CARDINAL;
  116.  
  117. BEGIN
  118.     len:=Length(StringValue);
  119.     IF StartIndex <= len THEN       (* Invalid Start Index  *)
  120.         IF NumberToDelete > 0 THEN
  121.                     (* Anything TO DO?      *)
  122.             IF NumberToDelete+StartIndex>=len THEN
  123.                     (* Deleting past end is *)
  124.                 StringValue[StartIndex]:=StrTerm;
  125.                     (* same as truncating.  *)
  126.             ELSE
  127.                 i:=StartIndex;
  128.                 WHILE (i<len-NumberToDelete) DO
  129.                     StringValue[i]:=StringValue[NumberToDelete+i];
  130.                     INC(i);
  131.                 END;
  132.                 StringValue[len-NumberToDelete]:=StrTerm;
  133.             END;
  134.         END;
  135.     END;
  136. END Delete;
  137.  
  138. (*----------------------------------------------------------------------*)
  139.  
  140.  
  141.  
  142. PROCEDURE Insert(Source: ARRAY OF CHAR; StartIndex: CARDINAL; VAR Destination: ARRAY OF CHAR);
  143.  
  144. VAR
  145.     DestLen,SourceLen,DestSize,i: CARDINAL;
  146.  
  147. BEGIN
  148.     DestLen :=Length(Destination);
  149.     DestSize :=HIGH(Destination)+1;
  150.     SourceLen:=Length(Source);
  151.  
  152.     IF StartIndex <= DestLen THEN   (* Legal Start Index    *)
  153.         IF SourceLen + DestLen >= DestSize THEN
  154.                     (* Doesn't fit in Dest. *)
  155.             IF SourceLen + StartIndex >= DestSize THEN
  156.                     (* Too long     *)
  157.                 SourceLen := DestSize - StartIndex;
  158.                     (* Truncate Source      *)
  159.                 DestLen := StartIndex;
  160.                     (* Truncate Destination *)
  161.             ELSE
  162.                 DestLen := DestSize-SourceLen;
  163.                     (* Just Truncate Dest.  *)
  164.             END;
  165.         ELSE
  166.             Destination[SourceLen+DestLen]:=StrTerm;
  167.                     (* Plug in Terminator *)
  168.         END;
  169.         i:=DestLen;
  170.         WHILE (i>StartIndex) DO
  171.             DEC(i);
  172.             Destination[SourceLen+i]:=Destination[i];
  173.         END;
  174.         i:=SourceLen;
  175.         WHILE (i>0) DO
  176.             DEC(i);
  177.             Destination[StartIndex+i]:=Source[i];
  178.         END;
  179.     END;
  180. END Insert;
  181.  
  182. (*----------------------------------------------------------------------*)
  183.  
  184.  
  185.  
  186. PROCEDURE Replace(Source: ARRAY OF CHAR; StartIndex: CARDINAL; VAR Destination: ARRAY OF CHAR);
  187.  
  188. VAR
  189.     DestLen,SourceLen,i: CARDINAL;
  190.  
  191. BEGIN
  192.     DestLen :=Length(Destination);
  193.     SourceLen:=Length(Source);
  194.  
  195.     IF StartIndex < DestLen THEN    (* If legal Start Index *)
  196.         IF SourceLen + StartIndex > DestLen THEN
  197.                     (* Truncate Source if   *)
  198.             SourceLen := DestLen - StartIndex;
  199.                     (* too big.             *)
  200.         END;
  201.         i:=SourceLen;
  202.         WHILE (i>0) DO
  203.             DEC(i);
  204.             Destination[StartIndex+i]:=Source[i];
  205.         END;
  206.     END;
  207. END Replace;
  208.  
  209. (*----------------------------------------------------------------------*)
  210.  
  211.  
  212.  
  213. PROCEDURE Append(Source: ARRAY OF CHAR; VAR Destination: ARRAY OF CHAR);
  214.  
  215. VAR
  216.     SourceLen,DestLen,i: CARDINAL;
  217. BEGIN
  218.     DestLen:=Length(Destination);
  219.     SourceLen:=Length(Source);
  220.     IF DestLen+SourceLen > HIGH(Destination) THEN
  221.         SourceLen:=HIGH(Destination)+1-DestLen;
  222.     ELSE
  223.         Destination[DestLen+SourceLen]:=StrTerm;
  224.     END;
  225.     i:=SourceLen;
  226.     WHILE (i#0) DO
  227.         DEC(i);
  228.         Destination[DestLen+i]:=Source[i];
  229.     END;
  230. END Append;
  231.  
  232. (*----------------------------------------------------------------------*)
  233. (* The optimization of not copying the pass-by-value strings on the     *)
  234. (* stack (@NoCopyStrings) cannot be used here since an undesirable      *)
  235. (* side-effect will result if Source2 and Destination are the same.     *)
  236. (*----------------------------------------------------------------------*)
  237.  
  238. PROCEDURE Concat(Source1, Source2: ARRAY OF CHAR; VAR Destination: ARRAY OF CHAR);
  239. BEGIN
  240.     Assign(Source1,Destination);
  241.     Append(Source2,Destination);
  242. END Concat;
  243.  
  244. (*----------------------------------------------------------------------*)
  245. (* NOTE:  This should really use CharClass.IsLower, CharClass.ToUpper   *)
  246. (*----------------------------------------------------------------------*)
  247.  
  248. PROCEDURE Capitalize(VAR StringVar: ARRAY OF CHAR);
  249.  
  250. VAR
  251.     i,len: CARDINAL;
  252. BEGIN
  253.     len:=Length(StringVar);
  254.     i:=0;
  255.     WHILE i<len DO
  256.         IF (StringVar[i]>='a') AND (StringVar[i]<='z') THEN
  257.             StringVar[i]:=CHR(ORD(StringVar[i])-ORD('a')+ORD('A'));
  258.         END;
  259.         INC(i);
  260.     END;
  261. END Capitalize;
  262.  
  263. (*----------------------------------------------------------------------*)
  264. (* Compare two string values according to the implementation-defined    *)
  265. (* collating sequence.  This is the local version to this module which  *)
  266. (* is shared by Equal, Compare, and FindDiff.                           *)
  267. (*----------------------------------------------------------------------*)
  268.  
  269. PROCEDURE Comp(VAR String1,String2: ARRAY OF CHAR; VAR i: CARDINAL):CompareResult;
  270.  
  271. VAR
  272.     len1,len2,minlen: CARDINAL;
  273.  
  274. BEGIN
  275.     len1:=Length(String1);
  276.     len2:=Length(String2);
  277.     minlen:=len2;
  278.     IF minlen>len1 THEN
  279.         minlen:=len1;
  280.     END;
  281.     i:=0;
  282.     WHILE i<minlen DO
  283.         IF String1[i] > String2[i] THEN
  284.             RETURN greater;
  285.         END;
  286.         IF String1[i] < String2[i] THEN
  287.             RETURN less;
  288.         END;
  289.         INC(i);
  290.     END;
  291.     IF len2=len1 THEN
  292.         RETURN equal;
  293.     END;
  294.     IF len2>len1 THEN
  295.         RETURN less;            (* The longer one is    *)
  296.     ELSE
  297.         RETURN greater;
  298.     END;                            (* considered the high  *)
  299. END Comp;
  300.  
  301. (*----------------------------------------------------------------------*)
  302.  
  303.  
  304.  
  305. PROCEDURE Compare(StringVal1: ARRAY OF CHAR; StringVal2: ARRAY OF CHAR): CompareResult;
  306. VAR
  307.     dummy: CARDINAL;
  308. BEGIN
  309.     RETURN Comp(StringVal1,StringVal2,dummy);
  310. END Compare;
  311.  
  312. (*----------------------------------------------------------------------*)
  313.  
  314.  
  315.  
  316. PROCEDURE Equal(StringVal1: ARRAY OF CHAR; StringVal2: ARRAY OF CHAR): BOOLEAN;
  317. VAR
  318.     dummy: CARDINAL;
  319. BEGIN
  320.     RETURN Comp(StringVal1,StringVal2,dummy)=equal;
  321. END Equal;
  322.  
  323. (*----------------------------------------------------------------------*)
  324.  
  325.  
  326.  
  327. PROCEDURE FindDiff(StringVal1: ARRAY OF CHAR; StringVal2: ARRAY OF CHAR; VAR DifferenceFound: BOOLEAN; VAR PosOfDifference:
  328. CARDINAL);
  329. VAR
  330.     dummy: CARDINAL;
  331. BEGIN
  332.     DifferenceFound:=Comp(StringVal1,StringVal2,dummy)#equal;
  333.     IF DifferenceFound THEN
  334.         PosOfDifference:=dummy;
  335.     END;
  336. END FindDiff;
  337.  
  338. (*----------------------------------------------------------------------*)
  339.  
  340.  
  341.  
  342. PROCEDURE FindNext(Pattern: ARRAY OF CHAR; StringValue: ARRAY OF CHAR; StartIndex: CARDINAL; VAR PatternFound: BOOLEAN; VAR
  343. PosOfPattern: CARDINAL);
  344.  
  345. VAR
  346.     i,patlen,len,pos: CARDINAL;
  347.  
  348. BEGIN
  349.     len:=Length(StringValue);
  350.     patlen:=Length(Pattern);
  351.     IF patlen<=len THEN
  352.         IF len-patlen>=StartIndex THEN
  353.             pos:=StartIndex;
  354.             WHILE pos<=len-patlen DO
  355.                     (* While still within String    *)
  356.                 i:=0;
  357.                 LOOP
  358.                     IF i>=patlen THEN
  359.                     (* If matched entire Pattern    *)
  360.                         PatternFound:=TRUE;
  361.                         PosOfPattern:=pos;
  362.                         RETURN;
  363.                     END;
  364.                     IF (i+pos>=len) OR (StringValue[i+pos] <> Pattern[i]) THEN
  365.                         EXIT;
  366.                     END;
  367.                     INC(i);
  368.                 END;
  369.                 INC(pos);
  370.                     (* No Match, Next...            *)
  371.             END;
  372.         END;
  373.     END;
  374.     PatternFound:=FALSE;
  375. END FindNext;
  376.  
  377. (*----------------------------------------------------------------------*)
  378.  
  379.  
  380.  
  381. PROCEDURE FindPrev(Pattern: ARRAY OF CHAR; StringValue: ARRAY OF CHAR; StartIndex: CARDINAL; VAR PatternFound: BOOLEAN; VAR
  382. PosOfPattern: CARDINAL);
  383.  
  384. VAR
  385.     i,patlen,len,pos: CARDINAL;
  386.  
  387. BEGIN
  388.     len:=Length(StringValue);
  389.     patlen:=Length(Pattern);
  390.     IF (patlen<=len) AND (StartIndex>=patlen) THEN
  391.         IF StartIndex>len-patlen THEN
  392.             StartIndex:=len;
  393.         END;
  394.         pos:=StartIndex-patlen+1;
  395.         WHILE pos>0 DO          (* While still within String    *)
  396.             DEC(pos);       (* No Match, Next...            *)
  397.             i:=0;
  398.             LOOP
  399.                 IF i>=patlen THEN
  400.                     (* If matched entire Pattern    *)
  401.                     PatternFound:=TRUE;
  402.                     PosOfPattern:=pos;
  403.                     RETURN;
  404.                 END;
  405.                 IF (i+pos>=len) OR (StringValue[i+pos] <> Pattern[i]) THEN
  406.                     EXIT;
  407.                 END;
  408.                 INC(i);
  409.             END;
  410.         END;
  411.     END;
  412.     PatternFound:=FALSE;
  413. END FindPrev;
  414.  
  415. (*----------------------------------------------------------------------*)
  416.  
  417. PROCEDURE CanAssignAll(SourceLength: CARDINAL; VAR Destination: ARRAY OF CHAR): BOOLEAN;
  418. BEGIN
  419.     RETURN HIGH(Destination)+1 >= SourceLength;
  420. END CanAssignAll;
  421.  
  422. (*----------------------------------------------------------------------*)
  423.  
  424. PROCEDURE CanExtractAll(SourceLength, StartIndex, NumberToExtract: CARDINAL; VAR Destination: ARRAY OF CHAR): BOOLEAN;
  425. BEGIN
  426.     RETURN (StartIndex + NumberToExtract <= SourceLength) AND (HIGH(Destination)+1 >= NumberToExtract);
  427. END CanExtractAll;
  428.  
  429. (*----------------------------------------------------------------------*)
  430.  
  431. PROCEDURE CanDeleteAll(StringLength, StartIndex, NumberToDelete: CARDINAL): BOOLEAN;
  432. BEGIN
  433.     RETURN (StartIndex < StringLength) AND (StringLength+1 > StartIndex + NumberToDelete );
  434. END CanDeleteAll;
  435.  
  436. (*----------------------------------------------------------------------*)
  437.  
  438. PROCEDURE CanInsertAll(SourceLength, StartIndex: CARDINAL; VAR Destination: ARRAY OF CHAR): BOOLEAN;
  439. VAR
  440.     LDest: CARDINAL;
  441. BEGIN
  442.     LDest:=Length(Destination);
  443.     RETURN (StartIndex <= LDest) AND (LDest+SourceLength <= HIGH(Destination)+1);
  444. END CanInsertAll;
  445.  
  446. (*----------------------------------------------------------------------*)
  447.  
  448. PROCEDURE CanReplaceAll(SourceLength, StartIndex: CARDINAL; VAR Destination: ARRAY OF CHAR): BOOLEAN;
  449. BEGIN
  450.     RETURN SourceLength + StartIndex <= Length (Destination);
  451. END CanReplaceAll;
  452.  
  453. (*----------------------------------------------------------------------*)
  454.  
  455. PROCEDURE CanAppendAll(SourceLength: CARDINAL; VAR Destination: ARRAY OF CHAR): BOOLEAN;
  456. BEGIN
  457.     RETURN Length(Destination) + SourceLength <= HIGH(Destination)+1;
  458. END CanAppendAll;
  459.  
  460. (*----------------------------------------------------------------------*)
  461.  
  462. PROCEDURE CanConcatAll(Source1Length, Source2Length: CARDINAL; VAR Destination: ARRAY OF CHAR): BOOLEAN;
  463. BEGIN
  464.     RETURN Source1Length + Source2Length <= HIGH(Destination)+1;
  465. END CanConcatAll;
  466.  
  467. END Strings.
  468.