StringLib.cp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. (* ============================================================= *)
  2. (* Preliminary library module for Gardens Point Component Pascal *)
  3. (* ============================================================= *)
  4. MODULE StringLib; (* from GPM module StdStrings.mod kjg june 1989 *)
  5. IMPORT RTS;
  6. CONST nul = 0X;
  7. (* ============================================================ *)
  8. PROCEDURE CanAssignAll*(sLen : INTEGER;
  9. IN dest : ARRAY OF CHAR) : BOOLEAN;
  10. (** Check if an assignment is possible without truncation.
  11. *)
  12. BEGIN
  13. RETURN LEN(dest) > sLen; (* must leave room for nul *)
  14. END CanAssignAll;
  15. PROCEDURE Assign* (IN src : ARRAY OF CHAR;
  16. OUT dst : ARRAY OF CHAR);
  17. (** Assign as much as possible of src to dst,
  18. * leaving room for a terminating ASCII nul.
  19. *)
  20. VAR ix, hi : INTEGER;
  21. ch : CHAR;
  22. BEGIN
  23. hi := MIN(LEN(src), LEN(dst)) - 1;
  24. FOR ix := 0 TO hi DO
  25. ch := src[ix];
  26. dst[ix] := ch;
  27. IF ch = nul THEN RETURN END;
  28. END;
  29. (*
  30. * We have copied up to index "hi"
  31. * without finding a nul in "src"
  32. *)
  33. dst[hi] := nul;
  34. END Assign;
  35. (* ============================================================ *)
  36. PROCEDURE CanExtractAll*(len : INTEGER;
  37. sIx : INTEGER;
  38. num : INTEGER;
  39. OUT dst : ARRAY OF CHAR) : BOOLEAN;
  40. (** Check if an extraction of "num" charcters,
  41. * starting at source index "sIx" is possible.
  42. *)
  43. BEGIN
  44. RETURN (sIx + num <= len) &
  45. (LEN(dst) > num); (* leave room for nul *)
  46. END CanExtractAll;
  47. PROCEDURE Extract* (IN src : ARRAY OF CHAR;
  48. sIx : INTEGER;
  49. num : INTEGER;
  50. OUT dst : ARRAY OF CHAR);
  51. (** Extract "num" characters starting at index "sIx".
  52. * Result is truncated if either there are fewer characters
  53. * left in the source, or the destination is too short.
  54. *)
  55. VAR ch : CHAR;
  56. sLm : INTEGER;
  57. dLm : INTEGER;
  58. dIx : INTEGER;
  59. BEGIN
  60. sLm := LEN(src$) - 1; (* max index of source *)
  61. dLm := LEN(dst) - 1; (* max index of dest. *)
  62. IF sIx < 0 THEN RTS.Throw("StdStrings.Extract: Bad start index") END;
  63. IF num < 0 THEN RTS.Throw("StdStrings.Extract: Bad char. count") END;
  64. IF sIx > sLm THEN dst[0] := nul; RETURN END;
  65. IF (sIx + num - 1) < sLm THEN sLm := sIx + num - 1 END;
  66. dIx := 0;
  67. FOR sIx := sIx TO sLm DO
  68. IF dIx = dLm THEN dst[dIx] := nul; RETURN END;
  69. ch := src[sIx];
  70. dst[dIx] := ch;
  71. INC(dIx);
  72. END;
  73. dst[dIx] := nul;
  74. END Extract;
  75. (* ============================================================ *)
  76. PROCEDURE CanDeleteAll*( len : INTEGER;
  77. sIx : INTEGER;
  78. num : INTEGER) : BOOLEAN;
  79. (** Check if "num" characters may be deleted starting
  80. * from index "sIx", when len is the source length.
  81. *)
  82. BEGIN
  83. RETURN (sIx < len) & (sIx + num <= len);
  84. END CanDeleteAll;
  85. PROCEDURE Delete*(VAR str : ARRAY OF CHAR;
  86. sIx : INTEGER;
  87. num : INTEGER);
  88. VAR sLm, mIx : INTEGER;
  89. (** Delete "num" characters starting from index "sIx".
  90. * Less characters are deleted if there are less
  91. * than "num" characters after "sIx".
  92. *)
  93. BEGIN
  94. sLm := LEN(str$) - 1;
  95. IF sIx < 0 THEN RTS.Throw("StdStrings.Delete: Bad start index") END;
  96. IF num < 0 THEN RTS.Throw("StdStrings.Delete: Bad char. count") END;
  97. (* post : lim is length of str *)
  98. IF sIx < sLm THEN (* else do nothing *)
  99. IF sIx + num <= sLm THEN (* else sIx is unchanged *)
  100. mIx := sIx + num;
  101. WHILE mIx <= sLm DO
  102. str[sIx] := str[mIx]; INC(sIx); INC(mIx);
  103. END;
  104. END;
  105. str[sIx] := nul;
  106. END;
  107. END Delete;
  108. (* ============================================================ *)
  109. PROCEDURE CanInsertAll*(sLen : INTEGER;
  110. sIdx : INTEGER;
  111. VAR dest : ARRAY OF CHAR) : BOOLEAN;
  112. (** Check if "sLen" characters may be inserted into "dest"
  113. * starting from index "sIdx".
  114. *)
  115. VAR dLen : INTEGER;
  116. dCap : INTEGER;
  117. BEGIN
  118. dCap := LEN(dest)-1; (* max chars in destination string *)
  119. dLen := LEN(dest$); (* current chars in destination str *)
  120. RETURN (sIdx < dLen) &
  121. (dLen + sLen < dCap);
  122. END CanInsertAll;
  123. PROCEDURE Insert* (IN src : ARRAY OF CHAR;
  124. sIx : INTEGER;
  125. VAR dst : ARRAY OF CHAR);
  126. (** Insert "src" string into "dst" starting from index
  127. * "sIx". Less characters are inserted if there is not
  128. * sufficient space in the destination. The destination is
  129. * unchanged if "sIx" is beyond the end of the initial string.
  130. *)
  131. VAR dLen, sLen, dCap, iEnd, cEnd : INTEGER;
  132. idx : INTEGER;
  133. BEGIN
  134. dCap := LEN(dst)-1;
  135. sLen := LEN(src$);
  136. dLen := LEN(dst$); (* dst[dLen] is index of the nul *)
  137. IF sIx < 0 THEN RTS.Throw("StdStrings.Insert: Bad start index") END;
  138. (* skip trivial case *)
  139. IF (sIx > dLen) OR (sLen = 0) THEN RETURN END;
  140. iEnd := MIN(sIx + sLen, dCap); (* next index after last insert position *)
  141. cEnd := MIN(dLen + sLen, dCap); (* next index after last string position *)
  142. FOR idx := cEnd-1 TO iEnd BY -1 DO
  143. dst[idx] := dst[idx-sLen];
  144. END;
  145. FOR idx := 0 TO sLen - 1 DO
  146. dst[idx+sIx] := src[idx];
  147. END;
  148. dst[cEnd] := nul;
  149. END Insert;
  150. (* ============================================================ *)
  151. PROCEDURE CanReplaceAll*(len : INTEGER;
  152. sIx : INTEGER;
  153. VAR dst : ARRAY OF CHAR) : BOOLEAN;
  154. (** Check if "len" characters may be replaced in "dst"
  155. * starting from index "sIx".
  156. *)
  157. BEGIN
  158. RETURN len + sIx <= LEN(dst$);
  159. END CanReplaceAll;
  160. PROCEDURE Replace* (IN src : ARRAY OF CHAR;
  161. sIx : INTEGER;
  162. VAR dst : ARRAY OF CHAR);
  163. (** Insert the characters of "src" string into "dst" starting
  164. * from index "sIx". Less characters are replaced if the
  165. * initial length of the destination string is insufficient.
  166. * The string length of "dst" is unchanged.
  167. *)
  168. VAR dLen, sLen, ix : INTEGER;
  169. BEGIN
  170. dLen := LEN(dst$);
  171. sLen := LEN(src$);
  172. IF sIx >= dLen THEN RETURN END;
  173. IF sIx < 0 THEN RTS.Throw("StdStrings.Replace: Bad start index") END;
  174. FOR ix := sIx TO MIN(sIx+sLen-1, dLen-1) DO
  175. dst[ix] := src[ix-sIx];
  176. END;
  177. END Replace;
  178. (* ============================================================ *)
  179. PROCEDURE CanAppendAll*(len : INTEGER;
  180. VAR dst : ARRAY OF CHAR) : BOOLEAN;
  181. (** Check if "len" characters may be appended to "dst"
  182. *)
  183. VAR dLen : INTEGER;
  184. dCap : INTEGER;
  185. BEGIN
  186. dCap := LEN(dst)-1; (* max chars in destination string *)
  187. dLen := LEN(dst$); (* current chars in destination str *)
  188. RETURN dLen + len <= dCap;
  189. END CanAppendAll;
  190. PROCEDURE Append*(src : ARRAY OF CHAR;
  191. VAR dst : ARRAY OF CHAR);
  192. (** Append the characters of "src" string onto "dst".
  193. * Less characters are appended if the length of the
  194. * destination string is insufficient.
  195. *)
  196. VAR dLen, dCap, sLen : INTEGER;
  197. idx : INTEGER;
  198. BEGIN
  199. dCap := LEN(dst)-1; (* max chars in destination string *)
  200. dLen := LEN(dst$); (* current chars in destination str *)
  201. sLen := LEN(src$);
  202. FOR idx := 0 TO sLen-1 DO
  203. IF dLen = dCap THEN dst[dCap] := nul; RETURN END;
  204. dst[dLen] := src[idx]; INC(dLen);
  205. END;
  206. dst[dLen] := nul;
  207. END Append;
  208. (* ============================================================ *)
  209. PROCEDURE Capitalize*(VAR str : ARRAY OF CHAR);
  210. VAR ix : INTEGER;
  211. BEGIN
  212. FOR ix := 0 TO LEN(str$)-1 DO str[ix] := CAP(str[ix]) END;
  213. END Capitalize;
  214. (* ============================================================ *)
  215. PROCEDURE FindNext* (IN pat : ARRAY OF CHAR;
  216. IN str : ARRAY OF CHAR;
  217. bIx : INTEGER; (* Begin index *)
  218. OUT fnd : BOOLEAN;
  219. OUT pos : INTEGER);
  220. (** Find the first occurrence of the pattern string "pat"
  221. * in "str" starting the search from index "bIx".
  222. * If no match is found "fnd" is set FALSE and "pos"
  223. * is set to "bIx". Empty patterns match everywhere.
  224. *)
  225. VAR pIx, sIx : INTEGER;
  226. pLn, sLn : INTEGER;
  227. sCh : CHAR;
  228. BEGIN
  229. pos := bIx;
  230. pLn := LEN(pat$);
  231. sLn := LEN(str$);
  232. (* first check that string extends to bIx *)
  233. IF bIx >= sLn - pLn THEN fnd := FALSE; RETURN END;
  234. IF pLn = 0 THEN fnd := TRUE; RETURN END;
  235. IF bIx < 0 THEN RTS.Throw("StdStrings.FindNext: Bad start index") END;
  236. sCh := pat[0];
  237. FOR sIx := bIx TO sLn - pLn - 1 DO
  238. IF str[sIx] = sCh THEN (* possible starting point! *)
  239. pIx := 0;
  240. REPEAT
  241. INC(pIx);
  242. IF pIx = pLn THEN fnd := TRUE; pos := sIx; RETURN END;
  243. UNTIL str[sIx + pIx] # pat[pIx];
  244. END;
  245. END;
  246. fnd := FALSE;
  247. END FindNext;
  248. (* ============================================================ *)
  249. PROCEDURE FindPrev*(IN pat : ARRAY OF CHAR;
  250. IN str : ARRAY OF CHAR;
  251. bIx : INTEGER; (* begin index *)
  252. OUT fnd : BOOLEAN;
  253. OUT pos : INTEGER);
  254. (** Find the previous occurrence of the pattern string "pat"
  255. * in "str" starting the search from index "bIx".
  256. * If no match is found "fnd" is set FALSE and "pos"
  257. * is set to "bIx". A pattern starting from "bIx" is found.
  258. * Empty patterns match everywhere.
  259. *)
  260. VAR pIx, sIx : INTEGER;
  261. pLn, sLn : INTEGER;
  262. sCh : CHAR;
  263. BEGIN
  264. pos := bIx;
  265. pLn := LEN(pat$);
  266. sLn := LEN(str$);
  267. IF pLn = 0 THEN fnd := TRUE; RETURN END;
  268. IF pLn > sLn THEN fnd := FALSE; RETURN END;
  269. IF bIx < 0 THEN RTS.Throw("StdStrings.FindPrev: Bad start index") END;
  270. (* start searching from bIx OR sLn - pLn *)
  271. sCh := pat[0];
  272. FOR sIx := MIN(bIx, sLn - pLn - 1) TO 0 BY - 1 DO
  273. IF str[sIx] = sCh THEN (* possible starting point! *)
  274. pIx := 0;
  275. REPEAT
  276. INC(pIx);
  277. IF pIx = pLn THEN fnd := TRUE; pos := sIx; RETURN END;
  278. UNTIL str[sIx + pIx] # pat[pIx];
  279. END;
  280. END;
  281. fnd := FALSE;
  282. END FindPrev;
  283. (* ============================================================ *)
  284. PROCEDURE FindDiff* (IN str1 : ARRAY OF CHAR;
  285. IN str2 : ARRAY OF CHAR;
  286. OUT diff : BOOLEAN;
  287. OUT dPos : INTEGER);
  288. (** Find the index of the first charater of difference
  289. * between the two input strings. If the strings are
  290. * identical "diff" is set FALSE, and "dPos" is zero.
  291. *)
  292. VAR ln1, ln2, idx : INTEGER;
  293. BEGIN
  294. ln1 := LEN(str1$);
  295. ln2 := LEN(str2$);
  296. FOR idx := 0 TO MIN(ln1, ln2) DO
  297. IF str1[idx] # str2[idx] THEN
  298. diff := TRUE; dPos := idx; RETURN; (* PRE-EMPTIVE RETURN *)
  299. END;
  300. END;
  301. dPos := 0;
  302. diff := (ln1 # ln2); (* default result *)
  303. END FindDiff;
  304. (* ============================================================ *)
  305. END StringLib.