STREDIT.MOD 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. IMPLEMENTATION MODULE StrEdit;
  2. (*
  3. * REPERTOIRE
  4. * Release 1.6
  5. * By Charles Bradford and Cole Brecheen
  6. * (c) Copyright 1985-1992 PMI
  7. * Green Bay, Wisconsin
  8. * All rights reserved
  9. * (414) 468-6040
  10. *
  11. * $Header: D:/logfiles/mods/stredit.mov 1.7 17 Mar 1991 17:58:52 coleb $
  12. *
  13. *)
  14. IMPORT LowLevel;
  15. IMPORT M2Strings;
  16. IMPORT Numbers;
  17. IMPORT ScanUtils;
  18. IMPORT SYSTEM;
  19. VAR
  20. Initialized : BOOLEAN;
  21. PROCEDURE Init();
  22. BEGIN
  23. IF Initialized THEN
  24. RETURN;
  25. ELSE
  26. Initialized := TRUE;
  27. END;
  28. LowLevel.Init();
  29. M2Strings.Init();
  30. Numbers.Init();
  31. ScanUtils.Init();
  32. END Init;
  33. CONST
  34. BLANK = ' ';
  35. TAB = 11C;
  36. PROCEDURE AssignStr(instr : ARRAY OF CHAR; VAR outstr : ARRAY OF CHAR);
  37. (*Allows assignment of constants to strings; Logitech's Assign has
  38. two VAR parameters. Changed 24 May 87 to use HIGH instead
  39. of SYSTEM.SIZE because M2SDS's SIZE returns incorrect results.*)
  40. VAR
  41. insize, outsize : CARDINAL;
  42. BEGIN
  43. insize := 1+HIGH(instr);
  44. outsize := 1+HIGH(outstr);
  45. IF insize>outsize THEN
  46. LowLevel.Move(SYSTEM.ADR(instr), SYSTEM.ADR(outstr), outsize);
  47. ELSE
  48. LowLevel.Move(SYSTEM.ADR(instr), SYSTEM.ADR(outstr), insize);
  49. SetLength(outstr, M2Strings.Length(instr));
  50. END;
  51. END AssignStr;
  52. PROCEDURE Append( VAR TheStr: ARRAY OF CHAR; AppStr: ARRAY OF CHAR);
  53. VAR
  54. HighAppStr, leng, leng2: CARDINAL;
  55. BEGIN
  56. HighAppStr := HIGH(AppStr);
  57. (* Exposes a nasty bug in Stony Brook M2. *)
  58. leng := M2Strings.Length(TheStr);
  59. leng2 := Numbers.Min(M2Strings.Length(AppStr), (HIGH(TheStr)+1-leng));
  60. IF leng2 > 0 THEN
  61. LowLevel.Move(SYSTEM.ADR(AppStr), SYSTEM.ADR(TheStr[leng]), leng2);
  62. INC(leng, leng2);
  63. IF leng <= HIGH(TheStr) THEN
  64. TheStr[leng] := 0C;
  65. END;
  66. END;
  67. END Append;
  68. PROCEDURE ReplaceTabs(VAR TheStr : ARRAY OF CHAR; tabInterval: CARDINAL);
  69. VAR
  70. cnt, tabspot, offsetToNextTabStop : CARDINAL;
  71. tabstr : ARRAY [0..15] OF CHAR;
  72. BEGIN
  73. tabspot := M2Strings.Pos(TAB, TheStr);
  74. WHILE (tabspot<=HIGH(TheStr)) DO
  75. M2Strings.Delete(TheStr, tabspot, 1);
  76. LowLevel.Fill( SYSTEM.ADR(tabstr), 16, BLANK );
  77. offsetToNextTabStop := tabInterval - (tabspot MOD tabInterval);
  78. tabstr[offsetToNextTabStop] := 0C;
  79. M2Strings.Insert(tabstr, TheStr, tabspot);
  80. tabspot := M2Strings.Pos(TAB, TheStr);
  81. END;
  82. END ReplaceTabs;
  83. PROCEDURE tabStop(thespot : CARDINAL; tabInterval: CARDINAL) : BOOLEAN;
  84. BEGIN
  85. RETURN (((thespot MOD tabInterval) = 0) AND (thespot # 0));
  86. END tabStop;
  87. PROCEDURE InsertTabs(VAR TheStr : ARRAY OF CHAR; tabInterval: CARDINAL;
  88. leadingOnly: BOOLEAN);
  89. VAR
  90. index, leng, spaceStrLngth, tabStrLngth : CARDINAL;
  91. spacestr : ARRAY [0..79] OF CHAR;
  92. tabstr : ARRAY [0..15] OF CHAR;
  93. newstr : ARRAY [0..255] OF CHAR;
  94. nonBlankFound: BOOLEAN;
  95. BEGIN
  96. (*InsertTabs*)
  97. ReplaceTabs(TheStr, tabInterval);
  98. (* We don't want to have to deal with the complication of tabs
  99. * already in TheStr, so we start by expanding them to blanks.
  100. *)
  101. leng := M2Strings.Length(TheStr);
  102. IF leng = 0 THEN
  103. RETURN;
  104. END;
  105. DEC(leng);
  106. spacestr := '';
  107. spaceStrLngth := 0;
  108. tabstr := '';
  109. tabStrLngth := 0;
  110. newstr := '';
  111. nonBlankFound := FALSE;
  112. FOR index := 0 TO leng DO
  113. IF NOT (leadingOnly AND nonBlankFound) THEN
  114. IF tabStop(index, tabInterval) AND (spaceStrLngth > 1) THEN
  115. Append(tabstr, TAB);
  116. INC(tabStrLngth);
  117. IF (spaceStrLngth > tabInterval) THEN
  118. (* What's happened here is that we had a single space
  119. * immediately preceding a tab stop before this last
  120. * run of spaces. We refused to replace it with a
  121. * tab because we had only one space to replace it
  122. * with. Now, however, we see that something has to
  123. * go there -- could either be a space or a tab. We
  124. * choose a tab.
  125. *)
  126. Append(tabstr, TAB);
  127. INC(tabStrLngth);
  128. END;
  129. spacestr := '';
  130. spaceStrLngth := 0;
  131. END;
  132. IF TheStr[index]=BLANK THEN
  133. Append(spacestr, BLANK);
  134. INC(spaceStrLngth);
  135. END;
  136. IF tabStrLngth > 0 THEN
  137. Append(newstr, tabstr);
  138. tabstr := '';
  139. tabStrLngth := 0;
  140. END;
  141. IF (spaceStrLngth > 0) AND (TheStr[index] # BLANK) THEN
  142. (* We've hit a nonblank and we're not at a tabstop, so we're
  143. * not going to get to replace this last sequence of blanks
  144. * with a tab.
  145. *)
  146. Append(newstr, spacestr);
  147. spacestr := '';
  148. spaceStrLngth := 0;
  149. END;
  150. END;
  151. IF (TheStr[index] # BLANK) OR (leadingOnly AND nonBlankFound) THEN
  152. Append(newstr, TheStr[index]);
  153. nonBlankFound := TRUE;
  154. END;
  155. END;
  156. AssignStr(newstr, TheStr);
  157. END InsertTabs;
  158. PROCEDURE InsertTimes(Ch : CHAR; VAR TheStr : ARRAY OF CHAR; indx,
  159. times : CARDINAL);
  160. VAR
  161. cnt : CARDINAL;
  162. BEGIN
  163. IF times = 0 THEN RETURN END;
  164. LowLevel.ShiftArrayRight( SYSTEM.ADR(TheStr[indx]), (HIGH(TheStr) + 1) -
  165. indx, times );
  166. FOR cnt := 1 TO times DO
  167. TheStr[ indx + cnt - 1 ] := Ch;
  168. END;
  169. END InsertTimes;
  170. PROCEDURE InsertSubstr(str1 : ARRAY OF CHAR; start, lnth :
  171. CARDINAL; VAR str2 : ARRAY OF CHAR; ndx : CARDINAL);
  172. VAR
  173. tmpstr : ARRAY [0..255] OF CHAR;
  174. BEGIN
  175. M2Strings.Copy(str1, start, lnth, tmpstr);
  176. M2Strings.Insert(tmpstr, str2, ndx);
  177. END InsertSubstr;
  178. PROCEDURE OverWrite(obj : ARRAY OF CHAR; VAR targ : ARRAY OF
  179. CHAR; pos : CARDINAL);
  180. (*Unconditionally writes obj into targ beginning at pos, and for the length of
  181. obj, wipes out anything that may have been in targ at that position.*)
  182. VAR
  183. max, i : CARDINAL;
  184. BEGIN
  185. max := M2Strings.Length(obj);
  186. IF max = 0 THEN RETURN END;
  187. (* bug fix submitted by Henk Hofmans, 8 Feb 87 *)
  188. IF (max>15) OR ((max+pos) > M2Strings.Length(targ)) THEN
  189. (*This test is only for optimization purposes.*)
  190. M2Strings.Delete(targ, pos, M2Strings.Length(obj));
  191. M2Strings.Insert(obj, targ, pos);
  192. ELSE
  193. FOR i := 0 TO (max-1) DO
  194. targ[pos+i] := obj[i];
  195. END;
  196. END;
  197. END OverWrite;
  198. PROCEDURE ReplaceStr(
  199. searchstr, replacstr : ARRAY OF CHAR;
  200. VAR TheStr : ARRAY OF CHAR);
  201. VAR
  202. spot, lngth1, lngth2 : CARDINAL;
  203. repeating: BOOLEAN;
  204. BEGIN
  205. lngth1 := M2Strings.Length( searchstr );
  206. lngth2 := M2Strings.Length( replacstr );
  207. spot := ScanUtils.Positn( searchstr, replacstr, 0, ScanUtils.CaseSens );
  208. repeating := spot > HIGH(replacstr);
  209. (* If repeating = FALSE, then the old string is embedded
  210. in the new string, and we'll get hung in an infinite
  211. loop if we try to replace all instances of the old
  212. string. *)
  213. spot := ScanUtils.Positn( searchstr, TheStr, 0, ScanUtils.CaseSens );
  214. WHILE spot<=HIGH(TheStr) DO
  215. M2Strings.Delete(TheStr, spot, lngth1);
  216. M2Strings.Insert(replacstr, TheStr, spot);
  217. IF repeating THEN
  218. spot := ScanUtils.Positn( searchstr, TheStr, 0,
  219. ScanUtils.CaseSens );
  220. ELSE
  221. spot := ScanUtils.Positn( searchstr, TheStr, spot + lngth2,
  222. ScanUtils.CaseSens );
  223. END;
  224. END;
  225. END ReplaceStr;
  226. PROCEDURE ReplaceStrInsens(
  227. searchstr, replacstr : ARRAY OF CHAR;
  228. VAR TheStr : ARRAY OF CHAR);
  229. VAR
  230. spot, lngth1, lngth2 : CARDINAL;
  231. repeating: BOOLEAN;
  232. BEGIN
  233. lngth1 := M2Strings.Length( searchstr );
  234. lngth2 := M2Strings.Length( replacstr );
  235. spot := ScanUtils.Positn( searchstr, replacstr, 0,
  236. ScanUtils.CaseInsens );
  237. repeating := spot > HIGH(replacstr);
  238. (* If repeating = FALSE, then the old string is embedded
  239. in the new string, and we'll get hung in an infinite
  240. loop if we try to replace all instances of the old
  241. string. *)
  242. spot := ScanUtils.Positn( searchstr, TheStr, 0,
  243. ScanUtils.CaseInsens );
  244. WHILE spot<=HIGH(TheStr) DO
  245. M2Strings.Delete(TheStr, spot, lngth1);
  246. M2Strings.Insert(replacstr, TheStr, spot);
  247. IF repeating THEN
  248. spot := ScanUtils.Positn( searchstr, TheStr, 0,
  249. ScanUtils.CaseInsens );
  250. ELSE
  251. spot := ScanUtils.Positn( searchstr, TheStr, spot + lngth2,
  252. ScanUtils.CaseInsens );
  253. END;
  254. END;
  255. END ReplaceStrInsens;
  256. PROCEDURE CrunchBlanks(VAR line : ARRAY OF CHAR);
  257. VAR
  258. LastNotBlank : BOOLEAN;
  259. LengthOfLine, ResultIndex, index, LeftOvers : CARDINAL;
  260. BEGIN
  261. ReplaceTabs(line, 8);
  262. LastNotBlank := FALSE;
  263. LengthOfLine := M2Strings.Length(line);
  264. IF LengthOfLine = 0 THEN
  265. RETURN;
  266. END;
  267. ResultIndex := 0;
  268. FOR index := 0 TO (LengthOfLine-1) DO
  269. IF line[index]<>BLANK THEN
  270. LastNotBlank := TRUE;
  271. line[ResultIndex] := line[index];
  272. INC(ResultIndex);
  273. ELSIF LastNotBlank THEN
  274. LastNotBlank := FALSE;
  275. line[ResultIndex] := line[index];
  276. INC(ResultIndex);
  277. END;
  278. END;
  279. IF (ResultIndex>0) AND (line[ResultIndex-1]=BLANK) THEN
  280. DEC(ResultIndex);
  281. END;
  282. LeftOvers := LengthOfLine-ResultIndex;
  283. IF LeftOvers>0 THEN
  284. M2Strings.Delete(line, ResultIndex, LeftOvers);
  285. END;
  286. END CrunchBlanks;
  287. PROCEDURE CutLeadingChars(TheChar : CHAR; VAR TheStr : ARRAY OF
  288. CHAR);
  289. (*deletes any TheChar's at the start of TheStr*)
  290. VAR
  291. NonMatchFound : BOOLEAN;
  292. ndx, StrLen : CARDINAL;
  293. BEGIN
  294. StrLen := M2Strings.Length(TheStr);
  295. IF StrLen=0 THEN
  296. RETURN;
  297. END;
  298. ndx := 0;
  299. IF (TheStr[ndx]=TheChar) THEN
  300. NonMatchFound := FALSE;
  301. WHILE ((ndx + 1) < StrLen) AND (NOT NonMatchFound) DO
  302. INC(ndx);
  303. NonMatchFound := TheStr[ndx]#TheChar;
  304. END;
  305. IF NOT NonMatchFound THEN
  306. INC(ndx);
  307. END;
  308. M2Strings.Delete(TheStr, 0, ndx);
  309. END;
  310. END CutLeadingChars;
  311. PROCEDURE CutTrailingChars(TheChar : CHAR; VAR TheStr : ARRAY
  312. OF CHAR);
  313. (*deletes any TheChar's at the end of TheStr*)
  314. VAR
  315. index : CARDINAL;
  316. BEGIN
  317. index := M2Strings.Length(TheStr);
  318. IF index > 0 THEN
  319. LOOP
  320. IF TheStr[ index - 1] = TheChar THEN
  321. DEC(index);
  322. IF index = 0 THEN
  323. TheStr[0] := 0C;
  324. RETURN;
  325. END;
  326. ELSIF index <= HIGH(TheStr) THEN
  327. TheStr[index] := 0C;
  328. RETURN;
  329. ELSE
  330. RETURN;
  331. END;
  332. END;
  333. END;
  334. END CutTrailingChars;
  335. PROCEDURE LowerStr(VAR TheStr : ARRAY OF CHAR);
  336. VAR
  337. pointer, leng : CARDINAL;
  338. CONST
  339. shiftdown = 32;
  340. BEGIN
  341. leng := M2Strings.Length(TheStr);
  342. IF leng = 0 THEN
  343. RETURN;
  344. END;
  345. DEC( leng);
  346. FOR pointer := 0 TO leng DO
  347. IF (TheStr[pointer]>='A') AND (TheStr[pointer]<='Z') THEN
  348. TheStr[pointer] := CHR( ORD(TheStr[pointer]) + shiftdown);
  349. END;
  350. END;
  351. END LowerStr;
  352. PROCEDURE CAPstr(VAR TheStr : ARRAY OF CHAR);
  353. VAR
  354. pointer, leng : CARDINAL;
  355. CONST
  356. shiftdown = 32;
  357. BEGIN
  358. leng := M2Strings.Length(TheStr);
  359. IF leng = 0 THEN
  360. RETURN;
  361. END;
  362. DEC( leng);
  363. FOR pointer := 0 TO leng DO
  364. TheStr[pointer] := CAP(TheStr[pointer]);
  365. END;
  366. END CAPstr;
  367. PROCEDURE DeleteChar(TheChar : CHAR; VAR x : ARRAY OF CHAR);
  368. VAR
  369. spot : CARDINAL;
  370. BEGIN
  371. spot := M2Strings.Pos(TheChar, x);
  372. WHILE spot<=HIGH(x) DO
  373. M2Strings.Delete(x, spot, 1);
  374. spot := M2Strings.Pos(TheChar, x);
  375. END;
  376. END DeleteChar;
  377. PROCEDURE SetLength( VAR TheStr : ARRAY OF CHAR; NewLength :
  378. CARDINAL);
  379. VAR
  380. OldLength, MaxLength: CARDINAL;
  381. BEGIN
  382. OldLength := M2Strings.Length( TheStr);
  383. IF NewLength # OldLength THEN
  384. MaxLength := HIGH(TheStr) + 1;
  385. IF OldLength < MaxLength THEN
  386. (* if a null exists that must be filled *)
  387. IF OldLength > 0 THEN
  388. TheStr[ OldLength] := TheStr[ OldLength - 1 ];
  389. (* the current last character in the string *)
  390. ELSIF MaxLength > 1 THEN
  391. TheStr[ OldLength] := TheStr[ 1 ];
  392. ELSE
  393. TheStr[ OldLength] := BLANK;
  394. END;
  395. END;
  396. IF NewLength < MaxLength THEN
  397. (* set the new length *)
  398. TheStr[ NewLength] := 0C;
  399. END;
  400. END;
  401. END SetLength;
  402. PROCEDURE RightJustify( VAR TheStr: ARRAY OF CHAR;
  403. RequiredLength: CARDINAL );
  404. VAR strlength: CARDINAL;
  405. BEGIN
  406. IF NOT ScanUtils.IsBlank( TheStr ) THEN
  407. CutTrailingChars( BLANK, TheStr );
  408. END;
  409. strlength := M2Strings.Length( TheStr );
  410. WHILE strlength > RequiredLength DO
  411. M2Strings.Delete( TheStr, 0, 1 );
  412. DEC( strlength );
  413. END;
  414. WHILE strlength < RequiredLength DO
  415. M2Strings.Insert( BLANK, TheStr, 0 );
  416. INC( strlength );
  417. END;
  418. END RightJustify;
  419. PROCEDURE LeftJustify( VAR TheStr: ARRAY OF CHAR;
  420. RequiredLength: CARDINAL );
  421. VAR strlength: CARDINAL;
  422. BEGIN
  423. IF NOT ScanUtils.IsBlank( TheStr ) THEN
  424. CutLeadingChars( BLANK, TheStr );
  425. END;
  426. strlength := M2Strings.Length( TheStr );
  427. IF strlength > RequiredLength THEN
  428. SetLength( TheStr, RequiredLength );
  429. ELSE
  430. WHILE strlength < RequiredLength DO
  431. Append( TheStr, BLANK );
  432. INC( strlength );
  433. END;
  434. END;
  435. END LeftJustify;
  436. PROCEDURE MakeCurrency( CurrencySymbol: ARRAY OF CHAR;
  437. VAR TheStr: ARRAY OF CHAR );
  438. VAR
  439. spot, lngth: CARDINAL;
  440. BEGIN
  441. DeleteChar( ' ', TheStr );
  442. IF NOT ScanUtils.Present( CurrencySymbol, TheStr,
  443. ScanUtils.CaseSens ) THEN
  444. M2Strings.Insert( CurrencySymbol, TheStr, 0 );
  445. END;
  446. lngth := M2Strings.Length(TheStr);
  447. IF lngth < 3 THEN
  448. RightJustify( TheStr, 3 );
  449. lngth := 3;
  450. END;
  451. IF NOT ScanUtils.PresentPos( '.', TheStr, spot,
  452. ScanUtils.CaseSens ) THEN
  453. Append( TheStr, '.' );
  454. INC( lngth );
  455. ELSIF spot < (lngth - 3) THEN
  456. M2Strings.Delete( TheStr, spot + 3, lngth - (spot + 3) );
  457. RETURN;
  458. END;
  459. WHILE (TheStr[ lngth - 3 ] # '.') AND (lngth < (HIGH(TheStr) + 1)) DO
  460. Append( TheStr, '0' );
  461. INC( lngth );
  462. END;
  463. END MakeCurrency;
  464. PROCEDURE Center( VAR TheStr: ARRAY OF CHAR;
  465. RequiredLength: CARDINAL );
  466. VAR
  467. PadLength, strlength: CARDINAL;
  468. BEGIN
  469. IF NOT ScanUtils.IsBlank( TheStr ) THEN
  470. CutLeadingChars( BLANK, TheStr );
  471. CutTrailingChars( BLANK, TheStr );
  472. END;
  473. strlength := M2Strings.Length( TheStr );
  474. IF strlength > RequiredLength THEN
  475. SetLength( TheStr, RequiredLength );
  476. ELSIF strlength < RequiredLength THEN
  477. PadLength := (RequiredLength - strlength) DIV 2;
  478. InsertTimes( ' ', TheStr, 0, PadLength );
  479. strlength := strlength + PadLength;
  480. PadLength := RequiredLength - strlength;
  481. InsertTimes( ' ', TheStr, strlength, PadLength );
  482. END;
  483. END Center;
  484. PROCEDURE InsertRightJustified( str1: ARRAY OF CHAR; VAR
  485. str2: ARRAY OF CHAR; spot: CARDINAL );
  486. (* Inserts str1 into str2 without changing the length of
  487. str2. Deletes characters from the beginning of str2 to
  488. make room for str1. Truncates str1 if necessary. *)
  489. VAR
  490. str1length, str2length: CARDINAL;
  491. tmpstr: ARRAY [0..255] OF CHAR;
  492. BEGIN
  493. str1length := M2Strings.Length( str1 );
  494. str2length := M2Strings.Length( str2 );
  495. IF str1length > str2length THEN
  496. SetLength( str1, str2length );
  497. str1length := str2length;
  498. END;
  499. LowLevel.Move( SYSTEM.ADR(str2), SYSTEM.ADR(tmpstr), Numbers.Min( HIGH(str2), HIGH(tmpstr)) + 1 );
  500. (* We assign str2 to a tmpstr to avoid complications
  501. associated with possible overflow of str2, and we do
  502. it with a Move to avoid overhead of an AssignStr. *)
  503. SetLength( tmpstr, str2length );
  504. IF spot >= str2length THEN
  505. (* Means insertions beyond length of str2 will be
  506. appended. *)
  507. Append( str2, str1 );
  508. ELSE
  509. M2Strings.Insert( str1, str2, spot );
  510. END;
  511. M2Strings.Delete( str2, 0, str1length );
  512. END InsertRightJustified;
  513. PROCEDURE DeleteRightJustified( VAR TheStr: ARRAY OF CHAR;
  514. spot, HowMany: CARDINAL );
  515. (* Deletes HowMany characters from TheStr beginning with
  516. spot, and fills in with blanks at the beginning of
  517. TheStr to preserve its former length. *)
  518. VAR
  519. cnt: CARDINAL;
  520. BEGIN
  521. M2Strings.Delete( TheStr, spot, HowMany );
  522. FOR cnt := 1 TO HowMany DO
  523. M2Strings.Insert( BLANK, TheStr, 0 );
  524. END;
  525. END DeleteRightJustified;
  526. BEGIN
  527. Initialized := FALSE;
  528. Init();
  529. END StrEdit.