SCANUTIL.MOD 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. IMPLEMENTATION MODULE ScanUtils;
  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/scanutil.mov 1.2 17 Mar 1991 17:56:48 coleb $
  12. *
  13. *)
  14. IMPORT LowLevel;
  15. IMPORT M2Strings;
  16. IMPORT Numbers;
  17. IMPORT StrEdit;
  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. StrEdit.Init();
  32. END Init;
  33. CONST
  34. space = ' ';
  35. tab = CHAR(9);
  36. PROCEDURE ScanForByte(size : INTEGER; lookfor : SYSTEM.BYTE;
  37. start : SYSTEM.ADDRESS; caseMatters: CaseSensitivity ) : INTEGER;
  38. VAR
  39. cnt: INTEGER;
  40. tmpAdr: LowLevel.Address8086;
  41. BEGIN
  42. tmpAdr.x := start;
  43. IF size < 0 THEN
  44. FOR cnt := 0 TO ABS(size + 1) DO
  45. IF caseMatters = CaseInsens THEN
  46. IF CAP(CHAR(lookfor)) = CAP(tmpAdr.b^) THEN
  47. RETURN cnt;
  48. END;
  49. ELSE
  50. IF CHAR(lookfor) = tmpAdr.b^ THEN
  51. RETURN cnt;
  52. END;
  53. END;
  54. DEC(tmpAdr.off);
  55. END;
  56. ELSIF size > 0 THEN
  57. FOR cnt := 0 TO (size - 1) DO
  58. IF caseMatters = CaseInsens THEN
  59. IF CAP(CHAR(lookfor)) = CAP(tmpAdr.b^) THEN
  60. RETURN cnt;
  61. END;
  62. ELSE
  63. IF CHAR(lookfor) = tmpAdr.b^ THEN
  64. RETURN cnt;
  65. END;
  66. END;
  67. INC(tmpAdr.off);
  68. END;
  69. END;
  70. RETURN size;
  71. END ScanForByte;
  72. PROCEDURE BreakPoint(VAR thestr : ARRAY OF CHAR; maxlength : CARDINAL;
  73. breakchars : ARRAY OF CHAR) : CARDINAL;
  74. VAR
  75. cnt : CARDINAL;
  76. BEGIN
  77. cnt := maxlength-1;
  78. WHILE (cnt>0) AND
  79. (Pos(thestr[cnt], breakchars, CaseSens) > HIGH(breakchars)) DO
  80. DEC(cnt);
  81. END;
  82. IF (cnt=0) AND
  83. (Pos(thestr[0], breakchars, CaseSens) > HIGH(breakchars)) THEN
  84. RETURN (maxlength);
  85. ELSE
  86. RETURN (cnt);
  87. END;
  88. END BreakPoint;
  89. PROCEDURE BreakPtAdr( TheAdr: SYSTEM.ADDRESS; TheSize: CARDINAL;
  90. maxlength : CARDINAL; breakchars : ARRAY OF CHAR) :
  91. CARDINAL;
  92. VAR
  93. cnt : CARDINAL;
  94. tmp : LowLevel.Address8086;
  95. BEGIN
  96. cnt := maxlength-1;
  97. tmp.a := TheAdr;
  98. INC( tmp.off, cnt );
  99. WHILE (cnt>0) AND (NOT Present(tmp.b^, breakchars, CaseSens)) DO
  100. DEC( tmp.off );
  101. DEC(cnt);
  102. END;
  103. IF (cnt=0) AND (NOT Present(tmp.b^, breakchars, CaseSens)) THEN
  104. RETURN maxlength;
  105. ELSE
  106. RETURN cnt;
  107. END;
  108. END BreakPtAdr;
  109. PROCEDURE ByteCount( size: CARDINAL; lookfor: CHAR; start:
  110. SYSTEM.ADDRESS): CARDINAL;
  111. VAR
  112. cnt, offset, skipped: CARDINAL;
  113. BEGIN
  114. cnt := 0;
  115. offset := 0;
  116. WHILE offset < size DO
  117. skipped := LowLevel.ScanEQ( size - offset, lookfor,
  118. LowLevel.AddAddr(start, offset) );
  119. IF skipped < (size - offset) THEN
  120. INC( cnt );
  121. INC( offset, skipped + 1 );
  122. ELSE
  123. RETURN cnt;
  124. END;
  125. END;
  126. RETURN cnt;
  127. END ByteCount;
  128. PROCEDURE Equal( str1, str2: ARRAY OF CHAR;
  129. caseMatters: CaseSensitivity ): BOOLEAN;
  130. BEGIN
  131. IF caseMatters = CaseInsens THEN
  132. StrEdit.CAPstr(str1);
  133. StrEdit.CAPstr(str2);
  134. END;
  135. RETURN M2Strings.CompareStr(str1, str2) = 0;
  136. END Equal;
  137. PROCEDURE FindNthPattern(pattern: ARRAY OF CHAR; which: CARDINAL;
  138. searchIn: ARRAY OF CHAR; caseMatters: CaseSensitivity ): CARDINAL;
  139. VAR
  140. cnt, lastSpot, inLngth: CARDINAL;
  141. found : BOOLEAN;
  142. BEGIN
  143. found := FALSE;
  144. lastSpot := 0;
  145. cnt := 0;
  146. inLngth := M2Strings.Length(searchIn);
  147. REPEAT
  148. lastSpot := Positn(pattern, searchIn, lastSpot, caseMatters);
  149. IF lastSpot >= inLngth THEN
  150. cnt := which + 1;
  151. ELSE
  152. INC(cnt);
  153. END;
  154. IF cnt = which THEN
  155. found := TRUE;
  156. END;
  157. UNTIL found OR (cnt > which);
  158. IF cnt > which THEN
  159. RETURN(65535);
  160. ELSE
  161. RETURN(lastSpot);
  162. END;
  163. END FindNthPattern;
  164. PROCEDURE FirstNonMatching(TheChar : CHAR; VAR TheStr : ARRAY OF CHAR) :
  165. CHAR;
  166. (* Returns the first character in TheStr that does not match
  167. TheChar. If none found, returns TheChar. *)
  168. VAR
  169. spot, leng : CARDINAL;
  170. BEGIN
  171. leng := M2Strings.Length(TheStr);
  172. IF leng = 0 THEN
  173. RETURN TheChar;
  174. END;
  175. spot := LowLevel.ScanNE( leng, TheChar, SYSTEM.ADR(TheStr) );
  176. IF spot < leng THEN
  177. RETURN TheStr[spot];
  178. ELSE
  179. RETURN TheChar;
  180. END;
  181. END FirstNonMatching;
  182. PROCEDURE IsAlphaChar( TheChar: CHAR ): BOOLEAN;
  183. BEGIN
  184. RETURN ((TheChar >= 'a') AND (TheChar <= 'z')) OR ((TheChar
  185. >= 'A') AND (TheChar <= 'Z'));
  186. END IsAlphaChar;
  187. PROCEDURE IsBlank(TheStr : ARRAY OF CHAR) : BOOLEAN;
  188. (*TRUE if thestr is all blanks *)
  189. VAR
  190. answer, leng : CARDINAL;
  191. BEGIN
  192. leng := M2Strings.Length(TheStr);
  193. IF leng=0 THEN
  194. RETURN TRUE;
  195. END;
  196. answer := LowLevel.ScanNE(leng,space,SYSTEM.ADR(TheStr));
  197. RETURN (answer>=leng);
  198. END IsBlank;
  199. PROCEDURE IsNextPattern( Pattern: ARRAY OF CHAR; VAR TheStr:
  200. ARRAY OF CHAR; StartingSpot: CARDINAL;
  201. caseMatters: CaseSensitivity ): BOOLEAN;
  202. VAR
  203. tmp, cnt: CARDINAL;
  204. lngth: INTEGER;
  205. tmpadr: LowLevel.Address8086;
  206. result: BOOLEAN;
  207. BEGIN
  208. lngth := INTEGER(M2Strings.Length(TheStr)) - INTEGER(StartingSpot);
  209. (* Don't bother looking if the StartingSpot is greater than the
  210. length of the string. *)
  211. IF lngth < 0 THEN
  212. RETURN FALSE;
  213. END;
  214. tmp := PosAdr( Pattern, LowLevel.AddAddr( SYSTEM.ADR(TheStr),
  215. StartingSpot), CARDINAL(lngth), caseMatters );
  216. (* Figure out where Pattern appears, if at all. *)
  217. IF tmp = CARDINAL(lngth) THEN
  218. (* If it doesn't appear at all, return FALSE. *)
  219. RETURN FALSE;
  220. END;
  221. (* tmp now represents the offset beyond StartingSpot at which
  222. Pattern appears. We want to know if that's the same offset
  223. as the first nonblank character beyond StartingSpot. *)
  224. result := TRUE;
  225. cnt := StartingSpot;
  226. WHILE ((cnt < tmp) AND result) DO
  227. IF (TheStr[cnt] # space) AND (TheStr[cnt] # tab) THEN
  228. result := FALSE;
  229. END;
  230. INC(cnt);
  231. END;
  232. RETURN result;
  233. END IsNextPattern;
  234. PROCEDURE IsNumber( TheStr: ARRAY OF CHAR; StartingSpot:
  235. CARDINAL ): BOOLEAN;
  236. VAR
  237. AllNumbers, PointFound, AtLeastOneFound : BOOLEAN;
  238. EndStr, index : CARDINAL;
  239. bufch : CHAR;
  240. BEGIN
  241. M2Strings.Delete( TheStr, 0, StartingSpot );
  242. StrEdit.CrunchBlanks( TheStr );
  243. EndStr := M2Strings.Length(TheStr);
  244. IF (EndStr = 0) OR Present( space, TheStr, CaseSens ) THEN
  245. RETURN FALSE;
  246. END;
  247. DEC( EndStr );
  248. index := 0;
  249. AtLeastOneFound := FALSE;
  250. PointFound := FALSE;
  251. AllNumbers := TRUE;
  252. REPEAT
  253. bufch := TheStr[index];
  254. IF IsNumericChar( bufch ) THEN
  255. AtLeastOneFound := TRUE;
  256. ELSIF (bufch = '-') OR (bufch = '+') THEN
  257. IF NOT (index = 0) THEN
  258. AllNumbers := FALSE;
  259. END;
  260. ELSIF bufch = '.' THEN
  261. IF PointFound THEN
  262. AllNumbers := FALSE;
  263. ELSE
  264. PointFound := TRUE;
  265. END;
  266. ELSE
  267. AllNumbers := FALSE;
  268. END;
  269. INC( index );
  270. UNTIL (NOT AllNumbers) OR (index > EndStr);
  271. RETURN AtLeastOneFound AND AllNumbers;
  272. END IsNumber;
  273. PROCEDURE IsNumericChar( TheChar: CHAR ): BOOLEAN;
  274. BEGIN
  275. RETURN (TheChar >= '0') AND (TheChar <= '9');
  276. END IsNumericChar;
  277. PROCEDURE IsWhiteSpace( TheChar: CHAR ): BOOLEAN;
  278. BEGIN
  279. RETURN (TheChar = space) OR (TheChar = tab);
  280. END IsWhiteSpace;
  281. PROCEDURE LastNonMatching(TheChar : CHAR; VAR TheStr
  282. : ARRAY OF CHAR) : CHAR;
  283. (* Starts at the end of TheStr and searches backward for a
  284. character that does not match TheChar. If none found,
  285. returns TheChar. *)
  286. VAR
  287. spot: INTEGER;
  288. BEGIN
  289. spot := M2Strings.Length(TheStr);
  290. IF spot = 0 THEN
  291. RETURN TheChar;
  292. ELSE
  293. DEC( spot );
  294. END;
  295. WHILE (TheStr[spot] = TheChar) AND (spot > 0) DO
  296. DEC( spot );
  297. END;
  298. IF spot > 0 THEN
  299. RETURN TheStr[spot];
  300. ELSE
  301. RETURN TheChar;
  302. END;
  303. END LastNonMatching;
  304. PROCEDURE MatchingPos( spot: CARDINAL; TheStr: ARRAY
  305. OF CHAR ): CARDINAL;
  306. (*Returns the position of the ending character that matches
  307. the beginning character at position spot within TheStr. If
  308. TheStr does not have a valid beginning character at spot,
  309. or if spot is not inside the present length of TheStr, or
  310. if no matching ending character is found, MatchingPos
  311. returns spot.*)
  312. VAR
  313. TmpSpot, StackCount, lngth : CARDINAL;
  314. Opener, Closer, bufch: CHAR;
  315. Openers, Closers: ARRAY [0..3] OF CHAR;
  316. BEGIN
  317. StrEdit.AssignStr( '[{(<', Openers );
  318. StrEdit.AssignStr( ']})>', Closers );
  319. lngth := M2Strings.Length( TheStr );
  320. IF spot >= lngth THEN
  321. RETURN spot;
  322. END;
  323. bufch := TheStr[spot];
  324. TmpSpot := LowLevel.ScanEQ(SYSTEM.SIZE(Openers), bufch,
  325. SYSTEM.ADR(Openers) );
  326. IF TmpSpot <= HIGH( Openers ) THEN
  327. Opener := bufch;
  328. Closer := Closers[ TmpSpot ];
  329. TmpSpot := spot + 1;
  330. StackCount := 0;
  331. WHILE TmpSpot < lngth DO
  332. IF TheStr[ TmpSpot ] = Opener THEN
  333. INC( StackCount );
  334. ELSIF TheStr[ TmpSpot ] = Closer THEN
  335. IF StackCount = 0 THEN
  336. RETURN TmpSpot;
  337. ELSE
  338. DEC( StackCount );
  339. END;
  340. END;
  341. INC( TmpSpot );
  342. END;
  343. END;
  344. RETURN spot;
  345. END MatchingPos;
  346. PROCEDURE PatternScan( PatternAdr: SYSTEM.ADDRESS;
  347. PatternSize: CARDINAL; ScanAreaAdr: SYSTEM.ADDRESS;
  348. ScanAreaSize: CARDINAL; caseMatters: CaseSensitivity ): CARDINAL;
  349. VAR
  350. BytesSkipped, ThisScan, cnt, PossibleStartSpots : CARDINAL;
  351. MaxScan: INTEGER;
  352. PatAdr, AreaAdr: LowLevel.Address8086;
  353. BEGIN
  354. PatAdr.a := PatternAdr;
  355. AreaAdr.a := ScanAreaAdr;
  356. IF (ScanAreaSize >= PatternSize) AND (PatternSize#0) THEN
  357. PossibleStartSpots := ScanAreaSize - PatternSize + 1;
  358. IF PossibleStartSpots > 32766 THEN
  359. MaxScan := 32766;
  360. ELSE
  361. MaxScan := PossibleStartSpots;
  362. END;
  363. BytesSkipped := ScanForByte( MaxScan, PatAdr.b^, ScanAreaAdr,
  364. caseMatters );
  365. ThisScan := BytesSkipped;
  366. INC( AreaAdr.off, ThisScan );
  367. WHILE (BytesSkipped < PossibleStartSpots) DO
  368. IF ThisScan < CARDINAL(MaxScan) THEN
  369. cnt := 0;
  370. LOOP
  371. (* as long as following elements equal do:*)
  372. INC( cnt );
  373. IF cnt >= PatternSize THEN
  374. (*if at end of pattern, we've found a match*)
  375. RETURN BytesSkipped;
  376. END;
  377. INC( PatAdr.off );
  378. INC( AreaAdr.off );
  379. IF caseMatters = CaseInsens THEN
  380. IF CAP(AreaAdr.b^) # CAP(PatAdr.b^) THEN
  381. (*if next element # object, stop comparing*)
  382. EXIT;
  383. END;
  384. ELSE
  385. IF AreaAdr.b^ # PatAdr.b^ THEN
  386. (*if next element # object, stop comparing*)
  387. EXIT;
  388. END;
  389. END;
  390. END;
  391. END;
  392. INC( BytesSkipped );
  393. IF BytesSkipped > PossibleStartSpots THEN
  394. RETURN ScanAreaSize;
  395. (* Pattern not found. *)
  396. ELSIF (PossibleStartSpots - BytesSkipped) > 32766 THEN
  397. MaxScan := 32766;
  398. ELSE
  399. MaxScan := PossibleStartSpots - BytesSkipped;
  400. END;
  401. PatAdr.a := PatternAdr;
  402. AreaAdr.a := ScanAreaAdr;
  403. INC( AreaAdr.off, BytesSkipped );
  404. ThisScan := ScanForByte( MaxScan,
  405. PatAdr.b^, AreaAdr.a, caseMatters );
  406. INC( BytesSkipped, ThisScan );
  407. INC( AreaAdr.off, ThisScan );
  408. END;
  409. END;
  410. RETURN ScanAreaSize;
  411. (* Pattern not found. *)
  412. END PatternScan;
  413. PROCEDURE PosAdr(VAR s2 : ARRAY OF CHAR; s : SYSTEM.ADDRESS;
  414. size: CARDINAL; caseMatters: CaseSensitivity ) : CARDINAL;
  415. BEGIN
  416. RETURN PatternScan( SYSTEM.ADR(s2), M2Strings.Length(s2), s,
  417. size, caseMatters );
  418. END PosAdr;
  419. PROCEDURE Pos(s2 : ARRAY OF CHAR; s : ARRAY OF CHAR;
  420. caseMatters: CaseSensitivity ) : CARDINAL;
  421. (* Return the index in s of the first occurence of the substring s2,
  422. or High(s)+1 if there are no occurences of s2.*)
  423. VAR
  424. i, j, n, n2, len : CARDINAL;
  425. BEGIN
  426. n := M2Strings.Length(s);
  427. (*length of string to search in*)
  428. n2 := M2Strings.Length(s2);
  429. (*length of string to search for*)
  430. IF (n >= n2) AND (n2 # 0) THEN
  431. (*only search if target bigger than object; object non-null*)
  432. len := n-n2+1;
  433. (* number of possible starting positions *)
  434. i := ScanForByte(len, s2[0], SYSTEM.ADR(s[0]), caseMatters);
  435. (*changed; start at first occurence of s2[0]*)
  436. WHILE (i<len) DO
  437. (*only for possible starting positions*)
  438. j := 1;
  439. LOOP
  440. (* as long as following elements equal object do:*)
  441. IF j >= n2 THEN
  442. (*if at end of object, finished*)
  443. RETURN i;
  444. END;
  445. IF caseMatters = CaseInsens THEN
  446. IF CAP(s[i+j]) # CAP(s2[0+j]) THEN
  447. (*if next element # to object, stop comparing*)
  448. EXIT;
  449. END;
  450. ELSE
  451. IF s[i+j] # s2[0+j] THEN
  452. (*if next element # to object, stop comparing*)
  453. EXIT;
  454. END;
  455. END;
  456. INC(j);
  457. END;
  458. i := i + 1 + CARDINAL(
  459. ScanForByte( len-1-i, s2[0], SYSTEM.ADR(s[i+1]), caseMatters));
  460. (*changed: try next possible starting position *)
  461. END;
  462. END;
  463. RETURN (HIGH(s)+1);
  464. (* String not found. *)
  465. END Pos;
  466. PROCEDURE PosDelimited(VAR pattern, obj, delimiters : ARRAY OF
  467. CHAR; caseMatters: CaseSensitivity ) : CARDINAL;
  468. (*These are VAR parameters just for purposes of efficiency.
  469. Neither is actually changed.*)
  470. VAR
  471. spot1, spot2 : CARDINAL;
  472. BEGIN
  473. (*PosDelimited*)
  474. IF PresentPos( pattern, obj, spot1, caseMatters ) THEN
  475. spot2 := spot1 + M2Strings.Length(pattern);
  476. (*spot2 should now point to the character after the
  477. pattern*)
  478. IF (spot1=0)
  479. OR
  480. Present(obj[spot1-1], delimiters, caseMatters) THEN
  481. (*Now we know everything to the left of the pattern
  482. is okay.*)
  483. IF (spot2>=M2Strings.Length(obj)) OR Present(obj[spot2],
  484. delimiters, caseMatters) THEN
  485. (*And now we know everything is okay to the right.*)
  486. RETURN (spot1);
  487. END;
  488. END;
  489. END;
  490. RETURN (HIGH(obj)+1);
  491. END PosDelimited;
  492. PROCEDURE Positn(s2 : ARRAY OF CHAR; s : ARRAY OF CHAR; i : CARDINAL;
  493. caseMatters: CaseSensitivity ) : CARDINAL;
  494. (* Return the index in s of the first occurence of the substring s2,
  495. at or after index i, or HIGH(s)+1 if there are no occurences of s2.*)
  496. VAR
  497. len, PosAdrResult: CARDINAL;
  498. BEGIN
  499. len := M2Strings.Length( s );
  500. IF len > i THEN
  501. PosAdrResult := PosAdr( s2, SYSTEM.ADR(s[i]), len - i, caseMatters );
  502. IF PosAdrResult < (len - i) THEN
  503. RETURN i + PosAdrResult;
  504. END;
  505. END;
  506. RETURN (HIGH(s)+1);
  507. (* String not found.*)
  508. END Positn;
  509. PROCEDURE Present(str1, str2 : ARRAY OF CHAR;
  510. caseMatters: CaseSensitivity ) : BOOLEAN;
  511. BEGIN
  512. IF Pos( str1, str2, caseMatters ) <= HIGH(str2) THEN
  513. RETURN (TRUE);
  514. ELSE
  515. RETURN (FALSE);
  516. END;
  517. END Present;
  518. PROCEDURE PresentPos(str1, str2 : ARRAY OF CHAR; VAR spot:
  519. CARDINAL; caseMatters: CaseSensitivity ) : BOOLEAN;
  520. VAR
  521. size: CARDINAL;
  522. BEGIN
  523. size := M2Strings.Length(str2);
  524. spot := PosAdr( str1, SYSTEM.ADR(str2), size, caseMatters );
  525. IF spot < size THEN
  526. RETURN (TRUE);
  527. ELSE
  528. spot := HIGH(str2) + 1;
  529. RETURN (FALSE);
  530. END;
  531. END PresentPos;
  532. PROCEDURE SubStrMatch( str1: ARRAY OF CHAR; StartingAt1,
  533. EndingAt1: CARDINAL; VAR str2: ARRAY OF CHAR; StartingAt2,
  534. EndingAt2: CARDINAL; caseMatters: CaseSensitivity ): BOOLEAN;
  535. VAR
  536. size1, size2, tmpc: CARDINAL;
  537. BEGIN
  538. size1 := M2Strings.Length(str1);
  539. size2 := M2Strings.Length(str2);
  540. IF (size1 <= StartingAt1) OR (size2 <= StartingAt2) OR
  541. (StartingAt1 > EndingAt1) OR (StartingAt2 > EndingAt2) THEN
  542. RETURN FALSE;
  543. END;
  544. size1 := Numbers.Min( EndingAt1 + 1, size1) - StartingAt1;
  545. size2 := Numbers.Min( EndingAt2 + 1, size2) - StartingAt2;
  546. tmpc := PatternScan( SYSTEM.ADR(str1[StartingAt1]), size1,
  547. SYSTEM.ADR(str2[StartingAt2]), size2, caseMatters );
  548. RETURN tmpc = 0;
  549. END SubStrMatch;
  550. BEGIN
  551. Initialized := FALSE;
  552. Init();
  553. END ScanUtils.