|
|
1.1 root 1: /* regexp.c */
2:
3: /* This file contains the code that compiles regular expressions and executes
4: * them. It supports the same syntax and features as vi's regular expression
5: * code. Specifically, the meta characters are:
6: * ^ matches the beginning of a line
7: * $ matches the end of a line
8: * \< matches the beginning of a word
9: * \> matches the end of a word
10: * . matches any single character
11: * [] matches any character in a character class
12: * \( delimits the start of a subexpression
13: * \) delimits the end of a subexpression
14: * * repeats the preceding 0 or more times
15: * NOTE: You cannot follow a \) with a *.
16: *
17: * The physical structure of a compiled RE is as follows:
18: * - First, there is a one-byte value that says how many character classes
19: * are used in this regular expression
20: * - Next, each character class is stored as a bitmap that is 256 bits
21: * (32 bytes) long.
22: * - A mixture of literal characters and compiled meta characters follows.
23: * This begins with M_BEGIN(0) and ends with M_END(0). All meta chars
24: * are stored as a \n followed by a one-byte code, so they take up two
25: * bytes apiece. Literal characters take up one byte apiece. \n can't
26: * be used as a literal character.
27: *
28: * If NO_MAGIC is defined, then a different set of functions is used instead.
29: * That right, this file contains TWO versions of the code.
30: */
31:
32: #include <setjmp.h>
33: #include <ctype.h>
34: #include "config.h"
35: #include "vi.h"
36: #include "regexp.h"
37:
38:
39:
40: static char *previous; /* the previous regexp, used when null regexp is given */
41:
42:
43: #ifndef NO_MAGIC
44: /* THE REAL REGEXP PACKAGE IS USED UNLESS "NO_MAGIC" IS DEFINED */
45:
46: /* These are used to classify or recognize meta-characters */
47: #define META '\0'
48: #define BASE_META(m) ((m) - 256)
49: #define INT_META(c) ((c) + 256)
50: #define IS_META(m) ((m) >= 256)
51: #define IS_CLASS(m) ((m) >= M_CLASS(0) && (m) <= M_CLASS(9))
52: #define IS_START(m) ((m) >= M_START(0) && (m) <= M_START(9))
53: #define IS_END(m) ((m) >= M_END(0) && (m) <= M_END(9))
54: #define IS_CLOSURE(m) ((m) >= M_SPLAT && (m) <= M_QMARK)
55: #define ADD_META(s,m) (*(s)++ = META, *(s)++ = BASE_META(m))
56: #define GET_META(s) (*(s) == META ? INT_META(*++(s)) : *s)
57:
58: /* These are the internal codes used for each type of meta-character */
59: #define M_BEGLINE 256 /* internal code for ^ */
60: #define M_ENDLINE 257 /* internal code for $ */
61: #define M_BEGWORD 258 /* internal code for \< */
62: #define M_ENDWORD 259 /* internal code for \> */
63: #define M_ANY 260 /* internal code for . */
64: #define M_SPLAT 261 /* internal code for * */
65: #define M_PLUS 262 /* internal code for \+ */
66: #define M_QMARK 263 /* internal code for \? */
67: #define M_CLASS(n) (264+(n)) /* internal code for [] */
68: #define M_START(n) (274+(n)) /* internal code for \( */
69: #define M_END(n) (284+(n)) /* internal code for \) */
70:
71: /* These are used during compilation */
72: static int class_cnt; /* used to assign class IDs */
73: static int start_cnt; /* used to assign start IDs */
74: static int end_stk[NSUBEXP];/* used to assign end IDs */
75: static int end_sp;
76: static char *retext; /* points to the text being compiled */
77:
78: /* error-handling stuff */
79: jmp_buf errorhandler;
80: #define FAIL(why) regerror(why); longjmp(errorhandler, 1)
81:
82:
83:
84:
85:
86: /* This function builds a bitmap for a particular class */
87: static char *makeclass(text, bmap)
88: REG char *text; /* start of the class */
89: REG char *bmap; /* the bitmap */
90: {
91: REG int i;
92: int complement = 0;
93:
94: # if TRACE
95: printf("makeclass(\"%s\", 0x%lx)\n", text, (long)bmap);
96: # endif
97:
98: /* zero the bitmap */
99: for (i = 0; bmap && i < 32; i++)
100: {
101: bmap[i] = 0;
102: }
103:
104: /* see if we're going to complement this class */
105: if (*text == '^')
106: {
107: text++;
108: complement = 1;
109: }
110:
111: /* add in the characters */
112: while (*text && *text != ']')
113: {
114: /* is this a span of characters? */
115: if (text[1] == '-' && text[2])
116: {
117: /* spans can't be backwards */
118: if (text[0] > text[2])
119: {
120: FAIL("Backwards span in []");
121: }
122:
123: /* add each character in the span to the bitmap */
124: for (i = text[0]; bmap && i <= text[2]; i++)
125: {
126: bmap[i >> 3] |= (1 << (i & 7));
127: }
128:
129: /* move past this span */
130: text += 3;
131: }
132: else
133: {
134: /* add this single character to the span */
135: i = *text++;
136: if (bmap)
137: {
138: bmap[i >> 3] |= (1 << (i & 7));
139: }
140: }
141: }
142:
143: /* make sure the closing ] is missing */
144: if (*text++ != ']')
145: {
146: FAIL("] missing");
147: }
148:
149: /* if we're supposed to complement this class, then do so */
150: if (complement && bmap)
151: {
152: for (i = 0; i < 32; i++)
153: {
154: bmap[i] = ~bmap[i];
155: }
156: }
157:
158: return text;
159: }
160:
161:
162:
163:
164: /* This function gets the next character or meta character from a string.
165: * The pointer is incremented by 1, or by 2 for \-quoted characters. For [],
166: * a bitmap is generated via makeclass() (if re is given), and the
167: * character-class text is skipped.
168: */
169: static int gettoken(sptr, re)
170: char **sptr;
171: regexp *re;
172: {
173: int c;
174:
175: c = **sptr;
176: ++*sptr;
177: if (c == '\\')
178: {
179: c = **sptr;
180: ++*sptr;
181: switch (c)
182: {
183: case '<':
184: return M_BEGWORD;
185:
186: case '>':
187: return M_ENDWORD;
188:
189: case '(':
190: if (start_cnt >= NSUBEXP)
191: {
192: FAIL("Too many \\(s");
193: }
194: end_stk[end_sp++] = start_cnt;
195: return M_START(start_cnt++);
196:
197: case ')':
198: if (end_sp <= 0)
199: {
200: FAIL("Mismatched \\)");
201: }
202: return M_END(end_stk[--end_sp]);
203:
204: case '*':
205: return (*o_magic ? c : M_SPLAT);
206:
207: case '.':
208: return (*o_magic ? c : M_ANY);
209:
210: case '+':
211: return M_PLUS;
212:
213: case '?':
214: return M_QMARK;
215:
216: default:
217: return c;
218: }
219: }
220: else if (*o_magic)
221: {
222: switch (c)
223: {
224: case '^':
225: if (*sptr == retext + 1)
226: {
227: return M_BEGLINE;
228: }
229: return c;
230:
231: case '$':
232: if (!**sptr)
233: {
234: return M_ENDLINE;
235: }
236: return c;
237:
238: case '.':
239: return M_ANY;
240:
241: case '*':
242: return M_SPLAT;
243:
244: case '[':
245: /* make sure we don't have too many classes */
246: if (class_cnt >= 10)
247: {
248: FAIL("Too many []s");
249: }
250:
251: /* process the character list for this class */
252: if (re)
253: {
254: /* generate the bitmap for this class */
255: *sptr = makeclass(*sptr, re->program + 1 + 32 * class_cnt);
256: }
257: else
258: {
259: /* skip to end of the class */
260: *sptr = makeclass(*sptr, (char *)0);
261: }
262: return M_CLASS(class_cnt++);
263:
264: default:
265: return c;
266: }
267: }
268: else /* unquoted nomagic */
269: {
270: switch (c)
271: {
272: case '^':
273: if (*sptr == retext + 1)
274: {
275: return M_BEGLINE;
276: }
277: return c;
278:
279: case '$':
280: if (!**sptr)
281: {
282: return M_ENDLINE;
283: }
284: return c;
285:
286: default:
287: return c;
288: }
289: }
290: /*NOTREACHED*/
291: }
292:
293:
294:
295:
296: /* This function calculates the number of bytes that will be needed for a
297: * compiled RE. Its argument is the uncompiled version. It is not clever
298: * about catching syntax errors; that is done in a later pass.
299: */
300: static unsigned calcsize(text)
301: char *text;
302: {
303: unsigned size;
304: int token;
305:
306: retext = text;
307: class_cnt = 0;
308: start_cnt = 1;
309: end_sp = 0;
310: size = 5;
311: while ((token = gettoken(&text, (regexp *)0)) != 0)
312: {
313: if (IS_CLASS(token))
314: {
315: size += 34;
316: }
317: else if (IS_META(token))
318: {
319: size += 2;
320: }
321: else
322: {
323: size++;
324: }
325: }
326:
327: return size;
328: }
329:
330:
331:
332: /* This function compiles a regexp. */
333: regexp *regcomp(text)
334: char *text;
335: {
336: int needfirst;
337: unsigned size;
338: int token;
339: int peek;
340: char *build;
341: regexp *re;
342:
343:
344: /* prepare for error handling */
345: re = (regexp *)0;
346: if (setjmp(errorhandler))
347: {
348: if (re)
349: {
350: free(re);
351: }
352: return (regexp *)0;
353: }
354:
355: /* if an empty regexp string was given, use the previous one */
356: if (*text == 0)
357: {
358: if (!previous)
359: {
360: FAIL("No previous RE");
361: }
362: text = previous;
363: }
364: else /* non-empty regexp given, so remember it */
365: {
366: if (previous)
367: free(previous);
368: previous = (char *)malloc((unsigned)(strlen(text) + 1));
369: if (previous)
370: strcpy(previous, text);
371: }
372:
373: /* allocate memory */
374: class_cnt = 0;
375: start_cnt = 1;
376: end_sp = 0;
377: retext = text;
378: size = calcsize(text) + sizeof(regexp);
379: #ifdef lint
380: re = ((regexp *)0) + size;
381: #else
382: re = (regexp *)malloc((unsigned)size);
383: #endif
384: if (!re)
385: {
386: FAIL("Not enough memory for this RE");
387: }
388:
389: /* compile it */
390: build = &re->program[1 + 32 * class_cnt];
391: re->program[0] = class_cnt;
392: for (token = 0; token < NSUBEXP; token++)
393: {
394: re->startp[token] = re->endp[token] = (char *)0;
395: }
396: re->first = 0;
397: re->bol = 0;
398: re->minlen = 0;
399: needfirst = 1;
400: class_cnt = 0;
401: start_cnt = 1;
402: end_sp = 0;
403: retext = text;
404: for (token = M_START(0), peek = gettoken(&text, re);
405: token;
406: token = peek, peek = gettoken(&text, re))
407: {
408: /* special processing for the closure operator */
409: if (IS_CLOSURE(peek))
410: {
411: /* detect misuse of closure operator */
412: if (IS_START(token))
413: {
414: FAIL("* or \\+ or \\? follows nothing");
415: }
416: else if (IS_META(token) && token != M_ANY && !IS_CLASS(token))
417: {
418: FAIL("* or \\+ or \\? can only follow a normal character or . or []");
419: }
420:
421: /* it is okay -- make it prefix instead of postfix */
422: ADD_META(build, peek);
423:
424: /* take care of "needfirst" - is this the first char? */
425: if (needfirst && peek == M_PLUS && !IS_META(token))
426: {
427: re->first = token;
428: }
429: needfirst = 0;
430:
431: /* we used "peek" -- need to refill it */
432: peek = gettoken(&text, re);
433: if (IS_CLOSURE(peek))
434: {
435: FAIL("* or \\+ or \\? doubled up");
436: }
437: }
438: else if (!IS_META(token))
439: {
440: /* normal char is NOT argument of closure */
441: if (needfirst)
442: {
443: re->first = token;
444: needfirst = 0;
445: }
446: re->minlen++;
447: }
448: else if (token == M_ANY || IS_CLASS(token))
449: {
450: /* . or [] is NOT argument of closure */
451: needfirst = 0;
452: re->minlen++;
453: }
454:
455: /* the "token" character is not closure -- process it normally */
456: if (token == M_BEGLINE)
457: {
458: /* set the BOL flag instead of storing M_BEGLINE */
459: re->bol = 1;
460: }
461: else if (IS_META(token))
462: {
463: ADD_META(build, token);
464: }
465: else
466: {
467: *build++ = token;
468: }
469: }
470:
471: /* end it with a \) which MUST MATCH the opening \( */
472: ADD_META(build, M_END(0));
473: if (end_sp > 0)
474: {
475: FAIL("Not enough \\)s");
476: }
477:
478: return re;
479: }
480:
481:
482:
483: /*---------------------------------------------------------------------------*/
484:
485:
486: /* This function checks for a match between a character and a token which is
487: * known to represent a single character. It returns 0 if they match, or
488: * 1 if they don't.
489: */
490: int match1(re, ch, token)
491: regexp *re;
492: REG char ch;
493: REG int token;
494: {
495: if (!ch)
496: {
497: /* the end of a line can't match any RE of width 1 */
498: return 1;
499: }
500: if (token == M_ANY)
501: {
502: return 0;
503: }
504: else if (IS_CLASS(token))
505: {
506: if (re->program[1 + 32 * (token - M_CLASS(0)) + (ch >> 3)] & (1 << (ch & 7)))
507: return 0;
508: }
509: else if (ch == token
510: || (*o_ignorecase && isupper(ch) && tolower(ch) == token))
511: {
512: return 0;
513: }
514: return 1;
515: }
516:
517:
518:
519: /* This function checks characters up to and including the next closure, at
520: * which point it does a recursive call to check the rest of it. This function
521: * returns 0 if everything matches, or 1 if something doesn't match.
522: */
523: int match(re, str, prog, here)
524: regexp *re; /* the regular expression */
525: char *str; /* the string */
526: REG char *prog; /* a portion of re->program, an compiled RE */
527: REG char *here; /* a portion of str, the string to compare it to */
528: {
529: REG int token;
530: REG int nmatched;
531: REG int closure;
532:
533: for (token = GET_META(prog); !IS_CLOSURE(token); prog++, token = GET_META(prog))
534: {
535: switch (token)
536: {
537: /*case M_BEGLINE: can't happen; re->bol is used instead */
538: case M_ENDLINE:
539: if (*here)
540: return 1;
541: break;
542:
543: case M_BEGWORD:
544: if (here != str &&
545: (here[-1] == '_' ||
546: isascii(here[-1]) && isalnum(here[-1])))
547: return 1;
548: break;
549:
550: case M_ENDWORD:
551: if (here[0] == '_' || isascii(here[0]) && isalnum(here[0]))
552: return 1;
553: break;
554:
555: case M_START(0):
556: case M_START(1):
557: case M_START(2):
558: case M_START(3):
559: case M_START(4):
560: case M_START(5):
561: case M_START(6):
562: case M_START(7):
563: case M_START(8):
564: case M_START(9):
565: re->startp[token - M_START(0)] = (char *)here;
566: break;
567:
568: case M_END(0):
569: case M_END(1):
570: case M_END(2):
571: case M_END(3):
572: case M_END(4):
573: case M_END(5):
574: case M_END(6):
575: case M_END(7):
576: case M_END(8):
577: case M_END(9):
578: re->endp[token - M_END(0)] = (char *)here;
579: if (token == M_END(0))
580: {
581: return 0;
582: }
583: break;
584:
585: default: /* literal, M_CLASS(n), or M_ANY */
586: if (match1(re, *here, token) != 0)
587: return 1;
588: here++;
589: }
590: }
591:
592: /* C L O S U R E */
593:
594: /* step 1: see what we have to match against, and move "prog" to point
595: * the the remainder of the compiled RE.
596: */
597: closure = token;
598: prog++, token = GET_META(prog);
599: prog++;
600:
601: /* step 2: see how many times we can match that token against the string */
602: for (nmatched = 0;
603: (closure != M_QMARK || nmatched < 1) && *here && match1(re, *here, token) == 0;
604: nmatched++, here++)
605: {
606: }
607:
608: /* step 3: try to match the remainder, and back off if it doesn't */
609: while (nmatched >= 0 && match(re, str, prog, here) != 0)
610: {
611: nmatched--;
612: here--;
613: }
614:
615: /* so how did it work out? */
616: if (nmatched >= ((closure == M_PLUS) ? 1 : 0))
617: return 0;
618: return 1;
619: }
620:
621:
622:
623: /* This function searches through a string for text that matches an RE. */
624: int regexec(re, str, bol)
625: regexp *re; /* the compiled regexp to search for */
626: char *str; /* the string to search through */
627: int bol; /* boolean: does str start at the beginning of a line? */
628: {
629: char *prog; /* the entry point of re->program */
630: int len; /* length of the string */
631: REG char *here;
632:
633: /* if must start at the beginning of a line, and this isn't, then fail */
634: if (re->bol && !bol)
635: {
636: return 0;
637: }
638:
639: len = strlen(str);
640: prog = re->program + 1 + 32 * re->program[0];
641:
642: /* search for the RE in the string */
643: if (re->bol)
644: {
645: /* must occur at BOL */
646: if ((re->first
647: && match1(re, *(char *)str, re->first))/* wrong first letter? */
648: || len < re->minlen /* not long enough? */
649: || match(re, (char *)str, prog, str)) /* doesn't match? */
650: return 0; /* THEN FAIL! */
651: }
652: #ifndef CRUNCH
653: else if (!*o_ignorecase)
654: {
655: /* can occur anywhere in the line, noignorecase */
656: for (here = (char *)str;
657: (re->first && re->first != *here)
658: || match(re, (char *)str, prog, here);
659: here++, len--)
660: {
661: if (len < re->minlen)
662: return 0;
663: }
664: }
665: #endif
666: else
667: {
668: /* can occur anywhere in the line, ignorecase */
669: for (here = (char *)str;
670: (re->first && match1(re, *here, (int)re->first))
671: || match(re, (char *)str, prog, here);
672: here++, len--)
673: {
674: if (len < re->minlen)
675: return 0;
676: }
677: }
678:
679: /* if we didn't fail, then we must have succeeded */
680: return 1;
681: }
682:
683: #else /* NO_MAGIC */
684:
685: regexp *regcomp(exp)
686: char *exp;
687: {
688: char *src;
689: char *dest;
690: regexp *re;
691: int i;
692:
693: /* allocate a big enough regexp structure */
694: #ifdef lint
695: re = (regexp *)0;
696: #else
697: re = (regexp *)malloc((unsigned)(strlen(exp) + 1 + sizeof(struct regexp)));
698: #endif
699: if (!re)
700: {
701: regerror("Could not malloc a regexp structure");
702: return (regexp *)0;
703: }
704:
705: /* initialize all fields of the structure */
706: for (i = 0; i < NSUBEXP; i++)
707: {
708: re->startp[i] = re->endp[i] = (char *)0;
709: }
710: re->minlen = 0;
711: re->first = 0;
712: re->bol = 0;
713:
714: /* copy the string into it, translating ^ and $ as needed */
715: for (src = exp, dest = re->program + 1; *src; src++)
716: {
717: switch (*src)
718: {
719: case '^':
720: if (src == exp)
721: {
722: re->bol += 1;
723: }
724: else
725: {
726: *dest++ = '^';
727: re->minlen++;
728: }
729: break;
730:
731: case '$':
732: if (!src[1])
733: {
734: re->bol += 2;
735: }
736: else
737: {
738: *dest++ = '$';
739: re->minlen++;
740: }
741: break;
742:
743: case '\\':
744: if (src[1])
745: {
746: *dest++ = *++src;
747: re->minlen++;
748: }
749: else
750: {
751: regerror("extra \\ at end of regular expression");
752: }
753: break;
754:
755: default:
756: *dest++ = *src;
757: re->minlen++;
758: }
759: }
760: *dest = '\0';
761:
762: return re;
763: }
764:
765:
766: /* This "helper" function checks for a match at a given location. It returns
767: * 1 if it matches, 0 if it doesn't match here but might match later on in the
768: * string, or -1 if it could not possibly match
769: */
770: static int reghelp(prog, string, bolflag)
771: struct regexp *prog;
772: char *string;
773: int bolflag;
774: {
775: char *scan;
776: char *str;
777:
778: /* if ^, then require bolflag */
779: if ((prog->bol & 1) && !bolflag)
780: {
781: return -1;
782: }
783:
784: /* if it matches, then it will start here */
785: prog->startp[0] = string;
786:
787: /* compare, possibly ignoring case */
788: if (*o_ignorecase)
789: {
790: for (scan = &prog->program[1]; *scan; scan++, string++)
791: if (tolower(*scan) != tolower(*string))
792: return *string ? 0 : -1;
793: }
794: else
795: {
796: for (scan = &prog->program[1]; *scan; scan++, string++)
797: if (*scan != *string)
798: return *string ? 0 : -1;
799: }
800:
801: /* if $, then require string to end here, too */
802: if ((prog->bol & 2) && *string)
803: {
804: return 0;
805: }
806:
807: /* if we get to here, it matches */
808: prog->endp[0] = string;
809: return 1;
810: }
811:
812:
813:
814: int regexec(prog, string, bolflag)
815: struct regexp *prog;
816: char *string;
817: int bolflag;
818: {
819: int rc;
820:
821: /* keep trying to match it */
822: for (rc = reghelp(prog, string, bolflag); rc == 0; rc = reghelp(prog, string, 0))
823: {
824: string++;
825: }
826:
827: /* did we match? */
828: return rc == 1;
829: }
830: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.