This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
perl 4.0 patch 16: patch #11, continued
[perl5.git] / regcomp.c
index 1333de2..0fd50c0 100644 (file)
--- a/regcomp.c
+++ b/regcomp.c
@@ -7,20 +7,28 @@
  * blame Henry for some of the lack of readability.
  */
 
-/* $Header: regcomp.c,v 3.0.1.2 90/02/28 18:08:35 lwall Locked $
+/* $RCSfile: regcomp.c,v $$Revision: 4.0.1.3 $$Date: 91/11/05 18:22:28 $
  *
  * $Log:       regcomp.c,v $
- * Revision 3.0.1.2  90/02/28  18:08:35  lwall
- * patch9: /[\200-\377]/ didn't work on machines with signed chars
+ * Revision 4.0.1.3  91/11/05  18:22:28  lwall
+ * patch11: minimum match length calculation in regexp is now cumulative
+ * patch11: initial .* in pattern had dependency on value of $*
+ * patch11: certain patterns made use of garbage pointers from uncleared memory
+ * patch11: prepared for ctype implementations that don't define isascii()
  * 
- * Revision 3.0.1.1  89/11/11  04:51:04  lwall
- * patch2: /[\000]/ didn't work
+ * Revision 4.0.1.2  91/06/07  11:48:24  lwall
+ * patch4: new copyright notice
+ * patch4: /(x+) \1/ incorrectly optimized to not match "xxx xx"
+ * patch4: // wouldn't use previous pattern if it started with a null character
  * 
- * Revision 3.0  89/10/18  15:22:29  lwall
- * 3.0 baseline
+ * Revision 4.0.1.1  91/04/12  09:04:45  lwall
+ * patch1: random cleanup in cpp namespace
+ * 
+ * Revision 4.0  91/03/20  01:39:01  lwall
+ * 4.0 baseline.
  * 
  */
-
+/*SUPPRESS 112*/
 /*
  * regcomp and regexec -- regsub and regerror are not used in perl
  *
  *
  ****    Alterations to Henry's code are...
  ****
- ****    Copyright (c) 1989, Larry Wall
+ ****    Copyright (c) 1991, Larry Wall
  ****
- ****    You may distribute under the terms of the GNU General Public License
- ****    as specified in the README file that comes with the perl 3.0 kit.
+ ****    You may distribute under the terms of either the GNU General Public
+ ****    License or the Artistic License, as specified in the README file.
+
  *
  * Beware that some of this code is subtly aware of the way operator
  * precedence is structured in regular expressions.  Serious changes in
 #include "INTERN.h"
 #include "regcomp.h"
 
+#ifdef MSDOS
+# if defined(BUGGY_MSC6)
+ /* MSC 6.00A breaks on op/regexp.t test 85 unless we turn this off */
+ # pragma optimize("a",off)
+ /* But MSC 6.00A is happy with 'w', for aliases only across function calls*/
+ # pragma optimize("w",on )
+# endif /* BUGGY_MSC6 */
+#endif /* MSDOS */
+
 #ifndef STATIC
 #define        STATIC  static
 #endif
@@ -67,6 +85,9 @@
        ((*s) == '{' && regcurly(s)))
 #define        META    "^$.[()|?+*\\"
 
+#ifdef SPSTART
+#undef SPSTART         /* dratted cpp namespace... */
+#endif
 /*
  * Flags to be passed up and down.
  */
@@ -86,6 +107,7 @@ static char *regcode;                /* Code-emit pointer; &regdummy = don't. */
 static long regsize;           /* Code size. */
 static int regfold;
 static int regsawbracket;      /* Did we do {d,d} trick? */
+static int regsawback;         /* Did we see \1, ...? */
 
 /*
  * Forward declarations for regcomp()'s friends.
@@ -97,6 +119,7 @@ STATIC char *regpiece();
 STATIC char *regatom();
 STATIC char *regclass();
 STATIC char *regnode();
+STATIC char *reganode();
 STATIC void regc();
 STATIC void reginsert();
 STATIC void regtail();
@@ -118,22 +141,26 @@ STATIC void regoptail();
  * of the structure of the compiled regexp.  [I'll say.]
  */
 regexp *
-regcomp(exp,xend,fold,rare)
+regcomp(exp,xend,fold)
 char *exp;
 char *xend;
 int fold;
-int rare;
 {
        register regexp *r;
        register char *scan;
-       register STR *longest;
+       register STR *longish;
+       STR *longest;
        register int len;
        register char *first;
        int flags;
-       int back;
+       int backish;
+       int backest;
        int curback;
+       int minlen;
        extern char *safemalloc();
        extern char *savestr();
+       int sawplus = 0;
+       int sawopen = 0;
 
        if (exp == NULL)
                fatal("NULL regexp argument");
@@ -144,12 +171,14 @@ int rare;
        regxend = xend;
        regprecomp = nsavestr(exp,xend-exp);
        regsawbracket = 0;
+       regsawback = 0;
        regnpar = 1;
        regsize = 0L;
        regcode = &regdummy;
-       regc(MAGIC);
+       regc((char)MAGIC);
        if (reg(0, &flags) == NULL) {
                Safefree(regprecomp);
+               regprecomp = Nullch;
                return(NULL);
        }
 
@@ -165,12 +194,13 @@ int rare;
        /* Second pass: emit code. */
        if (regsawbracket)
            bcopy(regprecomp,exp,xend-exp);
+       r->prelen = xend-exp;
        r->precomp = regprecomp;
-       r->subbase = NULL;
+       r->subbeg = r->subbase = NULL;
        regparse = exp;
        regnpar = 1;
        regcode = r->program;
-       regc(MAGIC);
+       regc((char)MAGIC);
        if (reg(0, &flags) == NULL)
                return(NULL);
 
@@ -185,12 +215,19 @@ int rare;
                scan = NEXTOPER(scan);
 
                first = scan;
-               while ((OP(first) > OPEN && OP(first) < CLOSE) ||
+               while ((OP(first) == OPEN && (sawopen = 1)) ||
                    (OP(first) == BRANCH && OP(regnext(first)) != BRANCH) ||
-                   (OP(first) == PLUS) )
+                   (OP(first) == PLUS) ||
+                   (OP(first) == CURLY && ARG1(first) > 0) ) {
+                       if (OP(first) == PLUS)
+                           sawplus = 1;
+                       else
+                           first += regarglen[OP(first)];
                        first = NEXTOPER(first);
+               }
 
                /* Starting-point info. */
+           again:
                if (OP(first) == EXACTLY) {
                        r->regstart =
                            str_make(OPERAND(first)+1,*OPERAND(first));
@@ -201,8 +238,15 @@ int rare;
                        r->regstclass = first;
                else if (OP(first) == BOUND || OP(first) == NBOUND)
                        r->regstclass = first;
-               else if (OP(first) == BOL)
-                       r->reganch++;
+               else if (OP(first) == BOL ||
+                   (OP(first) == STAR && OP(NEXTOPER(first)) == ANY) ) {
+                       /* kinda turn .* into ^.* */
+                       r->reganch = ROPT_ANCH | ROPT_IMPLICIT;
+                       first = NEXTOPER(first);
+                       goto again;
+               }
+               if (sawplus && (!sawopen || !regsawback))
+                   r->reganch |= ROPT_SKIP;    /* x+ must match 1st of run */
 
 #ifdef DEBUGGING
                if (debug & 512)
@@ -220,11 +264,14 @@ int rare;
                 * it happens that curback has been invalidated, since the
                 * earlier string may buy us something the later one won't.]
                 */
+               longish = str_make("",0);
                longest = str_make("",0);
                len = 0;
+               minlen = 0;
                curback = 0;
-               back = 0;
-               while (scan != NULL) {
+               backish = 0;
+               backest = 0;
+               while (OP(scan) != END) {
                        if (OP(scan) == BRANCH) {
                            if (OP(regnext(scan)) == BRANCH) {
                                curback = -30000;
@@ -235,11 +282,14 @@ int rare;
                                scan = NEXTOPER(scan);
                        }
                        if (OP(scan) == EXACTLY) {
+                           char *t;
+
                            first = scan;
-                           while (OP(regnext(scan)) >= CLOSE)
-                               scan = regnext(scan);
-                           if (curback - back == len) {
-                               str_ncat(longest, OPERAND(first)+1,
+                           while (OP(t = regnext(scan)) == CLOSE)
+                               scan = t;
+                           minlen += *OPERAND(first);
+                           if (curback - backish == len) {
+                               str_ncat(longish, OPERAND(first)+1,
                                    *OPERAND(first));
                                len += *OPERAND(first);
                                curback += *OPERAND(first);
@@ -247,37 +297,84 @@ int rare;
                            }
                            else if (*OPERAND(first) >= len + (curback >= 0)) {
                                len = *OPERAND(first);
-                               str_nset(longest, OPERAND(first)+1,len);
-                               back = curback;
+                               str_nset(longish, OPERAND(first)+1,len);
+                               backish = curback;
                                curback += len;
                                first = regnext(scan);
                            }
                            else
                                curback += *OPERAND(first);
                        }
-                       else if (index(varies,OP(scan)))
-                               curback = -30000;
-                       else if (index(simple,OP(scan)))
-                               curback++;
+                       else if (index(varies,OP(scan))) {
+                           curback = -30000;
+                           len = 0;
+                           if (longish->str_cur > longest->str_cur) {
+                               str_sset(longest,longish);
+                               backest = backish;
+                           }
+                           str_nset(longish,"",0);
+                           if (OP(scan) == PLUS &&
+                             index(simple,OP(NEXTOPER(scan))))
+                               minlen++;
+                           else if (OP(scan) == CURLY &&
+                             index(simple,OP(NEXTOPER(scan)+4)))
+                               minlen += ARG1(scan);
+                       }
+                       else if (index(simple,OP(scan))) {
+                           curback++;
+                           minlen++;
+                           len = 0;
+                           if (longish->str_cur > longest->str_cur) {
+                               str_sset(longest,longish);
+                               backest = backish;
+                           }
+                           str_nset(longish,"",0);
+                       }
                        scan = regnext(scan);
                }
-               if (len) {
+
+               /* Prefer earlier on tie, unless we can tail match latter */
+
+               if (longish->str_cur + (OP(first) == EOL) > longest->str_cur) {
+                   str_sset(longest,longish);
+                   backest = backish;
+               }
+               else
+                   str_nset(longish,"",0);
+               if (longest->str_cur
+                   &&
+                   (!r->regstart
+                    ||
+                    !fbminstr((unsigned char*) r->regstart->str_ptr,
+                         (unsigned char *) r->regstart->str_ptr
+                           + r->regstart->str_cur,
+                         longest)
+                   )
+                  )
+               {
                        r->regmust = longest;
-                       if (back < 0)
-                               back = -1;
-                       r->regback = back;
-                       if (len > !(sawstudy||fold||OP(first)==EOL))
+                       if (backest < 0)
+                               backest = -1;
+                       r->regback = backest;
+                       if (longest->str_cur
+                         > !(sawstudy || fold || OP(first) == EOL) )
                                fbmcompile(r->regmust,fold);
                        r->regmust->str_u.str_useful = 100;
-                       if (OP(first) == EOL) /* is match anchored to EOL? */
+                       if (OP(first) == EOL && longish->str_cur)
                            r->regmust->str_pok |= SP_TAIL;
                }
-               else
+               else {
                        str_free(longest);
+                       longest = Nullstr;
+               }
+               str_free(longish);
        }
 
        r->do_folding = fold;
        r->nparens = regnpar - 1;
+       r->minlen = minlen;
+       Newz(1002, r->startp, regnpar, char*);
+       Newz(1002, r->endp, regnpar, char*);
 #ifdef DEBUGGING
        if (debug & 512)
                regdump(r);
@@ -309,11 +406,9 @@ int *flagp;
 
        /* Make an OPEN node, if parenthesized. */
        if (paren) {
-               if (regnpar >= NSUBEXP)
-                       FAIL("too many () in regexp");
                parno = regnpar;
                regnpar++;
-               ret = regnode(OPEN+parno);
+               ret = reganode(OPEN, parno);
        } else
                ret = NULL;
 
@@ -340,7 +435,10 @@ int *flagp;
        }
 
        /* Make a closing node, and hook it on the end. */
-       ender = regnode((paren) ? CLOSE+parno : END);   
+       if (paren)
+           ender = reganode(CLOSE, parno);
+       else
+           ender = regnode(END);
        regtail(ret, ender);
 
        /* Hook the tails of the branches to the closing node. */
@@ -436,7 +534,7 @@ int *flagp;
        if (op == '{' && regcurly(regparse)) {
            next = regparse + 1;
            max = Nullch;
-           while (isdigit(*next) || *next == ',') {
+           while (isDIGIT(*next) || *next == ',') {
                if (*next == ',') {
                    if (max)
                        break;
@@ -446,21 +544,48 @@ int *flagp;
                next++;
            }
            if (*next == '}') {         /* got one */
-               regsawbracket++;        /* remember we clobbered exp */
                if (!max)
                    max = next;
                regparse++;
                iter = atoi(regparse);
+               if (flags&SIMPLE) {     /* we can do it right after all */
+                   int tmp;
+
+                   reginsert(CURLY, ret);
+                   if (iter > 0)
+                       *flagp = (WORST|HASWIDTH);
+                   if (*max == ',')
+                       max++;
+                   else
+                       max = regparse;
+                   tmp = atoi(max);
+                   if (tmp && tmp < iter)
+                       fatal("Can't do {n,m} with n > m");
+                   if (regcode != &regdummy) {
+#ifdef REGALIGN
+                       *(unsigned short *)(ret+3) = iter;
+                       *(unsigned short *)(ret+5) = tmp;
+#else
+                       ret[3] = iter >> 8; ret[4] = iter & 0377;
+                       ret[5] = tmp  >> 8; ret[6] = tmp  & 0377;
+#endif
+                   }
+                   regparse = next;
+                   goto nest_check;
+               }
+               regsawbracket++;        /* remember we clobbered exp */
                if (iter > 0) {
                    ch = *max;
                    sprintf(regparse,"%.*d", max-regparse, iter - 1);
                    *max = ch;
-                   if (*max == ',' && atoi(max+1) > 0) {
+                   if (*max == ',' && max[1] != '}') {
+                       if (atoi(max+1) <= 0)
+                           fatal("Can't do {n,m} with n > m");
                        ch = *next;
                        sprintf(max+1,"%.*d", next-(max+1), atoi(max+1) - 1);
                        *next = ch;
                    }
-                   if (iter != 1 || (*max == ',' || atoi(max+1))) {
+                   if (iter != 1 || *max == ',') {
                        regparse = origparse;   /* back up input pointer */
                        regnpar = orignpar;     /* don't make more parens */
                    }
@@ -636,14 +761,26 @@ int *flagp;
                case 'r':
                case 't':
                case 'f':
+               case 'e':
+               case 'a':
+               case 'x':
+               case 'c':
+               case '0':
                        goto defchar;
-               case '0': case '1': case '2': case '3': case '4':
+               case '1': case '2': case '3': case '4':
                case '5': case '6': case '7': case '8': case '9':
-                       if (isdigit(regparse[1]))
+                       {
+                           int num = atoi(regparse);
+
+                           if (num > 9 && num >= regnpar)
                                goto defchar;
-                       else {
-                               ret = regnode(REF + *regparse++ - '0');
+                           else {
+                               regsawback = 1;
+                               ret = reganode(REF, num);
+                               while (isDIGIT(*regparse))
+                                   regparse++;
                                *flagp |= SIMPLE;
+                           }
                        }
                        break;
                case '\0':
@@ -659,7 +796,7 @@ int *flagp;
                        register char ender;
                        register char *p;
                        char *oldp;
-                       int foo;
+                       int numlen;
 
                    defchar:
                        ret = regnode(EXACTLY);
@@ -706,16 +843,31 @@ int *flagp;
                                        ender = '\f';
                                        p++;
                                        break;
+                               case 'e':
+                                       ender = '\033';
+                                       p++;
+                                       break;
+                               case 'a':
+                                       ender = '\007';
+                                       p++;
+                                       break;
+                               case 'x':
+                                   ender = scanhex(++p, 2, &numlen);
+                                   p += numlen;
+                                   break;
+                               case 'c':
+                                   p++;
+                                   ender = *p++;
+                                   if (isLOWER(ender))
+                                       ender = toupper(ender);
+                                   ender ^= 64;
+                                   break;
                                case '0': case '1': case '2': case '3':case '4':
                                case '5': case '6': case '7': case '8':case '9':
-                                   if (isdigit(p[1])) {
-                                       foo = *p++ - '0';
-                                       foo <<= 3;
-                                       foo += *p - '0';
-                                       if (isdigit(p[1]))
-                                           foo = (foo<<3) + *++p - '0';
-                                       ender = foo;
-                                       p++;
+                                   if (*p == '0' ||
+                                     (isDIGIT(p[1]) && atoi(p) >= regnpar) ) {
+                                       ender = scanoct(p, 3, &numlen);
+                                       p += numlen;
                                    }
                                    else {
                                        --p;
@@ -735,7 +887,7 @@ int *flagp;
                                ender = *p++;
                                break;
                            }
-                           if (regfold && isupper(ender))
+                           if (regfold && isUPPER(ender))
                                    ender = tolower(ender);
                            if (ISMULT2(p)) { /* Back off on ?+*. */
                                if (len)
@@ -789,21 +941,22 @@ regclass()
        register int range = 0;
        register char *ret;
        register int def;
+       int numlen;
 
+       ret = regnode(ANYOF);
        if (*regparse == '^') { /* Complement of range. */
-               ret = regnode(ANYBUT);
                regparse++;
                def = 0;
        } else {
-               ret = regnode(ANYOF);
                def = 255;
        }
        bits = regcode;
        for (class = 0; class < 32; class++)
            regc(def);
        if (*regparse == ']' || *regparse == '-')
-               regset(bits,def,lastclass = *regparse++);
+               goto skipcond;          /* allow 1st char to be ] or - */
        while (regparse < regxend && *regparse != ']') {
+             skipcond:
                class = UCHARAT(regparse++);
                if (class == '\\') {
                        class = UCHARAT(regparse++);
@@ -846,35 +999,46 @@ regclass()
                        case 'b':
                                class = '\b';
                                break;
+                       case 'e':
+                               class = '\033';
+                               break;
+                       case 'a':
+                               class = '\007';
+                               break;
+                       case 'x':
+                               class = scanhex(regparse, 2, &numlen);
+                               regparse += numlen;
+                               break;
+                       case 'c':
+                               class = *regparse++;
+                               if (isLOWER(class))
+                                   class = toupper(class);
+                               class ^= 64;
+                               break;
                        case '0': case '1': case '2': case '3': case '4':
                        case '5': case '6': case '7': case '8': case '9':
-                               class -= '0';
-                               if (isdigit(*regparse)) {
-                                       class <<= 3;
-                                       class += *regparse++ - '0';
-                               }
-                               if (isdigit(*regparse)) {
-                                       class <<= 3;
-                                       class += *regparse++ - '0';
-                               }
+                               class = scanoct(--regparse, 3, &numlen);
+                               regparse += numlen;
                                break;
                        }
                }
-               if (!range && class == '-' && regparse < regxend &&
-                   *regparse != ']') {
-                       range = 1;
-                       continue;
-               }
                if (range) {
                        if (lastclass > class)
                                FAIL("invalid [] range in regexp");
+                       range = 0;
                }
-               else
-                       lastclass = class - 1;
-               range = 0;
-               for (lastclass++; lastclass <= class; lastclass++) {
+               else {
+                       lastclass = class;
+                       if (*regparse == '-' && regparse+1 < regxend &&
+                           regparse[1] != ']') {
+                               regparse++;
+                               range = 1;
+                               continue;       /* do it next time */
+                       }
+               }
+               for ( ; lastclass <= class; lastclass++) {
                        regset(bits,def,lastclass);
-                       if (regfold && isupper(lastclass))
+                       if (regfold && isUPPER(lastclass))
                                regset(bits,def,tolower(lastclass));
                }
                lastclass = class;
@@ -921,6 +1085,48 @@ char op;
 }
 
 /*
+ - reganode - emit a node with an argument
+ */
+static char *                  /* Location. */
+reganode(op, arg)
+char op;
+unsigned short arg;
+{
+       register char *ret;
+       register char *ptr;
+
+       ret = regcode;
+       if (ret == &regdummy) {
+#ifdef REGALIGN
+               if (!(regsize & 1))
+                       regsize++;
+#endif
+               regsize += 5;
+               return(ret);
+       }
+
+#ifdef REGALIGN
+#ifndef lint
+       if (!((long)ret & 1))
+           *ret++ = 127;
+#endif
+#endif
+       ptr = ret;
+       *ptr++ = op;
+       *ptr++ = '\0';          /* Null "next" pointer. */
+       *ptr++ = '\0';
+#ifdef REGALIGN
+       *(unsigned short *)(ret+3) = arg;
+#else
+       ret[3] = arg >> 8; ret[4] = arg & 0377;
+#endif
+       ptr += 2;
+       regcode = ptr;
+
+       return(ret);
+}
+
+/*
  - regc - emit (if appropriate) a byte of code
  */
 static void
@@ -946,21 +1152,22 @@ char *opnd;
        register char *src;
        register char *dst;
        register char *place;
+       register offset = (op == CURLY ? 4 : 0);
 
        if (regcode == &regdummy) {
 #ifdef REGALIGN
-               regsize += 4;
+               regsize += 4 + offset;
 #else
-               regsize += 3;
+               regsize += 3 + offset;
 #endif
                return;
        }
 
        src = regcode;
 #ifdef REGALIGN
-       regcode += 4;
+       regcode += 4 + offset;
 #else
-       regcode += 3;
+       regcode += 3 + offset;
 #endif
        dst = regcode;
        while (src > opnd)
@@ -970,6 +1177,8 @@ char *opnd;
        *place++ = op;
        *place++ = '\0';
        *place++ = '\0';
+       while (offset-- > 0)
+           *place++ = '\0';
 }
 
 /*
@@ -1036,13 +1245,13 @@ register char *s;
 {
     if (*s++ != '{')
        return FALSE;
-    if (!isdigit(*s))
+    if (!isDIGIT(*s))
        return FALSE;
-    while (isdigit(*s))
+    while (isDIGIT(*s))
        s++;
     if (*s == ',')
        s++;
-    while (isdigit(*s))
+    while (isDIGIT(*s))
        s++;
     if (*s != '}')
        return FALSE;
@@ -1061,7 +1270,6 @@ regexp *r;
        register char *s;
        register char op = EXACTLY;     /* Arbitrary non-END op. */
        register char *next;
-       extern char *index();
 
 
        s = r->program + 1;
@@ -1073,12 +1281,13 @@ regexp *r;
                op = OP(s);
                fprintf(stderr,"%2d%s", s-r->program, regprop(s));      /* Where, what. */
                next = regnext(s);
+               s += regarglen[op];
                if (next == NULL)               /* Next ptr. */
                        fprintf(stderr,"(0)");
                else 
                        fprintf(stderr,"(%d)", (s-r->program)+(next-s));
                s += 3;
-               if (op == ANYOF || op == ANYBUT) {
+               if (op == ANYOF) {
                        s += 32;
                }
                if (op == EXACTLY) {
@@ -1098,11 +1307,16 @@ regexp *r;
                fprintf(stderr,"start `%s' ", r->regstart->str_ptr);
        if (r->regstclass)
                fprintf(stderr,"stclass `%s' ", regprop(r->regstclass));
-       if (r->reganch)
+       if (r->reganch & ROPT_ANCH)
                fprintf(stderr,"anchored ");
+       if (r->reganch & ROPT_SKIP)
+               fprintf(stderr,"plus ");
+       if (r->reganch & ROPT_IMPLICIT)
+               fprintf(stderr,"implicit ");
        if (r->regmust != NULL)
                fprintf(stderr,"must have \"%s\" back %d ", r->regmust->str_ptr,
                  r->regback);
+       fprintf(stderr, "minlen %d ", r->minlen);
        fprintf(stderr,"\n");
 }
 
@@ -1130,9 +1344,6 @@ char *op;
        case ANYOF:
                p = "ANYOF";
                break;
-       case ANYBUT:
-               p = "ANYBUT";
-               break;
        case BRANCH:
                p = "BRANCH";
                break;
@@ -1172,41 +1383,21 @@ char *op;
        case NDIGIT:
                p = "NDIGIT";
                break;
+       case CURLY:
+               (void)sprintf(buf+strlen(buf), "CURLY {%d,%d}",
+                   ARG1(op),ARG2(op));
+               p = NULL;
+               break;
        case REF:
-       case REF+1:
-       case REF+2:
-       case REF+3:
-       case REF+4:
-       case REF+5:
-       case REF+6:
-       case REF+7:
-       case REF+8:
-       case REF+9:
-               (void)sprintf(buf+strlen(buf), "REF%d", OP(op)-REF);
+               (void)sprintf(buf+strlen(buf), "REF%d", ARG1(op));
                p = NULL;
                break;
-       case OPEN+1:
-       case OPEN+2:
-       case OPEN+3:
-       case OPEN+4:
-       case OPEN+5:
-       case OPEN+6:
-       case OPEN+7:
-       case OPEN+8:
-       case OPEN+9:
-               (void)sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
+       case OPEN:
+               (void)sprintf(buf+strlen(buf), "OPEN%d", ARG1(op));
                p = NULL;
                break;
-       case CLOSE+1:
-       case CLOSE+2:
-       case CLOSE+3:
-       case CLOSE+4:
-       case CLOSE+5:
-       case CLOSE+6:
-       case CLOSE+7:
-       case CLOSE+8:
-       case CLOSE+9:
-               (void)sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
+       case CLOSE:
+               (void)sprintf(buf+strlen(buf), "CLOSE%d", ARG1(op));
                p = NULL;
                break;
        case STAR:
@@ -1227,13 +1418,23 @@ char *op;
 regfree(r)
 struct regexp *r;
 {
-       if (r->precomp)
+       if (r->precomp) {
                Safefree(r->precomp);
-       if (r->subbase)
+               r->precomp = Nullch;
+       }
+       if (r->subbase) {
                Safefree(r->subbase);
-       if (r->regmust)
+               r->subbase = Nullch;
+       }
+       if (r->regmust) {
                str_free(r->regmust);
-       if (r->regstart)
+               r->regmust = Nullstr;
+       }
+       if (r->regstart) {
                str_free(r->regstart);
+               r->regstart = Nullstr;
+       }
+       Safefree(r->startp);
+       Safefree(r->endp);
        Safefree(r);
 }