Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

781 lines
32 KiB

  1. // static char *SCCSID = "@(#)qmatch.c 13.7 90/08/13";
  2. #include <stdio.h>
  3. #include <ctype.h>
  4. #include <assert.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <windows.h>
  8. #include <stdarg.h>
  9. #include "fsmsg.h"
  10. #define ASCLEN 256 // Number of ascii characters
  11. #define BUFLEN 256 // Temporary buffer length
  12. #define EOS ('\r') // End of string character
  13. #define EOS2 ('\n') // Alternate End of string character
  14. #define PATMAX 512 // Maximum parsed pattern length
  15. #define BEGLINE 0x08 // Match at beginning of line
  16. #define DEBUG 0x20 // Print debugging output
  17. #define ENDLINE 0x10 // Match at end of line
  18. #define T_END 0 // End of expression
  19. #define T_STRING 1 // String to match
  20. #define T_SINGLE 2 // Single character to match
  21. #define T_CLASS 3 // Class to match
  22. #define T_ANY 4 // Match any character
  23. #define T_STAR 5 // *-expr
  24. typedef struct exprnode {
  25. struct exprnode *ex_next; // Next node in list
  26. unsigned char *ex_pattern; // Pointer to pattern to match
  27. } EXPR; // Expression node
  28. static int clists = 1; // One is first available index
  29. static int toklen[] = { // Table of token lengths
  30. 32767, // T_END: invalid
  31. 32767, // T_STRING: invalid
  32. 2, // T_SINGLE
  33. ASCLEN/8+1, // T_CLASS
  34. 1, // T_ANY
  35. 32767 // T_STAR: invalid
  36. };
  37. static int (__cdecl *ncmp)(const char *,const char *,size_t);
  38. // String comparison pointer
  39. extern int casesen; // Case-sensitivity flag
  40. extern char *(*find)(unsigned char *, char *); // Pointer to search function
  41. extern int flags; // Flags
  42. extern int strcnt; // String count
  43. extern char transtab[]; // Translation table
  44. EXPR *stringlist[ASCLEN];
  45. // String table
  46. void addexpr( char *, int ); // Add expression
  47. extern char *alloc(unsigned); // User-defined heap allocator
  48. unsigned char *simpleprefix(); // Match simple prefix
  49. char *strnupr( char *pch, int cch );
  50. void printmessage(FILE *fp, DWORD messagegid, ...);
  51. // Message display function for internationalization(findstr.c)
  52. unsigned char *
  53. simpleprefix(
  54. unsigned char *s, // String pointer
  55. unsigned char **pp // Pointer to pattern pointer
  56. )
  57. {
  58. register unsigned char *p; // Simple pattern pointer
  59. register int c; // Single character
  60. char tmp[2];
  61. tmp[1] = 0;
  62. p = *pp; // Initialize
  63. while(*p != T_END && *p != T_STAR) { // While not at end of pattern
  64. switch(*p++) { // Switch on token type
  65. case T_STRING: // String to compare
  66. if((*ncmp)((char *)s, (char *)p + 1, *p) != 0)
  67. return(NULL);
  68. // Fail if mismatch found
  69. s += *p; // Skip matched portion
  70. p += *p + 1; // Skip to next token
  71. break;
  72. case T_SINGLE: // Single character
  73. c = *s++; // Get character
  74. if(!casesen) {
  75. tmp[0] = (char)c;
  76. c = (unsigned char)(_strupr(tmp))[0];
  77. }
  78. // Map to upper case if necessary
  79. if(c != (int)*p++)
  80. return(NULL);
  81. // Fail if mismatch found
  82. break;
  83. case T_CLASS: // Class of characters
  84. if(!(p[*s >> 3] & (1 << (*s & 7))))
  85. return(NULL); // Failure if bit not set
  86. p += ASCLEN/8; // Skip bit vector
  87. ++s; // Skip character
  88. break;
  89. case T_ANY: // Any character
  90. if(*s == EOS || *s == EOS2)
  91. return(NULL); // Match all but end of string
  92. ++s;
  93. break;
  94. }
  95. }
  96. *pp = p; // Update pointer
  97. return(s); // Pattern is prefix of s
  98. }
  99. int
  100. match(
  101. unsigned char *s, // String to match
  102. unsigned char *p // Pattern to match against
  103. )
  104. {
  105. register unsigned char *q; // Temporary pointer
  106. unsigned char *r; // Temporary pointer
  107. register int c; // Character
  108. char tmp[2];
  109. if(*p != T_END && *p != T_STAR && (s = simpleprefix(s,&p)) == NULL)
  110. return(0); // Failure if prefix mismatch
  111. if(*p++ == T_END)
  112. return(1); // Match if end of pattern
  113. tmp[1] = 0;
  114. q = r = p; // Point to repeated token
  115. r += toklen[*q]; // Skip repeated token
  116. switch(*q++) { // Switch on token type
  117. case T_ANY: // Any character
  118. while(match(s,r) == 0) { // While match not found
  119. if(*s == EOS || *s == EOS2)
  120. return(0); // Match all but end of string
  121. ++s;
  122. }
  123. return(1); // Success
  124. case T_SINGLE: // Single character
  125. while(match(s,r) == 0) { // While match not found
  126. c = *s++; // Get character
  127. if(!casesen) {
  128. tmp[0] = (char)c;
  129. c = (unsigned char)(_strupr(tmp))[0]; // Map to upper case if necessary
  130. }
  131. if((unsigned char) c != *q)
  132. return(0); // Fail if mismatch found
  133. }
  134. return(1); // Success
  135. case T_CLASS: // Class of characters
  136. while(match(s,r) == 0) { // While match not found
  137. if(!(q[*s >> 3] & (1 << (*s & 7))))
  138. return(0); // Fail if bit not set
  139. ++s; // Else skip character
  140. }
  141. return(1); // Success
  142. }
  143. return(0); // Return failure
  144. }
  145. int
  146. exprmatch(
  147. char *s, // String
  148. char *p // Pattern
  149. )
  150. {
  151. ncmp = _strncoll; // Assume case-sensitive
  152. if(!casesen) {
  153. ncmp = _strnicoll;
  154. } // Be case-insensitive if flag set
  155. // See if pattern matches string
  156. return(match((unsigned char *)s, (unsigned char *)p));
  157. }
  158. void
  159. bitset(
  160. char *bitvec, // Bit vector
  161. unsigned char first, // First character
  162. unsigned char last, // Last character
  163. int bitval // Bit value (0 or 1)
  164. )
  165. {
  166. int bitno; // Bit number
  167. bitvec += first >> 3; // Point at first byte
  168. bitno = first & 7; // Calculate first bit number
  169. while(first <= last) { // Loop to set bits
  170. if(bitno == 0 && first + 8 <= last) {
  171. // If we have a whole byte's worth
  172. *bitvec++ = (char)(bitval? '\xFF': '\0');
  173. // Set the bits
  174. first += 8; // Increment the counter
  175. continue; // Next iteration
  176. }
  177. *bitvec=(char)(*bitvec & (unsigned char)(~(1 << bitno))) | (unsigned char)(bitval << bitno);
  178. // Set the appropriate bit
  179. if(++bitno == 8) { // If we wrap into next byte
  180. ++bitvec; // Increment pointer
  181. bitno = 0; // Reset bit index
  182. }
  183. ++first; // Increment bit index
  184. }
  185. }
  186. unsigned char *
  187. exprparse(
  188. unsigned char *p // Raw pattern
  189. )
  190. {
  191. register char *cp; // Char pointer
  192. unsigned char *cp2; // Char pointer
  193. int i; // Counter/index
  194. int j; // Counter/index
  195. int n;
  196. int bitval; // Bit value
  197. char buffer[PATMAX]; // Temporary buffer
  198. char tmp1[2];
  199. char tmp2[2];
  200. char tmp3[2];
  201. unsigned x;
  202. tmp1[1] = tmp2[1] = tmp3[1] = 0;
  203. if(!casesen)
  204. strnupr((char *)p, strlen((char *)p)); // Force pattern to upper case
  205. cp = buffer; // Initialize pointer
  206. if(*p == '^')
  207. *cp++ = *p++; // Copy leading caret if any
  208. while(*p != '\0') { // While not end of pattern
  209. i = -2; // Initialize
  210. for(n = 0;;) { // Loop to delimit ordinary string
  211. n += strcspn((char *)(p + n),".\\[*");// Look for a special character
  212. if(p[n] != '\\')
  213. break; // Break if not backslash
  214. i = n; // Remember where backslash is
  215. if(p[++n] == '\0')
  216. return(NULL); // Cannot be at very end
  217. ++n; // Skip escaped character
  218. }
  219. if(p[n] == '*') { // If we found a *-expr.
  220. if(n-- == 0)
  221. return(NULL); // Illegal first character
  222. if(i == n - 1)
  223. n = i; // Escaped single-char. *-expr.
  224. }
  225. if(n > 0) { // If we have string or single
  226. if(n == 1 || (n == 2 && *p == '\\')) {
  227. // If single character
  228. *cp++ = T_SINGLE; // Set type
  229. if(*p == '\\')
  230. ++p; // Skip escape if any
  231. *cp++ = *p++; // Copy single character
  232. } else { // Else we have a string
  233. *cp++ = T_STRING; // Set type
  234. cp2 = (unsigned char *)cp++; // Save pointer to length byte
  235. while(n-- > 0) { // While bytes to copy remain
  236. if(*p == '\\') { // If escape found
  237. ++p; // Skip escape
  238. --n; // Adjust length
  239. }
  240. *cp++ = *p++; // Copy character
  241. }
  242. *cp2 = (unsigned char)((cp - (char *)cp2) - 1);
  243. // Set string length
  244. }
  245. }
  246. if(*p == '\0')
  247. break; // Break if end of pattern
  248. if(*p == '.') { // If matching any
  249. if(*++p == '*') { // If star follows any
  250. ++p; // Skip star, too
  251. *cp++ = T_STAR; // Insert prefix ahead of token
  252. }
  253. *cp++ = T_ANY; // Match any character
  254. continue; // Next iteration
  255. }
  256. if(*p == '[') { // If character class
  257. if(*++p == '\0')
  258. return(NULL);
  259. // Skip '['
  260. *cp++ = T_CLASS; // Set type
  261. memset(cp,'\0',ASCLEN/8); // Clear the vector
  262. bitval = 1; // Assume we're setting bits
  263. if(*p == '^') { // If inverted class
  264. ++p; // Skip '^'
  265. memset(cp,'\xFF',ASCLEN/8);
  266. // Set all bits
  267. bitset(cp,EOS,EOS,0); // All except end-of-string
  268. bitset(cp,'\n','\n',0); // And linefeed!
  269. bitval = 0; // Now we're clearing bits
  270. }
  271. while(*p != ']') { // Loop to find ']'
  272. if(*p == '\0')
  273. return(NULL); // Check for malformed string
  274. if(*p == '\\') { // If escape found
  275. if(*++p == '\0')
  276. return(NULL); // Skip escape
  277. }
  278. i = *p++; // Get first character in range
  279. if(*p == '-' && p[1] != '\0' && p[1] != ']') {
  280. // If range found
  281. ++p; // Skip hyphen
  282. if(*p == '\\' && p[1] != '\0')
  283. ++p; // Skip escape character
  284. j = *p++; // Get end of range
  285. } else
  286. j = i; // Else just one character
  287. tmp1[0] = (char)i;
  288. tmp2[0] = (char)j;
  289. if (strcoll(tmp1, tmp2) <= 0) {
  290. for (x=0; x<ASCLEN; x++) {
  291. tmp3[0] = (char)x;
  292. if (strcoll(tmp1, tmp3) <= 0 &&
  293. strcoll(tmp3, tmp2) <= 0) {
  294. bitset(cp, (unsigned char)tmp3[0],
  295. (unsigned char)tmp3[0], bitval);
  296. if (!casesen) {
  297. if (isupper(x)) {
  298. _strlwr(tmp3);
  299. } else if (islower(x))
  300. _strupr(tmp3);
  301. else
  302. continue;
  303. bitset(cp, (unsigned char)tmp3[0],
  304. (unsigned char)tmp3[0], bitval);
  305. }
  306. }
  307. }
  308. }
  309. }
  310. if(*++p == '*') { // If repeated class
  311. memmove(cp,cp - 1,ASCLEN/8 + 1);
  312. // Move vector forward 1 byte
  313. cp[-1] = T_STAR; // Insert prefix
  314. ++cp; // Skip to start of vector
  315. ++p; // Skip star
  316. }
  317. cp += ASCLEN/8; // Skip over vector
  318. continue; // Next iteration
  319. }
  320. *cp++ = T_STAR; // Repeated single character
  321. *cp++ = T_SINGLE;
  322. if(*p == '\\')
  323. ++p; // Skip escape if any
  324. *cp++ = *p++; // Copy the character
  325. assert(*p == '*'); // Validate assumption
  326. ++p; // Skip the star
  327. }
  328. *cp++ = T_END; // Mark end of parsed expression
  329. cp2 = (unsigned char *)alloc((int)(cp - buffer)); // Allocate buffer
  330. memmove(cp2, buffer,(int)(cp - buffer)); // Copy expression to buffer
  331. return(cp2); // Return buffer pointer
  332. }
  333. int
  334. istoken(
  335. unsigned char *s, // String
  336. int n // Length
  337. )
  338. {
  339. if(n >= 2 && s[0] == '\\' && s[1] == '<')
  340. return(1); // Token if starts with '\<'
  341. while(n-- > 0) { // Loop to find end of string
  342. if(*s++ == '\\') { // If escape found
  343. if(--n == 0 && *s == '>')
  344. return(1); // Token if ends with '\>'
  345. ++s; // Skip escaped character
  346. }
  347. }
  348. return(0); // Not a token
  349. }
  350. int
  351. isexpr(
  352. unsigned char *s, // String
  353. int n // Length
  354. )
  355. {
  356. unsigned char *cp; // Char pointer
  357. int status; // Return status
  358. char buffer[BUFLEN]; // Temporary buffer
  359. if(istoken(s, n))
  360. return(1); // Tokens are exprs
  361. memmove(buffer,s,n); // Copy string to buffer
  362. buffer[n] = '\0'; // Null-terminate string
  363. if (*buffer && buffer[n - 1] == '$')
  364. return(1);
  365. if((s = exprparse((unsigned char *)buffer)) == NULL)
  366. return(0); // Not an expression if parse fails
  367. status = 1; // Assume we have an expression
  368. if(*s != '^' && *s != T_END) { // If no caret and not empty
  369. status = 0; // Assume not an expression
  370. cp = s; // Initialize
  371. do { // Loop to find special tokens
  372. switch(*cp++) { // Switch on token type
  373. case T_STAR: // Repeat prefix
  374. case T_CLASS: // Character class
  375. case T_ANY: // Any character
  376. ++status; // This is an expression
  377. break;
  378. case T_SINGLE: // Single character
  379. ++cp; // Skip character
  380. break;
  381. case T_STRING: // String
  382. cp += *cp + 1; // Skip string
  383. break;
  384. }
  385. }
  386. while(!status && *cp != T_END)
  387. ; // Do while not at end of expression
  388. }
  389. free(s); // Free expression
  390. return(status); // Return status
  391. }
  392. #ifdef gone // for DEBUG
  393. void
  394. exprprint(
  395. unsigned char *p, // Pointer to expression
  396. FILE *fo // File pointer
  397. )
  398. {
  399. int bit; // Bit value
  400. int count; // Count of characters in string
  401. int first; // First character in range
  402. int last; // Last character in range
  403. int star; // Repeat prefix flag
  404. if(*p == '^')
  405. fputc(*p++,fo); // Print leading caret
  406. while(*p != T_END) { // While not at end of expression
  407. star = 0; // Assume no prefix
  408. if(*p == T_STAR) { // If repeat prefix found
  409. ++star; // Set flag
  410. ++p; // Skip prefix
  411. }
  412. switch(*p++) { // Switch on token type
  413. case T_END: // End of expression
  414. case T_STAR: // Repeat prefix
  415. fprintf(stderr,"Internal error: exprprint\n");
  416. // Not valid
  417. exit(2); // Die abnormal death
  418. case T_STRING: // String
  419. count = *p++; // Get string length
  420. goto common; // Forgive me, Djikstra!
  421. case T_SINGLE: // Single character
  422. count = 1; // Only one character
  423. common:
  424. while(count-- > 0) { // While bytes remain
  425. if(*p == EOS || *p == EOS2) {
  426. // If end-of-string found
  427. ++p; // Skip character
  428. fputc('$',fo); // Emit special marker
  429. continue; // Next iteration
  430. }
  431. if(strchr("*.[\\$",*p) != NULL)
  432. fputc('\\',fo); // Emit escape if needed
  433. fputc(*p++,fo); // Emit the character
  434. }
  435. break;
  436. case T_ANY: // Match any
  437. fputc('.',fo); // Emit dot
  438. break;
  439. case T_CLASS:
  440. first = -1; // Initialize
  441. fputc('[',fo); // Open braces
  442. for(count = ' '; count <= '~'; ++count) {
  443. // Loop through printable characters
  444. if((bit = p[count >> 3] & (1 << (count & 7))) != 0) {
  445. // If bit is set
  446. if(first == -1)
  447. first = count;
  448. // Set first bit
  449. last = count; // Set last bit
  450. }
  451. if((!bit || count == '~') && first != -1) {
  452. // If range to print
  453. if(strchr("\\]-",first) != NULL)
  454. fputc('\\',fo); // Emit escape if needed
  455. fputc(first,fo); // Print first character in range
  456. if(last != first) { // If we have a range
  457. if(last > first + 1)
  458. fputc('-',fo); // Emit hyphen if needed
  459. if(strchr("\\]-",last) != NULL)
  460. fputc('\\',fo); // Emit escape if needed
  461. fputc(last,fo);
  462. // Print last character in range
  463. }
  464. first = -1; // Range printed
  465. }
  466. }
  467. fputc(']',fo); // Close braces
  468. p += ASCLEN/8; // Skip bit vector
  469. break;
  470. }
  471. if(star)
  472. fputc('*',fo); // Print star if needed
  473. }
  474. fputc('\n',fo); // Print newline
  475. }
  476. #endif
  477. char *
  478. get1stcharset(
  479. unsigned char *e, // Pointer to expression
  480. char *bitvec // Pointer to bit vector
  481. )
  482. {
  483. unsigned char *cp; // Char pointer
  484. int i; // Index/counter
  485. int star; // Repeat prefix flag
  486. if(*e == '^')
  487. ++e; // Skip leading caret if any
  488. memset(bitvec,'\0',ASCLEN/8); // Clear bit vector
  489. cp = e; // Initialize
  490. while(*e != T_END) { // Loop to process leading *-expr.s
  491. star = 0; // Assume no repeat prefix
  492. if(*e == T_STAR) { // If repeat prefix found
  493. ++star; // Set flag
  494. ++e; // Skip repeat prefix
  495. }
  496. switch(*e++) { // Switch on token type
  497. case T_END: // End of expression
  498. case T_STAR: // Repeat prefix
  499. assert(0); // Not valid
  500. exit(2); // Die abnormal death
  501. case T_STRING: // String
  502. if(star || *e++ == '\0') { // If repeat prefix or zero count
  503. assert(0); // Not valid
  504. exit(2); // Die abnormal death
  505. }
  506. // Drop through
  507. case T_SINGLE: // Single character
  508. bitset(bitvec,*e,*e,1); // Set the bit
  509. ++e; // Skip the character
  510. break;
  511. case T_ANY: // Match any
  512. memset(bitvec,'\xFF',ASCLEN/8);
  513. // Set all the bits
  514. bitset(bitvec,EOS,EOS,0); // Except end-of-string
  515. bitset(bitvec,'\n','\n',0); // And linefeed!
  516. break;
  517. case T_CLASS:
  518. for(i = 0; i < ASCLEN/8; ++i)
  519. bitvec[i] |= *e++; // Or in all the bits
  520. break;
  521. }
  522. if(!star)
  523. break; // Break if not repeated
  524. cp = e; // Update pointer
  525. }
  526. return((char *)cp); // Point to 1st non-repeated expr.
  527. }
  528. char *
  529. findall(
  530. unsigned char *buffer, // Buffer in which to search
  531. char *bufend // End of buffer
  532. )
  533. {
  534. return(buffer < (unsigned char *) bufend ? (char *) buffer : NULL); // Fail only on empty buffer
  535. }
  536. void
  537. addtoken(
  538. char *e, // Raw token expression
  539. int n // Length of expression
  540. )
  541. {
  542. static char achpref[] = "^";// Prefix
  543. static char achprefsuf[] = "[^A-Za-z0-9_]";
  544. // Prefix/suffix
  545. static char achsuf[] = "$"; // Suffix
  546. char buffer[BUFLEN]; // Temporary buffer
  547. assert(n >= 2); // Must have at least two characters
  548. if(e[0] == '\\' && e[1] == '<') { // If begin token
  549. if(!(flags & BEGLINE)) { // If not matching at beginning only
  550. memcpy(buffer,achprefsuf,sizeof achprefsuf - 1);
  551. // Copy first prefix
  552. memcpy(buffer + sizeof achprefsuf - 1,e + 2,n - 2);
  553. // Attach expression
  554. addexpr(buffer,n + sizeof achprefsuf - 3);
  555. // Add expression
  556. }
  557. memcpy(buffer,achpref,sizeof achpref - 1);
  558. // Copy second prefix
  559. memcpy(buffer + sizeof achpref - 1,e + 2,n - 2);
  560. // Attach expression
  561. addexpr(buffer,n + sizeof achpref - 3);
  562. // Add expression
  563. return; // Done
  564. }
  565. assert(e[n-2] == '\\' && e[n - 1] == '>');
  566. // Must be end token
  567. if(!(flags & ENDLINE)) { // If not matching at end only
  568. memcpy(buffer,e,n - 2); // Copy expression
  569. memcpy(buffer + n - 2,achprefsuf,sizeof achprefsuf - 1);
  570. // Attach first suffix
  571. addexpr(buffer,n + sizeof achprefsuf - 3);
  572. // Add expression
  573. }
  574. memcpy(buffer,e,n - 2); // Copy expression
  575. memcpy(buffer + n - 2,achsuf,sizeof achsuf - 1);
  576. // Attach second suffix
  577. addexpr(buffer,n + sizeof achsuf - 3);
  578. // Add expression
  579. }
  580. void
  581. addexpr(
  582. char *e, // Expression to add
  583. int n // Length of expression
  584. )
  585. {
  586. EXPR *expr; // Expression node pointer
  587. int i; // Index
  588. int j; // Index
  589. int locflags; // Local copy of flags
  590. char bitvec[ASCLEN/8];
  591. // First char. bit vector
  592. char buffer[BUFLEN]; // Temporary buffer
  593. char tmp[2];
  594. if(find == findall)
  595. return; // Return if matching everything
  596. if(istoken((unsigned char *)e, n)) { // If expr is token
  597. addtoken(e,n); // Convert and add tokens
  598. return; // Done
  599. }
  600. tmp[1] = 0;
  601. locflags = flags; // Initialize local copy
  602. if(*e == '^') locflags |= BEGLINE; // Set flag if match must begin line
  603. j = -2; // Assume no escapes in string
  604. for(i = 0; i < n - 1; ++i) { // Loop to find last escape
  605. if(e[i] == '\\') j = i++; // Save index of last escape
  606. }
  607. if(n > 0 && e[n-1] == '$' && j != n-2) {
  608. // If expr. ends in unescaped '$'
  609. --n; // Skip dollar sign
  610. locflags |= ENDLINE; // Match must be at end
  611. }
  612. strncpy(buffer,e,n); // Copy pattern to buffer
  613. if(locflags & ENDLINE)
  614. buffer[n++] = EOS; // Add end character if needed
  615. buffer[n] = '\0'; // Null-terminate string
  616. if((e = (char *)exprparse((unsigned char *)buffer)) == NULL)
  617. return; // Return if invalid expression
  618. ++strcnt; // Increment string count
  619. if(!(locflags & BEGLINE)) { // If match needn't be at beginning
  620. e = get1stcharset((unsigned char *)e, bitvec); // Remove leading *-expr.s
  621. }
  622. // E now points to a buffer containing a preprocessed expression.
  623. // We need to find the set of allowable first characters and make
  624. // the appropriate entries in the string node table.
  625. if(*get1stcharset((unsigned char *)e, bitvec) == T_END) {
  626. // If expression will match anything
  627. find = findall; // Match everything
  628. return; // All done
  629. }
  630. for(j = 0; j < ASCLEN; ++j) { // Loop to examine bit vector
  631. if(bitvec[j >> 3] & (1 << (j & 7))) { // If the bit is set
  632. expr = (EXPR *) alloc(sizeof(EXPR)); // Allocate record
  633. expr->ex_pattern = (unsigned char *)e; // Point it at pattern
  634. if((i = (UCHAR)transtab[j]) == 0) { // If no existing list
  635. if((i = clists++) >= ASCLEN) { // If too many string lists
  636. printmessage(stderr,MSG_FINDSTR_TOO_MANY_STRING_LISTS,NULL);
  637. // Error message
  638. exit(2); // Die
  639. }
  640. stringlist[i] = NULL; // Initialize
  641. transtab[j] = (char) i; // Set pointer to new list
  642. if(!casesen && isalpha(j)) {
  643. tmp[0] = (char)j;
  644. if ((unsigned char)(_strlwr(tmp))[0] != (unsigned char)j ||
  645. (unsigned char)(_strupr(tmp))[0] != (unsigned char)j)
  646. transtab[(unsigned char)tmp[0]] = (char)i; // Set pointer for other case
  647. }
  648. }
  649. expr->ex_next = stringlist[i]; // Link new record into table
  650. stringlist[i] = expr;
  651. }
  652. }
  653. // if(locflags & DEBUG) exprprint(e,stderr);
  654. // Print the expression if debugging
  655. }
  656. char *
  657. findexpr(
  658. unsigned char *buffer, // Buffer in which to search
  659. char *bufend // End of buffer
  660. )
  661. {
  662. EXPR *expr; // Expression list pointer
  663. unsigned char *pattern; // Pattern
  664. int i; // Index
  665. unsigned char *bufbegin;
  666. int b;
  667. bufbegin = buffer;
  668. while(buffer < (unsigned char *)bufend) { // Loop to find match
  669. if((i = (UCHAR)transtab[*buffer++]) == 0)
  670. continue; // Continue if not valid 1st char
  671. if((expr = (EXPR *) stringlist[i]) == NULL) {
  672. // If null pointer
  673. assert(0);
  674. exit(2); // Die
  675. }
  676. --buffer; // Back up to first character
  677. while(expr != NULL) { // Loop to find match
  678. pattern = expr->ex_pattern; // Point to pattern
  679. expr = expr->ex_next; // Point to next record
  680. if(pattern[0] == '^') { // If match begin line
  681. ++pattern; // Skip caret
  682. if(buffer > bufbegin && buffer[-1] != '\n') continue;
  683. // Don't bother if not at beginning
  684. }
  685. __try {
  686. b = exprmatch((char *)buffer, (char *)pattern);
  687. } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) {
  688. b = 0;
  689. }
  690. if (b) {
  691. return((char *)buffer);
  692. }
  693. }
  694. ++buffer; // Skip first character
  695. }
  696. return(NULL); // No match
  697. }