home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / perl-5.003-base.tgz / perl-5.003-base.tar / fsf / perl / regexec.c < prev    next >
C/C++ Source or Header  |  1995-11-14  |  25KB  |  1,120 lines

  1. /*    regexec.c
  2.  */
  3.  
  4. /*
  5.  * "One Ring to rule them all, One Ring to find them..."
  6.  */
  7.  
  8. /* NOTE: this is derived from Henry Spencer's regexp code, and should not
  9.  * confused with the original package (see point 3 below).  Thanks, Henry!
  10.  */
  11.  
  12. /* Additional note: this code is very heavily munged from Henry's version
  13.  * in places.  In some spots I've traded clarity for efficiency, so don't
  14.  * blame Henry for some of the lack of readability.
  15.  */
  16.  
  17. /* The names of the functions have been changed from regcomp and
  18.  * regexec to  pregcomp and pregexec in order to avoid conflicts
  19.  * with the POSIX routines of the same names.
  20. */
  21.  
  22. /*SUPPRESS 112*/
  23. /*
  24.  * pregcomp and pregexec -- regsub and regerror are not used in perl
  25.  *
  26.  *    Copyright (c) 1986 by University of Toronto.
  27.  *    Written by Henry Spencer.  Not derived from licensed software.
  28.  *
  29.  *    Permission is granted to anyone to use this software for any
  30.  *    purpose on any computer system, and to redistribute it freely,
  31.  *    subject to the following restrictions:
  32.  *
  33.  *    1. The author is not responsible for the consequences of use of
  34.  *        this software, no matter how awful, even if they arise
  35.  *        from defects in it.
  36.  *
  37.  *    2. The origin of this software must not be misrepresented, either
  38.  *        by explicit claim or by omission.
  39.  *
  40.  *    3. Altered versions must be plainly marked as such, and must not
  41.  *        be misrepresented as being the original software.
  42.  *
  43.  ****    Alterations to Henry's code are...
  44.  ****
  45.  ****    Copyright (c) 1991-1994, Larry Wall
  46.  ****
  47.  ****    You may distribute under the terms of either the GNU General Public
  48.  ****    License or the Artistic License, as specified in the README file.
  49.  *
  50.  * Beware that some of this code is subtly aware of the way operator
  51.  * precedence is structured in regular expressions.  Serious changes in
  52.  * regular-expression syntax might require a total rethink.
  53.  */
  54. #include "EXTERN.h"
  55. #include "perl.h"
  56. #include "regcomp.h"
  57.  
  58. #ifndef STATIC
  59. #define    STATIC    static
  60. #endif
  61.  
  62. #ifdef DEBUGGING
  63. static I32 regnarrate = 0;
  64. static char* regprogram = 0;
  65. #endif
  66.  
  67. /* Current curly descriptor */
  68. typedef struct curcur CURCUR;
  69. struct curcur {
  70.     int        parenfloor;    /* how far back to strip paren data */
  71.     int        cur;        /* how many instances of scan we've matched */
  72.     int        min;        /* the minimal number of scans to match */
  73.     int        max;        /* the maximal number of scans to match */
  74.     int        minmod;        /* whether to work our way up or down */
  75.     char *    scan;        /* the thing to match */
  76.     char *    next;        /* what has to match after it */
  77.     char *    lastloc;    /* where we started matching this scan */
  78.     CURCUR *    oldcc;        /* current curly before we started this one */
  79. };
  80.  
  81. static CURCUR* regcc;
  82.  
  83. typedef I32 CHECKPOINT;
  84.  
  85. CHECKPOINT regcppush _((I32 parenfloor));
  86. char * regcppop _((void));
  87.  
  88. CHECKPOINT
  89. regcppush(parenfloor)
  90. I32 parenfloor;
  91. {
  92.     int retval = savestack_ix;
  93.     int i = (regsize - parenfloor) * 3;
  94.     int p;
  95.  
  96.     SSCHECK(i + 5);
  97.     for (p = regsize; p > parenfloor; p--) {
  98.     SSPUSHPTR(regendp[p]);
  99.     SSPUSHPTR(regstartp[p]);
  100.     SSPUSHINT(p);
  101.     }
  102.     SSPUSHINT(regsize);
  103.     SSPUSHINT(*reglastparen);
  104.     SSPUSHPTR(reginput);
  105.     SSPUSHINT(i + 3);
  106.     SSPUSHINT(SAVEt_REGCONTEXT);
  107.     return retval;
  108. }
  109.  
  110. char*
  111. regcppop()
  112. {
  113.     I32 i = SSPOPINT;
  114.     U32 paren = 0;
  115.     char *input;
  116.     char *tmps;
  117.     assert(i == SAVEt_REGCONTEXT);
  118.     i = SSPOPINT;
  119.     input = (char *) SSPOPPTR;
  120.     *reglastparen = SSPOPINT;
  121.     regsize = SSPOPINT;
  122.     for (i -= 3; i > 0; i -= 3) {
  123.     paren = (U32)SSPOPINT;
  124.     regstartp[paren] = (char *) SSPOPPTR;
  125.     tmps = (char*)SSPOPPTR;
  126.     if (paren <= *reglastparen)
  127.         regendp[paren] = tmps;
  128.     }
  129.     for (paren = *reglastparen + 1; paren <= regnpar; paren++) {
  130.     if (paren > regsize)
  131.         regstartp[paren] = Nullch;
  132.     regendp[paren] = Nullch;
  133.     }
  134.     return input;
  135. }
  136.  
  137. #define regcpblow(cp) leave_scope(cp)
  138.  
  139. /*
  140.  * pregexec and friends
  141.  */
  142.  
  143. /*
  144.  * Forwards.
  145.  */
  146.  
  147. static I32 regmatch _((char *prog));
  148. static I32 regrepeat _((char *p, I32 max));
  149. static I32 regtry _((regexp *prog, char *startpos));
  150.  
  151. /*
  152.  - pregexec - match a regexp against a string
  153.  */
  154. I32
  155. pregexec(prog, stringarg, strend, strbeg, minend, screamer, safebase)
  156. register regexp *prog;
  157. char *stringarg;
  158. register char *strend;    /* pointer to null at end of string */
  159. char *strbeg;    /* real beginning of string */
  160. I32 minend;    /* end of match must be at least minend after stringarg */
  161. SV *screamer;
  162. I32 safebase;    /* no need to remember string in subbase */
  163. {
  164.     register char *s;
  165.     register I32 i;
  166.     register char *c;
  167.     register char *startpos = stringarg;
  168.     register I32 tmp;
  169.     I32 minlen = 0;        /* must match at least this many chars */
  170.     I32 dontbother = 0;    /* how many characters not to try at end */
  171.     CURCUR cc;
  172.  
  173.     cc.cur = 0;
  174.     cc.oldcc = 0;
  175.     regcc = &cc;
  176.  
  177. #ifdef DEBUGGING
  178.     regnarrate = debug & 512;
  179.     regprogram = prog->program;
  180. #endif
  181.  
  182.     /* Be paranoid... */
  183.     if (prog == NULL || startpos == NULL) {
  184.     croak("NULL regexp parameter");
  185.     return 0;
  186.     }
  187.  
  188.     if (startpos == strbeg)    /* is ^ valid at stringarg? */
  189.     regprev = '\n';
  190.     else {
  191.     regprev = stringarg[-1];
  192.     if (!multiline && regprev == '\n')
  193.         regprev = '\0';        /* force ^ to NOT match */
  194.     }
  195.     regprecomp = prog->precomp;
  196.     regnpar = prog->nparens;
  197.     /* Check validity of program. */
  198.     if (UCHARAT(prog->program) != MAGIC) {
  199.     FAIL("corrupted regexp program");
  200.     }
  201.  
  202.     if (prog->do_folding) {
  203.     i = strend - startpos;
  204.     New(1101,c,i+1,char);
  205.     Copy(startpos, c, i+1, char);
  206.     startpos = c;
  207.     strend = startpos + i;
  208.     for (s = startpos; s < strend; s++)
  209.         if (isUPPER(*s))
  210.         *s = toLOWER(*s);
  211.     }
  212.  
  213.     /* If there is a "must appear" string, look for it. */
  214.     s = startpos;
  215.     if (prog->regmust != Nullsv &&
  216.     (!(prog->reganch & ROPT_ANCH)
  217.      || (multiline && prog->regback >= 0)) )
  218.     {
  219.     if (stringarg == strbeg && screamer) {
  220.         if (screamfirst[BmRARE(prog->regmust)] >= 0)
  221.             s = screaminstr(screamer,prog->regmust);
  222.         else
  223.             s = Nullch;
  224.     }
  225.     else
  226.         s = fbm_instr((unsigned char*)s, (unsigned char*)strend,
  227.         prog->regmust);
  228.     if (!s) {
  229.         ++BmUSEFUL(prog->regmust);    /* hooray */
  230.         goto phooey;    /* not present */
  231.     }
  232.     else if (prog->regback >= 0) {
  233.         s -= prog->regback;
  234.         if (s < startpos)
  235.         s = startpos;
  236.         minlen = prog->regback + SvCUR(prog->regmust);
  237.     }
  238.     else if (!prog->naughty && --BmUSEFUL(prog->regmust) < 0) { /* boo */
  239.         SvREFCNT_dec(prog->regmust);
  240.         prog->regmust = Nullsv;    /* disable regmust */
  241.         s = startpos;
  242.     }
  243.     else {
  244.         s = startpos;
  245.         minlen = SvCUR(prog->regmust);
  246.     }
  247.     }
  248.  
  249.     /* Mark beginning of line for ^ . */
  250.     regbol = startpos;
  251.  
  252.     /* Mark end of line for $ (and such) */
  253.     regeol = strend;
  254.  
  255.     /* see how far we have to get to not match where we matched before */
  256.     regtill = startpos+minend;
  257.  
  258.     /* Simplest case:  anchored match need be tried only once. */
  259.     /*  [unless multiline is set] */
  260.     if (prog->reganch & ROPT_ANCH) {
  261.     if (regtry(prog, startpos))
  262.         goto got_it;
  263.     else if (multiline || (prog->reganch & ROPT_IMPLICIT)) {
  264.         if (minlen)
  265.         dontbother = minlen - 1;
  266.         strend -= dontbother;
  267.         /* for multiline we only have to try after newlines */
  268.         if (s > startpos)
  269.         s--;
  270.         while (s < strend) {
  271.         if (*s++ == '\n') {
  272.             if (s < strend && regtry(prog, s))
  273.             goto got_it;
  274.         }
  275.         }
  276.     }
  277.     goto phooey;
  278.     }
  279.  
  280.     /* Messy cases:  unanchored match. */
  281.     if (prog->regstart) {
  282.     if (prog->reganch & ROPT_SKIP) {  /* we have /x+whatever/ */
  283.         /* it must be a one character string */
  284.         i = SvPVX(prog->regstart)[0];
  285.         while (s < strend) {
  286.         if (*s == i) {
  287.             if (regtry(prog, s))
  288.             goto got_it;
  289.             s++;
  290.             while (s < strend && *s == i)
  291.             s++;
  292.         }
  293.         s++;
  294.         }
  295.     }
  296.     else if (SvPOK(prog->regstart) == 3) {
  297.         /* We know what string it must start with. */
  298.         while ((s = fbm_instr((unsigned char*)s,
  299.           (unsigned char*)strend, prog->regstart)) != NULL)
  300.         {
  301.         if (regtry(prog, s))
  302.             goto got_it;
  303.         s++;
  304.         }
  305.     }
  306.     else {
  307.         c = SvPVX(prog->regstart);
  308.         while ((s = ninstr(s, strend, c, c + SvCUR(prog->regstart))) != NULL)
  309.         {
  310.         if (regtry(prog, s))
  311.             goto got_it;
  312.         s++;
  313.         }
  314.     }
  315.     goto phooey;
  316.     }
  317.     /*SUPPRESS 560*/
  318.     if (c = prog->regstclass) {
  319.     I32 doevery = (prog->reganch & ROPT_SKIP) == 0;
  320.  
  321.     if (minlen)
  322.         dontbother = minlen - 1;
  323.     strend -= dontbother;    /* don't bother with what can't match */
  324.     tmp = 1;
  325.     /* We know what class it must start with. */
  326.     switch (OP(c)) {
  327.     case ANYOF:
  328.         c = OPERAND(c);
  329.         while (s < strend) {
  330.         i = UCHARAT(s);
  331.         if (!(c[i >> 3] & (1 << (i&7)))) {
  332.             if (tmp && regtry(prog, s))
  333.             goto got_it;
  334.             else
  335.             tmp = doevery;
  336.         }
  337.         else
  338.             tmp = 1;
  339.         s++;
  340.         }
  341.         break;
  342.     case BOUND:
  343.         if (minlen)
  344.         dontbother++,strend--;
  345.         if (s != startpos) {
  346.         i = s[-1];
  347.         tmp = isALNUM(i);
  348.         }
  349.         else
  350.         tmp = isALNUM(regprev);    /* assume not alphanumeric */
  351.         while (s < strend) {
  352.         i = *s;
  353.         if (tmp != isALNUM(i)) {
  354.             tmp = !tmp;
  355.             if (regtry(prog, s))
  356.             goto got_it;
  357.         }
  358.         s++;
  359.         }
  360.         if ((minlen || tmp) && regtry(prog,s))
  361.         goto got_it;
  362.         break;
  363.     case NBOUND:
  364.         if (minlen)
  365.         dontbother++,strend--;
  366.         if (s != startpos) {
  367.         i = s[-1];
  368.         tmp = isALNUM(i);
  369.         }
  370.         else
  371.         tmp = isALNUM(regprev);    /* assume not alphanumeric */
  372.         while (s < strend) {
  373.         i = *s;
  374.         if (tmp != isALNUM(i))
  375.             tmp = !tmp;
  376.         else if (regtry(prog, s))
  377.             goto got_it;
  378.         s++;
  379.         }
  380.         if ((minlen || !tmp) && regtry(prog,s))
  381.         goto got_it;
  382.         break;
  383.     case ALNUM:
  384.         while (s < strend) {
  385.         i = *s;
  386.         if (isALNUM(i)) {
  387.             if (tmp && regtry(prog, s))
  388.             goto got_it;
  389.             else
  390.             tmp = doevery;
  391.         }
  392.         else
  393.             tmp = 1;
  394.         s++;
  395.         }
  396.         break;
  397.     case NALNUM:
  398.         while (s < strend) {
  399.         i = *s;
  400.         if (!isALNUM(i)) {
  401.             if (tmp && regtry(prog, s))
  402.             goto got_it;
  403.             else
  404.             tmp = doevery;
  405.         }
  406.         else
  407.             tmp = 1;
  408.         s++;
  409.         }
  410.         break;
  411.     case SPACE:
  412.         while (s < strend) {
  413.         if (isSPACE(*s)) {
  414.             if (tmp && regtry(prog, s))
  415.             goto got_it;
  416.             else
  417.             tmp = doevery;
  418.         }
  419.         else
  420.             tmp = 1;
  421.         s++;
  422.         }
  423.         break;
  424.     case NSPACE:
  425.         while (s < strend) {
  426.         if (!isSPACE(*s)) {
  427.             if (tmp && regtry(prog, s))
  428.             goto got_it;
  429.             else
  430.             tmp = doevery;
  431.         }
  432.         else
  433.             tmp = 1;
  434.         s++;
  435.         }
  436.         break;
  437.     case DIGIT:
  438.         while (s < strend) {
  439.         if (isDIGIT(*s)) {
  440.             if (tmp && regtry(prog, s))
  441.             goto got_it;
  442.             else
  443.             tmp = doevery;
  444.         }
  445.         else
  446.             tmp = 1;
  447.         s++;
  448.         }
  449.         break;
  450.     case NDIGIT:
  451.         while (s < strend) {
  452.         if (!isDIGIT(*s)) {
  453.             if (tmp && regtry(prog, s))
  454.             goto got_it;
  455.             else
  456.             tmp = doevery;
  457.         }
  458.         else
  459.             tmp = 1;
  460.         s++;
  461.         }
  462.         break;
  463.     }
  464.     }
  465.     else {
  466.     if (minlen)
  467.         dontbother = minlen - 1;
  468.     strend -= dontbother;
  469.     /* We don't know much -- general case. */
  470.     do {
  471.         if (regtry(prog, s))
  472.         goto got_it;
  473.     } while (s++ < strend);
  474.     }
  475.  
  476.     /* Failure. */
  477.     goto phooey;
  478.  
  479. got_it:
  480.     strend += dontbother;    /* uncheat */
  481.     prog->subbeg = strbeg;
  482.     prog->subend = strend;
  483.     if ((!safebase && (prog->nparens || sawampersand)) || prog->do_folding) {
  484.     i = strend - startpos + (stringarg - strbeg);
  485.     if (safebase) {            /* no need for $digit later */
  486.         s = strbeg;
  487.         prog->subend = s+i;
  488.     }
  489.     else if (strbeg != prog->subbase) {
  490.         s = savepvn(strbeg,i);    /* so $digit will work later */
  491.         if (prog->subbase)
  492.         Safefree(prog->subbase);
  493.         prog->subbeg = prog->subbase = s;
  494.         prog->subend = s+i;
  495.     }
  496.     else {
  497.         prog->subbeg = s = prog->subbase;
  498.         prog->subend = s+i;
  499.     }
  500.     s += (stringarg - strbeg);
  501.     for (i = 0; i <= prog->nparens; i++) {
  502.         if (prog->endp[i]) {
  503.         prog->startp[i] = s + (prog->startp[i] - startpos);
  504.         prog->endp[i] = s + (prog->endp[i] - startpos);
  505.         }
  506.     }
  507.     if (prog->do_folding)
  508.         Safefree(startpos);
  509.     }
  510.     return 1;
  511.  
  512. phooey:
  513.     if (prog->do_folding)
  514.     Safefree(startpos);
  515.     return 0;
  516. }
  517.  
  518. /*
  519.  - regtry - try match at specific point
  520.  */
  521. static I32            /* 0 failure, 1 success */
  522. regtry(prog, startpos)
  523. regexp *prog;
  524. char *startpos;
  525. {
  526.     register I32 i;
  527.     register char **sp;
  528.     register char **ep;
  529.  
  530.     reginput = startpos;
  531.     regstartp = prog->startp;
  532.     regendp = prog->endp;
  533.     reglastparen = &prog->lastparen;
  534.     prog->lastparen = 0;
  535.     regsize = 0;
  536.  
  537.     sp = prog->startp;
  538.     ep = prog->endp;
  539.     if (prog->nparens) {
  540.     for (i = prog->nparens; i >= 0; i--) {
  541.         *sp++ = NULL;
  542.         *ep++ = NULL;
  543.     }
  544.     }
  545.     if (regmatch(prog->program + 1) && reginput >= regtill) {
  546.     prog->startp[0] = startpos;
  547.     prog->endp[0] = reginput;
  548.     return 1;
  549.     }
  550.     else
  551.     return 0;
  552. }
  553.  
  554. /*
  555.  - regmatch - main matching routine
  556.  *
  557.  * Conceptually the strategy is simple:  check to see whether the current
  558.  * node matches, call self recursively to see whether the rest matches,
  559.  * and then act accordingly.  In practice we make some effort to avoid
  560.  * recursion, in particular by going through "ordinary" nodes (that don't
  561.  * need to know whether the rest of the match failed) by a loop instead of
  562.  * by recursion.
  563.  */
  564. /* [lwall] I've hoisted the register declarations to the outer block in order to
  565.  * maybe save a little bit of pushing and popping on the stack.  It also takes
  566.  * advantage of machines that use a register save mask on subroutine entry.
  567.  */
  568. static I32            /* 0 failure, 1 success */
  569. regmatch(prog)
  570. char *prog;
  571. {
  572.     register char *scan;    /* Current node. */
  573.     char *next;            /* Next node. */
  574.     register I32 nextchar;
  575.     register I32 n;        /* no or next */
  576.     register I32 ln;        /* len or last */
  577.     register char *s;        /* operand or save */
  578.     register char *locinput = reginput;
  579.     int minmod = 0;
  580. #ifdef DEBUGGING
  581.     static int regindent = 0;
  582.     regindent++;
  583. #endif
  584.  
  585.     nextchar = *locinput;
  586.     scan = prog;
  587.     while (scan != NULL) {
  588. #ifdef DEBUGGING
  589. #define sayYES goto yes
  590. #define sayNO goto no
  591. #define saySAME(x) if (x) goto yes; else goto no
  592.     if (regnarrate) {
  593.         fprintf(stderr, "%*s%2d%-8.8s\t<%.10s>\n", regindent*2, "",
  594.         scan - regprogram, regprop(scan), locinput);
  595.     }
  596. #else
  597. #define sayYES return 1
  598. #define sayNO return 0
  599. #define saySAME(x) return x
  600. #endif
  601.  
  602. #ifdef REGALIGN
  603.     next = scan + NEXT(scan);
  604.     if (next == scan)
  605.         next = NULL;
  606. #else
  607.     next = regnext(scan);
  608. #endif
  609.  
  610.     switch (OP(scan)) {
  611.     case BOL:
  612.         if (locinput == regbol
  613.         ? regprev == '\n'
  614.         : ((nextchar || locinput < regeol) && locinput[-1] == '\n') )
  615.         {
  616.         /* regtill = regbol; */
  617.         break;
  618.         }
  619.         sayNO;
  620.     case MBOL:
  621.         if (locinput == regbol
  622.         ? regprev == '\n'
  623.         : ((nextchar || locinput < regeol) && locinput[-1] == '\n') )
  624.         {
  625.         break;
  626.         }
  627.         sayNO;
  628.     case SBOL:
  629.         if (locinput == regbol && regprev == '\n')
  630.         break;
  631.         sayNO;
  632.     case GBOL:
  633.         if (locinput == regbol)
  634.         break;
  635.         sayNO;
  636.     case EOL:
  637.         if (multiline)
  638.         goto meol;
  639.         else
  640.         goto seol;
  641.     case MEOL:
  642.       meol:
  643.         if ((nextchar || locinput < regeol) && nextchar != '\n')
  644.         sayNO;
  645.         break;
  646.     case SEOL:
  647.       seol:
  648.         if ((nextchar || locinput < regeol) && nextchar != '\n')
  649.         sayNO;
  650.         if (regeol - locinput > 1)
  651.         sayNO;
  652.         break;
  653.     case SANY:
  654.         if (!nextchar && locinput >= regeol)
  655.         sayNO;
  656.         nextchar = *++locinput;
  657.         break;
  658.     case ANY:
  659.         if (!nextchar && locinput >= regeol || nextchar == '\n')
  660.         sayNO;
  661.         nextchar = *++locinput;
  662.         break;
  663.     case EXACTLY:
  664.         s = OPERAND(scan);
  665.         ln = *s++;
  666.         /* Inline the first character, for speed. */
  667.         if (*s != nextchar)
  668.         sayNO;
  669.         if (regeol - locinput < ln)
  670.         sayNO;
  671.         if (ln > 1 && bcmp(s, locinput, ln) != 0)
  672.         sayNO;
  673.         locinput += ln;
  674.         nextchar = *locinput;
  675.         break;
  676.     case ANYOF:
  677.         s = OPERAND(scan);
  678.         if (nextchar < 0)
  679.         nextchar = UCHARAT(locinput);
  680.         if (s[nextchar >> 3] & (1 << (nextchar&7)))
  681.         sayNO;
  682.         if (!nextchar && locinput >= regeol)
  683.         sayNO;
  684.         nextchar = *++locinput;
  685.         break;
  686.     case ALNUM:
  687.         if (!nextchar)
  688.         sayNO;
  689.         if (!isALNUM(nextchar))
  690.         sayNO;
  691.         nextchar = *++locinput;
  692.         break;
  693.     case NALNUM:
  694.         if (!nextchar && locinput >= regeol)
  695.         sayNO;
  696.         if (isALNUM(nextchar))
  697.         sayNO;
  698.         nextchar = *++locinput;
  699.         break;
  700.     case NBOUND:
  701.     case BOUND:
  702.         if (locinput == regbol)    /* was last char in word? */
  703.         ln = isALNUM(regprev);
  704.         else 
  705.         ln = isALNUM(locinput[-1]);
  706.         n = isALNUM(nextchar); /* is next char in word? */
  707.         if ((ln == n) == (OP(scan) == BOUND))
  708.         sayNO;
  709.         break;
  710.     case SPACE:
  711.         if (!nextchar && locinput >= regeol)
  712.         sayNO;
  713.         if (!isSPACE(nextchar))
  714.         sayNO;
  715.         nextchar = *++locinput;
  716.         break;
  717.     case NSPACE:
  718.         if (!nextchar)
  719.         sayNO;
  720.         if (isSPACE(nextchar))
  721.         sayNO;
  722.         nextchar = *++locinput;
  723.         break;
  724.     case DIGIT:
  725.         if (!isDIGIT(nextchar))
  726.         sayNO;
  727.         nextchar = *++locinput;
  728.         break;
  729.     case NDIGIT:
  730.         if (!nextchar && locinput >= regeol)
  731.         sayNO;
  732.         if (isDIGIT(nextchar))
  733.         sayNO;
  734.         nextchar = *++locinput;
  735.         break;
  736.     case REF:
  737.         n = ARG1(scan);  /* which paren pair */
  738.         s = regstartp[n];
  739.         if (!s)
  740.         sayNO;
  741.         if (!regendp[n])
  742.         sayNO;
  743.         if (s == regendp[n])
  744.         break;
  745.         /* Inline the first character, for speed. */
  746.         if (*s != nextchar)
  747.         sayNO;
  748.         ln = regendp[n] - s;
  749.         if (locinput + ln > regeol)
  750.         sayNO;
  751.         if (ln > 1 && bcmp(s, locinput, ln) != 0)
  752.         sayNO;
  753.         locinput += ln;
  754.         nextchar = *locinput;
  755.         break;
  756.  
  757.     case NOTHING:
  758.         break;
  759.     case BACK:
  760.         break;
  761.     case OPEN:
  762.         n = ARG1(scan);  /* which paren pair */
  763.         regstartp[n] = locinput;
  764.         if (n > regsize)
  765.         regsize = n;
  766.         break;
  767.     case CLOSE:
  768.         n = ARG1(scan);  /* which paren pair */
  769.         regendp[n] = locinput;
  770.         if (n > *reglastparen)
  771.         *reglastparen = n;
  772.         break;
  773.     case CURLYX: {
  774.         CURCUR cc;
  775.         CHECKPOINT cp = savestack_ix;
  776.         cc.oldcc = regcc;
  777.         regcc = &cc;
  778.         cc.parenfloor = *reglastparen;
  779.         cc.cur = -1;
  780.         cc.min = ARG1(scan);
  781.         cc.max  = ARG2(scan);
  782.         cc.scan = NEXTOPER(scan) + 4;
  783.         cc.next = next;
  784.         cc.minmod = minmod;
  785.         cc.lastloc = 0;
  786.         reginput = locinput;
  787.         n = regmatch(PREVOPER(next));    /* start on the WHILEM */
  788.         regcpblow(cp);
  789.         regcc = cc.oldcc;
  790.         saySAME(n);
  791.         }
  792.         /* NOT REACHED */
  793.     case WHILEM: {
  794.         /*
  795.          * This is really hard to understand, because after we match
  796.          * what we're trying to match, we must make sure the rest of
  797.          * the RE is going to match for sure, and to do that we have
  798.          * to go back UP the parse tree by recursing ever deeper.  And
  799.          * if it fails, we have to reset our parent's current state
  800.          * that we can try again after backing off.
  801.          */
  802.  
  803.         CURCUR* cc = regcc;
  804.         n = cc->cur + 1;    /* how many we know we matched */
  805.         reginput = locinput;
  806.  
  807. #ifdef DEBUGGING
  808.         if (regnarrate)
  809.             fprintf(stderr, "%*s  %d  %lx\n", regindent*2, "",
  810.             n, (long)cc);
  811. #endif
  812.  
  813.         /* If degenerate scan matches "", assume scan done. */
  814.  
  815.         if (locinput == cc->lastloc) {
  816.             regcc = cc->oldcc;
  817.             ln = regcc->cur;
  818.             if (regmatch(cc->next))
  819.             sayYES;
  820.             regcc->cur = ln;
  821.             regcc = cc;
  822.             sayNO;
  823.         }
  824.  
  825.         /* First just match a string of min scans. */
  826.  
  827.         if (n < cc->min) {
  828.             cc->cur = n;
  829.             cc->lastloc = locinput;
  830.             if (regmatch(cc->scan))
  831.             sayYES;
  832.             cc->cur = n - 1;
  833.             sayNO;
  834.         }
  835.  
  836.         /* Prefer next over scan for minimal matching. */
  837.  
  838.         if (cc->minmod) {
  839.             regcc = cc->oldcc;
  840.             ln = regcc->cur;
  841.             if (regmatch(cc->next))
  842.             sayYES;    /* All done. */
  843.             regcc->cur = ln;
  844.             regcc = cc;
  845.  
  846.             if (n >= cc->max)    /* Maximum greed exceeded? */
  847.             sayNO;
  848.  
  849.             /* Try scanning more and see if it helps. */
  850.             reginput = locinput;
  851.             cc->cur = n;
  852.             cc->lastloc = locinput;
  853.             if (regmatch(cc->scan))
  854.             sayYES;
  855.             cc->cur = n - 1;
  856.             sayNO;
  857.         }
  858.  
  859.         /* Prefer scan over next for maximal matching. */
  860.  
  861.         if (n < cc->max) {    /* More greed allowed? */
  862.             regcppush(cc->parenfloor);
  863.             cc->cur = n;
  864.             cc->lastloc = locinput;
  865.             if (regmatch(cc->scan))
  866.             sayYES;
  867.             regcppop();        /* Restore some previous $<digit>s? */
  868.             reginput = locinput;
  869.         }
  870.  
  871.         /* Failed deeper matches of scan, so see if this one works. */
  872.         regcc = cc->oldcc;
  873.         ln = regcc->cur;
  874.         if (regmatch(cc->next))
  875.             sayYES;
  876.         regcc->cur = ln;
  877.         regcc = cc;
  878.         cc->cur = n - 1;
  879.         sayNO;
  880.         }
  881.         /* NOT REACHED */
  882.     case BRANCH: {
  883.         if (OP(next) != BRANCH)      /* No choice. */
  884.             next = NEXTOPER(scan);/* Avoid recursion. */
  885.         else {
  886.             int lastparen = *reglastparen;
  887.             do {
  888.             reginput = locinput;
  889.             if (regmatch(NEXTOPER(scan)))
  890.                 sayYES;
  891.             for (n = *reglastparen; n > lastparen; n--)
  892.                 regendp[n] = 0;
  893.             *reglastparen = n;
  894.                 
  895. #ifdef REGALIGN
  896.             /*SUPPRESS 560*/
  897.             if (n = NEXT(scan))
  898.                 scan += n;
  899.             else
  900.                 scan = NULL;
  901. #else
  902.             scan = regnext(scan);
  903. #endif
  904.             } while (scan != NULL && OP(scan) == BRANCH);
  905.             sayNO;
  906.             /* NOTREACHED */
  907.         }
  908.         }
  909.         break;
  910.     case MINMOD:
  911.         minmod = 1;
  912.         break;
  913.     case CURLY:
  914.         ln = ARG1(scan);  /* min to match */
  915.         n  = ARG2(scan);  /* max to match */
  916.         scan = NEXTOPER(scan) + 4;
  917.         goto repeat;
  918.     case STAR:
  919.         ln = 0;
  920.         n = 32767;
  921.         scan = NEXTOPER(scan);
  922.         goto repeat;
  923.     case PLUS:
  924.         /*
  925.         * Lookahead to avoid useless match attempts
  926.         * when we know what character comes next.
  927.         */
  928.         ln = 1;
  929.         n = 32767;
  930.         scan = NEXTOPER(scan);
  931.       repeat:
  932.         if (OP(next) == EXACTLY)
  933.         nextchar = *(OPERAND(next)+1);
  934.         else
  935.         nextchar = -1000;
  936.         reginput = locinput;
  937.         if (minmod) {
  938.         minmod = 0;
  939.         if (ln && regrepeat(scan, ln) < ln)
  940.             sayNO;
  941.         while (n >= ln || (n == 32767 && ln > 0)) { /* ln overflow ? */
  942.             /* If it could work, try it. */
  943.             if (nextchar == -1000 || *reginput == nextchar)
  944.             if (regmatch(next))
  945.                 sayYES;
  946.             /* Couldn't or didn't -- back up. */
  947.             reginput = locinput + ln;
  948.             if (regrepeat(scan, 1)) {
  949.             ln++;
  950.             reginput = locinput + ln;
  951.             }
  952.             else
  953.             sayNO;
  954.         }
  955.         }
  956.         else {
  957.         n = regrepeat(scan, n);
  958.         if (ln < n && regkind[(U8)OP(next)] == EOL &&
  959.             (!multiline || OP(next) == SEOL))
  960.             ln = n;            /* why back off? */
  961.         while (n >= ln) {
  962.             /* If it could work, try it. */
  963.             if (nextchar == -1000 || *reginput == nextchar)
  964.             if (regmatch(next))
  965.                 sayYES;
  966.             /* Couldn't or didn't -- back up. */
  967.             n--;
  968.             reginput = locinput + n;
  969.         }
  970.         }
  971.         sayNO;
  972.     case SUCCEED:
  973.     case END:
  974.         reginput = locinput;    /* put where regtry can find it */
  975.         sayYES;            /* Success! */
  976.     case IFMATCH:
  977.         reginput = locinput;
  978.         scan = NEXTOPER(scan);
  979.         if (!regmatch(scan))
  980.         sayNO;
  981.         break;
  982.     case UNLESSM:
  983.         reginput = locinput;
  984.         scan = NEXTOPER(scan);
  985.         if (regmatch(scan))
  986.         sayNO;
  987.         break;
  988.     default:
  989.         fprintf(stderr, "%x %d\n",(unsigned)scan,scan[1]);
  990.         FAIL("regexp memory corruption");
  991.     }
  992.     scan = next;
  993.     }
  994.  
  995.     /*
  996.     * We get here only if there's trouble -- normally "case END" is
  997.     * the terminating point.
  998.     */
  999.     FAIL("corrupted regexp pointers");
  1000.     /*NOTREACHED*/
  1001.     sayNO;
  1002.  
  1003. yes:
  1004. #ifdef DEBUGGING
  1005.     regindent--;
  1006. #endif
  1007.     return 1;
  1008.  
  1009. no:
  1010. #ifdef DEBUGGING
  1011.     regindent--;
  1012. #endif
  1013.     return 0;
  1014. }
  1015.  
  1016. /*
  1017.  - regrepeat - repeatedly match something simple, report how many
  1018.  */
  1019. /*
  1020.  * [This routine now assumes that it will only match on things of length 1.
  1021.  * That was true before, but now we assume scan - reginput is the count,
  1022.  * rather than incrementing count on every character.]
  1023.  */
  1024. static I32
  1025. regrepeat(p, max)
  1026. char *p;
  1027. I32 max;
  1028. {
  1029.     register char *scan;
  1030.     register char *opnd;
  1031.     register I32 c;
  1032.     register char *loceol = regeol;
  1033.  
  1034.     scan = reginput;
  1035.     if (max != 32767 && max < loceol - scan)
  1036.       loceol = scan + max;
  1037.     opnd = OPERAND(p);
  1038.     switch (OP(p)) {
  1039.     case ANY:
  1040.     while (scan < loceol && *scan != '\n')
  1041.         scan++;
  1042.     break;
  1043.     case SANY:
  1044.     scan = loceol;
  1045.     break;
  1046.     case EXACTLY:        /* length of string is 1 */
  1047.     opnd++;
  1048.     while (scan < loceol && *opnd == *scan)
  1049.         scan++;
  1050.     break;
  1051.     case ANYOF:
  1052.     c = UCHARAT(scan);
  1053.     while (scan < loceol && !(opnd[c >> 3] & (1 << (c & 7)))) {
  1054.         scan++;
  1055.         c = UCHARAT(scan);
  1056.     }
  1057.     break;
  1058.     case ALNUM:
  1059.     while (scan < loceol && isALNUM(*scan))
  1060.         scan++;
  1061.     break;
  1062.     case NALNUM:
  1063.     while (scan < loceol && !isALNUM(*scan))
  1064.         scan++;
  1065.     break;
  1066.     case SPACE:
  1067.     while (scan < loceol && isSPACE(*scan))
  1068.         scan++;
  1069.     break;
  1070.     case NSPACE:
  1071.     while (scan < loceol && !isSPACE(*scan))
  1072.         scan++;
  1073.     break;
  1074.     case DIGIT:
  1075.     while (scan < loceol && isDIGIT(*scan))
  1076.         scan++;
  1077.     break;
  1078.     case NDIGIT:
  1079.     while (scan < loceol && !isDIGIT(*scan))
  1080.         scan++;
  1081.     break;
  1082.     default:        /* Called on something of 0 width. */
  1083.     break;        /* So match right here or not at all. */
  1084.     }
  1085.  
  1086.     c = scan - reginput;
  1087.     reginput = scan;
  1088.  
  1089.     return(c);
  1090. }
  1091.  
  1092. /*
  1093.  - regnext - dig the "next" pointer out of a node
  1094.  *
  1095.  * [Note, when REGALIGN is defined there are two places in regmatch()
  1096.  * that bypass this code for speed.]
  1097.  */
  1098. char *
  1099. regnext(p)
  1100. register char *p;
  1101. {
  1102.     register I32 offset;
  1103.  
  1104.     if (p == ®dummy)
  1105.     return(NULL);
  1106.  
  1107.     offset = NEXT(p);
  1108.     if (offset == 0)
  1109.     return(NULL);
  1110.  
  1111. #ifdef REGALIGN
  1112.     return(p+offset);
  1113. #else
  1114.     if (OP(p) == BACK)
  1115.     return(p-offset);
  1116.     else
  1117.     return(p+offset);
  1118. #endif
  1119. }
  1120.