unstack, sort: cleanup and improvement
[minix.git] / commands / elvis / regexp.c
blob91db71af854bdec50f6110f3867bdf670374613d
1 /* regexp.c */
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 *.
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.
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.
32 #include <setjmp.h>
33 #include "config.h"
34 #include "ctype.h"
35 #include "vi.h"
36 #include "regexp.h"
40 static char *previous; /* the previous regexp, used when null regexp is given */
43 #ifndef NO_MAGIC
44 /* THE REAL REGEXP PACKAGE IS USED UNLESS "NO_MAGIC" IS DEFINED */
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_RANGE)
55 #define ADD_META(s,m) (*(s)++ = META, *(s)++ = BASE_META(m))
56 #define GET_META(s) (*(s) == META ? INT_META(*++(s)) : *s)
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_RANGE 264 /* internal code for \{ */
68 #define M_CLASS(n) (265+(n)) /* internal code for [] */
69 #define M_START(n) (275+(n)) /* internal code for \( */
70 #define M_END(n) (285+(n)) /* internal code for \) */
72 /* These are used during compilation */
73 static int class_cnt; /* used to assign class IDs */
74 static int start_cnt; /* used to assign start IDs */
75 static int end_stk[NSUBEXP];/* used to assign end IDs */
76 static int end_sp;
77 static char *retext; /* points to the text being compiled */
79 /* error-handling stuff */
80 jmp_buf errorhandler;
81 #define FAIL(why) regerror(why); longjmp(errorhandler, 1)
87 /* This function builds a bitmap for a particular class */
88 static char *makeclass(text, bmap)
89 REG char *text; /* start of the class */
90 REG char *bmap; /* the bitmap */
92 REG int i;
93 int complement = 0;
96 /* zero the bitmap */
97 for (i = 0; bmap && i < 32; i++)
99 bmap[i] = 0;
102 /* see if we're going to complement this class */
103 if (*text == '^')
105 text++;
106 complement = 1;
109 /* add in the characters */
110 while (*text && *text != ']')
112 /* is this a span of characters? */
113 if (text[1] == '-' && text[2])
115 /* spans can't be backwards */
116 if (text[0] > text[2])
118 FAIL("Backwards span in []");
121 /* add each character in the span to the bitmap */
122 for (i = text[0]; bmap && i <= text[2]; i++)
124 bmap[i >> 3] |= (1 << (i & 7));
127 /* move past this span */
128 text += 3;
130 else
132 /* add this single character to the span */
133 i = *text++;
134 if (bmap)
136 bmap[i >> 3] |= (1 << (i & 7));
141 /* make sure the closing ] is missing */
142 if (*text++ != ']')
144 FAIL("] missing");
147 /* if we're supposed to complement this class, then do so */
148 if (complement && bmap)
150 for (i = 0; i < 32; i++)
152 bmap[i] = ~bmap[i];
156 return text;
162 /* This function gets the next character or meta character from a string.
163 * The pointer is incremented by 1, or by 2 for \-quoted characters. For [],
164 * a bitmap is generated via makeclass() (if re is given), and the
165 * character-class text is skipped.
167 static int gettoken(sptr, re)
168 char **sptr;
169 regexp *re;
171 int c;
173 c = **sptr;
174 ++*sptr;
175 if (c == '\\')
177 c = **sptr;
178 ++*sptr;
179 switch (c)
181 case '<':
182 return M_BEGWORD;
184 case '>':
185 return M_ENDWORD;
187 case '(':
188 if (start_cnt >= NSUBEXP)
190 FAIL("Too many \\(s");
192 end_stk[end_sp++] = start_cnt;
193 return M_START(start_cnt++);
195 case ')':
196 if (end_sp <= 0)
198 FAIL("Mismatched \\)");
200 return M_END(end_stk[--end_sp]);
202 case '*':
203 return (*o_magic ? c : M_SPLAT);
205 case '.':
206 return (*o_magic ? c : M_ANY);
208 case '+':
209 return M_PLUS;
211 case '?':
212 return M_QMARK;
213 #ifndef CRUNCH
214 case '{':
215 return M_RANGE;
216 #endif
217 default:
218 return c;
221 else if (*o_magic)
223 switch (c)
225 case '^':
226 if (*sptr == retext + 1)
228 return M_BEGLINE;
230 return c;
232 case '$':
233 if (!**sptr)
235 return M_ENDLINE;
237 return c;
239 case '.':
240 return M_ANY;
242 case '*':
243 return M_SPLAT;
245 case '[':
246 /* make sure we don't have too many classes */
247 if (class_cnt >= 10)
249 FAIL("Too many []s");
252 /* process the character list for this class */
253 if (re)
255 /* generate the bitmap for this class */
256 *sptr = makeclass(*sptr, re->program + 1 + 32 * class_cnt);
258 else
260 /* skip to end of the class */
261 *sptr = makeclass(*sptr, (char *)0);
263 return M_CLASS(class_cnt++);
265 default:
266 return c;
269 else /* unquoted nomagic */
271 switch (c)
273 case '^':
274 if (*sptr == retext + 1)
276 return M_BEGLINE;
278 return c;
280 case '$':
281 if (!**sptr)
283 return M_ENDLINE;
285 return c;
287 default:
288 return c;
291 /*NOTREACHED*/
297 /* This function calculates the number of bytes that will be needed for a
298 * compiled RE. Its argument is the uncompiled version. It is not clever
299 * about catching syntax errors; that is done in a later pass.
301 static unsigned calcsize(text)
302 char *text;
304 unsigned size;
305 int token;
307 retext = text;
308 class_cnt = 0;
309 start_cnt = 1;
310 end_sp = 0;
311 size = 5;
312 while ((token = gettoken(&text, (regexp *)0)) != 0)
314 if (IS_CLASS(token))
316 size += 34;
318 #ifndef CRUNCH
319 else if (token == M_RANGE)
321 size += 4;
322 while ((token = gettoken(&text, (regexp *)0)) != 0
323 && token != '}')
326 if (!token)
328 return size;
331 #endif
332 else if (IS_META(token))
334 size += 2;
336 else
338 size++;
342 return size;
347 /* This function compiles a regexp. */
348 regexp *regcomp(exp)
349 char *exp;
351 int needfirst;
352 unsigned size;
353 int token;
354 int peek;
355 char *build;
356 regexp *re;
357 #ifndef CRUNCH
358 int from;
359 int to;
360 int digit;
361 #endif
364 /* prepare for error handling */
365 re = (regexp *)0;
366 if (setjmp(errorhandler))
368 if (re)
370 free(re);
372 return (regexp *)0;
375 /* if an empty regexp string was given, use the previous one */
376 if (*exp == 0)
378 if (!previous)
380 FAIL("No previous RE");
382 exp = previous;
384 else /* non-empty regexp given, so remember it */
386 if (previous)
387 free(previous);
388 previous = (char *)malloc((unsigned)(strlen(exp) + 1));
389 if (previous)
390 strcpy(previous, exp);
393 /* allocate memory */
394 class_cnt = 0;
395 start_cnt = 1;
396 end_sp = 0;
397 retext = exp;
398 size = calcsize(exp) + sizeof(regexp) + 10; /* !!! 10 bytes for slop */
399 #ifdef lint
400 re = ((regexp *)0) + size;
401 #else
402 re = (regexp *)malloc((unsigned)size);
403 #endif
404 if (!re)
406 FAIL("Not enough memory for this RE");
409 /* compile it */
410 build = &re->program[1 + 32 * class_cnt];
411 re->program[0] = class_cnt;
412 for (token = 0; token < NSUBEXP; token++)
414 re->startp[token] = re->endp[token] = (char *)0;
416 re->first = 0;
417 re->bol = 0;
418 re->minlen = 0;
419 needfirst = 1;
420 class_cnt = 0;
421 start_cnt = 1;
422 end_sp = 0;
423 retext = exp;
424 for (token = M_START(0), peek = gettoken(&exp, re);
425 token;
426 token = peek, peek = gettoken(&exp, re))
428 /* special processing for the closure operator */
429 if (IS_CLOSURE(peek))
431 /* detect misuse of closure operator */
432 if (IS_START(token))
434 FAIL("Closure operator follows nothing");
436 else if (IS_META(token) && token != M_ANY && !IS_CLASS(token))
438 FAIL("Closure operators can only follow a normal character or . or []");
441 #ifndef CRUNCH
442 /* if \{ \} then read the range */
443 if (peek == M_RANGE)
445 from = 0;
446 for (digit = gettoken(&exp, re);
447 !IS_META(digit) && isdigit(digit);
448 digit = gettoken(&exp, re))
450 from = from * 10 + digit - '0';
452 if (digit == '}')
454 to = from;
456 else if (digit == ',')
458 to = 0;
459 for (digit = gettoken(&exp, re);
460 !IS_META(digit) && isdigit(digit);
461 digit = gettoken(&exp, re))
463 to = to * 10 + digit - '0';
465 if (to == 0)
467 to = 255;
470 if (digit != '}')
472 FAIL("Bad characters after \\{");
474 else if (to < from || to == 0 || from >= 255)
476 FAIL("Invalid range for \\{ \\}");
478 re->minlen += from;
480 else
481 #endif
482 if (peek != M_SPLAT)
484 re->minlen++;
487 /* it is okay -- make it prefix instead of postfix */
488 ADD_META(build, peek);
489 #ifndef CRUNCH
490 if (peek == M_RANGE)
492 *build++ = from;
493 *build++ = (to < 255 ? to : 255);
495 #endif
498 /* take care of "needfirst" - is this the first char? */
499 if (needfirst && peek == M_PLUS && !IS_META(token))
501 re->first = token;
503 needfirst = 0;
505 /* we used "peek" -- need to refill it */
506 peek = gettoken(&exp, re);
507 if (IS_CLOSURE(peek))
509 FAIL("* or \\+ or \\? doubled up");
512 else if (!IS_META(token))
514 /* normal char is NOT argument of closure */
515 if (needfirst)
517 re->first = token;
518 needfirst = 0;
520 re->minlen++;
522 else if (token == M_ANY || IS_CLASS(token))
524 /* . or [] is NOT argument of closure */
525 needfirst = 0;
526 re->minlen++;
529 /* the "token" character is not closure -- process it normally */
530 if (token == M_BEGLINE)
532 /* set the BOL flag instead of storing M_BEGLINE */
533 re->bol = 1;
535 else if (IS_META(token))
537 ADD_META(build, token);
539 else
541 *build++ = token;
545 /* end it with a \) which MUST MATCH the opening \( */
546 ADD_META(build, M_END(0));
547 if (end_sp > 0)
549 FAIL("Not enough \\)s");
552 return re;
557 /*---------------------------------------------------------------------------*/
560 /* This function checks for a match between a character and a token which is
561 * known to represent a single character. It returns 0 if they match, or
562 * 1 if they don't.
564 int match1(re, ch, token)
565 regexp *re;
566 REG char ch;
567 REG int token;
569 if (!ch)
571 /* the end of a line can't match any RE of width 1 */
572 return 1;
574 if (token == M_ANY)
576 return 0;
578 else if (IS_CLASS(token))
580 if (re->program[1 + 32 * (token - M_CLASS(0)) + (ch >> 3)] & (1 << (ch & 7)))
581 return 0;
583 else if (ch == token || *o_ignorecase && tolower(ch) == tolower(token))
585 return 0;
587 return 1;
592 /* This function checks characters up to and including the next closure, at
593 * which point it does a recursive call to check the rest of it. This function
594 * returns 0 if everything matches, or 1 if something doesn't match.
596 int match(re, str, prog, here)
597 regexp *re; /* the regular expression */
598 char *str; /* the string */
599 REG char *prog; /* a portion of re->program, an compiled RE */
600 REG char *here; /* a portion of str, the string to compare it to */
602 REG int token; /* the roken pointed to by prog */
603 REG int nmatched;/* counter, used during closure matching */
604 REG int closure;/* the token denoting the type of closure */
605 int from; /* minimum number of matches in closure */
606 int to; /* maximum number of matches in closure */
608 for (token = GET_META(prog); !IS_CLOSURE(token); prog++, token = GET_META(prog))
610 switch (token)
612 /*case M_BEGLINE: can't happen; re->bol is used instead */
613 case M_ENDLINE:
614 if (*here)
615 return 1;
616 break;
618 case M_BEGWORD:
619 if (here != str &&
620 (here[-1] == '_' || isalnum(here[-1])))
621 return 1;
622 break;
624 case M_ENDWORD:
625 if (here[0] == '_' || isalnum(here[0]))
626 return 1;
627 break;
629 case M_START(0):
630 case M_START(1):
631 case M_START(2):
632 case M_START(3):
633 case M_START(4):
634 case M_START(5):
635 case M_START(6):
636 case M_START(7):
637 case M_START(8):
638 case M_START(9):
639 re->startp[token - M_START(0)] = (char *)here;
640 break;
642 case M_END(0):
643 case M_END(1):
644 case M_END(2):
645 case M_END(3):
646 case M_END(4):
647 case M_END(5):
648 case M_END(6):
649 case M_END(7):
650 case M_END(8):
651 case M_END(9):
652 re->endp[token - M_END(0)] = (char *)here;
653 if (token == M_END(0))
655 return 0;
657 break;
659 default: /* literal, M_CLASS(n), or M_ANY */
660 if (match1(re, *here, token) != 0)
661 return 1;
662 here++;
666 /* C L O S U R E */
668 /* step 1: see what we have to match against, and move "prog" to point
669 * to the remainder of the compiled RE.
671 closure = token;
672 prog++;
673 switch (closure)
675 case M_SPLAT:
676 from = 0;
677 to = strlen(str); /* infinity */
678 break;
680 case M_PLUS:
681 from = 1;
682 to = strlen(str); /* infinity */
683 break;
685 case M_QMARK:
686 from = 0;
687 to = 1;
688 break;
690 #ifndef CRUNCH
691 case M_RANGE:
692 from = UCHAR(*prog++);
693 to = UCHAR(*prog++);
694 if (to == 255)
696 to = strlen(str); /* infinity */
698 break;
699 #endif
701 token = GET_META(prog);
702 prog++;
704 /* step 2: see how many times we can match that token against the string */
705 for (nmatched = 0;
706 nmatched < to && *here && match1(re, *here, token) == 0;
707 nmatched++, here++)
711 /* step 3: try to match the remainder, and back off if it doesn't */
712 while (nmatched >= from && match(re, str, prog, here) != 0)
714 nmatched--;
715 here--;
718 /* so how did it work out? */
719 if (nmatched >= from)
720 return 0;
721 return 1;
726 /* This function searches through a string for text that matches an RE. */
727 int regexec(re, str, bol)
728 regexp *re; /* the compiled regexp to search for */
729 char *str; /* the string to search through */
730 int bol; /* boolean: does str start at the beginning of a line? */
732 char *prog; /* the entry point of re->program */
733 int len; /* length of the string */
734 REG char *here;
736 /* if must start at the beginning of a line, and this isn't, then fail */
737 if (re->bol && !bol)
739 return 0;
742 len = strlen(str);
743 prog = re->program + 1 + 32 * re->program[0];
745 /* search for the RE in the string */
746 if (re->bol)
748 /* must occur at BOL */
749 if ((re->first
750 && match1(re, *(char *)str, re->first))/* wrong first letter? */
751 || len < re->minlen /* not long enough? */
752 || match(re, (char *)str, prog, str)) /* doesn't match? */
753 return 0; /* THEN FAIL! */
755 #ifndef CRUNCH
756 else if (!*o_ignorecase)
758 /* can occur anywhere in the line, noignorecase */
759 for (here = (char *)str;
760 (re->first && re->first != *here)
761 || match(re, (char *)str, prog, here);
762 here++, len--)
764 if (len < re->minlen)
765 return 0;
768 #endif
769 else
771 /* can occur anywhere in the line, ignorecase */
772 for (here = (char *)str;
773 (re->first && match1(re, *here, (int)re->first))
774 || match(re, (char *)str, prog, here);
775 here++, len--)
777 if (len < re->minlen)
778 return 0;
782 /* if we didn't fail, then we must have succeeded */
783 return 1;
786 /*============================================================================*/
787 #else /* NO_MAGIC */
789 regexp *regcomp(exp)
790 char *exp;
792 char *src;
793 char *dest;
794 regexp *re;
795 int i;
797 /* allocate a big enough regexp structure */
798 #ifdef lint
799 re = (regexp *)0;
800 #else
801 re = (regexp *)malloc((unsigned)(strlen(exp) + 1 + sizeof(struct regexp)));
802 #endif
803 if (!re)
805 regerror("Could not malloc a regexp structure");
806 return (regexp *)0;
809 /* initialize all fields of the structure */
810 for (i = 0; i < NSUBEXP; i++)
812 re->startp[i] = re->endp[i] = (char *)0;
814 re->minlen = 0;
815 re->first = 0;
816 re->bol = 0;
818 /* copy the string into it, translating ^ and $ as needed */
819 for (src = exp, dest = re->program + 1; *src; src++)
821 switch (*src)
823 case '^':
824 if (src == exp)
826 re->bol += 1;
828 else
830 *dest++ = '^';
831 re->minlen++;
833 break;
835 case '$':
836 if (!src[1])
838 re->bol += 2;
840 else
842 *dest++ = '$';
843 re->minlen++;
845 break;
847 case '\\':
848 if (src[1])
850 *dest++ = *++src;
851 re->minlen++;
853 else
855 regerror("extra \\ at end of regular expression");
857 break;
859 default:
860 *dest++ = *src;
861 re->minlen++;
864 *dest = '\0';
866 return re;
870 /* This "helper" function checks for a match at a given location. It returns
871 * 1 if it matches, 0 if it doesn't match here but might match later on in the
872 * string, or -1 if it could not possibly match
874 static int reghelp(prog, string, bolflag)
875 struct regexp *prog;
876 char *string;
877 int bolflag;
879 char *scan;
880 char *str;
882 /* if ^, then require bolflag */
883 if ((prog->bol & 1) && !bolflag)
885 return -1;
888 /* if it matches, then it will start here */
889 prog->startp[0] = string;
891 /* compare, possibly ignoring case */
892 if (*o_ignorecase)
894 for (scan = &prog->program[1]; *scan; scan++, string++)
895 if (tolower(*scan) != tolower(*string))
896 return *string ? 0 : -1;
898 else
900 for (scan = &prog->program[1]; *scan; scan++, string++)
901 if (*scan != *string)
902 return *string ? 0 : -1;
905 /* if $, then require string to end here, too */
906 if ((prog->bol & 2) && *string)
908 return 0;
911 /* if we get to here, it matches */
912 prog->endp[0] = string;
913 return 1;
918 int regexec(prog, string, bolflag)
919 struct regexp *prog;
920 char *string;
921 int bolflag;
923 int rc;
925 /* keep trying to match it */
926 for (rc = reghelp(prog, string, bolflag); rc == 0; rc = reghelp(prog, string, 0))
928 string++;
931 /* did we match? */
932 return rc == 1;
934 #endif