Annotation of coherent/e/bin/pax/regexp.c, revision 1.1

1.1     ! root        1: /* $Source: /src386/usr/bin/pax/regexp.c,v $
        !             2:  *
        !             3:  * $Revision: 1.1 $
        !             4:  *
        !             5:  * regexp.c - regular expression matching
        !             6:  *
        !             7:  * DESCRIPTION
        !             8:  *
        !             9:  *     Underneath the reformatting and comment blocks which were added to 
        !            10:  *     make it consistent with the rest of the code, you will find a
        !            11:  *     modified version of Henry Specer's regular expression library.
        !            12:  *     Henry's functions were modified to provide the minimal regular
        !            13:  *     expression matching, as required by P1003.  Henry's code was
        !            14:  *     copyrighted, and copy of the copyright message and restrictions
        !            15:  *     are provided, verbatim, below:
        !            16:  *
        !            17:  *     Copyright (c) 1986 by University of Toronto.
        !            18:  *     Written by Henry Spencer.  Not derived from licensed software.
        !            19:  *
        !            20:  *     Permission is granted to anyone to use this software for any
        !            21:  *     purpose on any computer system, and to redistribute it freely,
        !            22:  *     subject to the following restrictions:
        !            23:  *
        !            24:  *     1. The author is not responsible for the consequences of use of
        !            25:  *         this software, no matter how awful, even if they arise
        !            26:  *        from defects in it.
        !            27:  *
        !            28:  *     2. The origin of this software must not be misrepresented, either
        !            29:  *        by explicit claim or by omission.
        !            30:  *
        !            31:  *     3. Altered versions must be plainly marked as such, and must not
        !            32:  *        be misrepresented as being the original software.
        !            33:  *
        !            34:  *     Beware that some of this code is subtly aware of the way operator
        !            35:  *     precedence is structured in regular expressions.  Serious changes in
        !            36:  *     regular-expression syntax might require a total rethink.
        !            37:  *
        !            38:  * AUTHORS
        !            39:  *
        !            40:  *     Mark H. Colburn, NAPS International ([email protected])
        !            41:  *     Henry Spencer, University of Torronto ([email protected])
        !            42:  *
        !            43:  * Sponsored by The USENIX Association for public distribution. 
        !            44:  *
        !            45:  * $Log:       regexp.c,v $
        !            46:  * Revision 1.1  92/08/28  08:02:59  bin
        !            47:  * Initial revision
        !            48:  * 
        !            49:  * Revision 1.1  89/02/14  16:48:42  jep
        !            50:  * Initial revision
        !            51:  * 
        !            52:  * Revision 1.1  88/12/23  18:02:32  mark
        !            53:  * Initial revision
        !            54:  * 
        !            55:  */
        !            56: 
        !            57: /* Headers */
        !            58: 
        !            59: #include "pax.h"
        !            60: 
        !            61: #ifndef lint
        !            62: static char    *Ident = "$Id: regexp.c,v 1.1 92/08/28 08:02:59 bin Exp Locker: bin $";
        !            63: #endif
        !            64: 
        !            65: 
        !            66: /*
        !            67:  * The "internal use only" fields in regexp.h are present to pass info from
        !            68:  * compile to execute that permits the execute phase to run lots faster on
        !            69:  * simple cases.  They are:
        !            70:  *
        !            71:  * regstart    char that must begin a match; '\0' if none obvious
        !            72:  * reganch     is the match anchored (at beginning-of-line only)?
        !            73:  * regmust     string (pointer into program) that match must include, or NULL
        !            74:  * regmlen     length of regmust string
        !            75:  *
        !            76:  * Regstart and reganch permit very fast decisions on suitable starting points
        !            77:  * for a match, cutting down the work a lot.  Regmust permits fast rejection
        !            78:  * of lines that cannot possibly match.  The regmust tests are costly enough
        !            79:  * that regcomp() supplies a regmust only if the r.e. contains something
        !            80:  * potentially expensive (at present, the only such thing detected is * or +
        !            81:  * at the start of the r.e., which can involve a lot of backup).  Regmlen is
        !            82:  * supplied because the test in regexec() needs it and regcomp() is computing
        !            83:  * it anyway.
        !            84:  */
        !            85: 
        !            86: /*
        !            87:  * Structure for regexp "program".  This is essentially a linear encoding
        !            88:  * of a nondeterministic finite-state machine (aka syntax charts or
        !            89:  * "railroad normal form" in parsing technology).  Each node is an opcode
        !            90:  * plus a "nxt" pointer, possibly plus an operand.  "Nxt" pointers of
        !            91:  * all nodes except BRANCH implement concatenation; a "nxt" pointer with
        !            92:  * a BRANCH on both ends of it is connecting two alternatives.  (Here we
        !            93:  * have one of the subtle syntax dependencies:  an individual BRANCH (as
        !            94:  * opposed to a collection of them) is never concatenated with anything
        !            95:  * because of operator precedence.)  The operand of some types of node is
        !            96:  * a literal string; for others, it is a node leading into a sub-FSM.  In
        !            97:  * particular, the operand of a BRANCH node is the first node of the branch.
        !            98:  * (NB this is *not* a tree structure:  the tail of the branch connects
        !            99:  * to the thing following the set of BRANCHes.)  The opcodes are:
        !           100:  */
        !           101: 
        !           102: /* definition  number  opnd?   meaning */
        !           103: #define        END     0               /* no   End of program. */
        !           104: #define        BOL     1               /* no   Match "" at beginning of line. */
        !           105: #define        EOL     2               /* no   Match "" at end of line. */
        !           106: #define        ANY     3               /* no   Match any one character. */
        !           107: #define        ANYOF   4               /* str  Match any character in this string. */
        !           108: #define        ANYBUT  5               /* str  Match any character not in this
        !           109:                                 * string. */
        !           110: #define        BRANCH  6               /* node Match this alternative, or the
        !           111:                                 * nxt... */
        !           112: #define        BACK    7               /* no   Match "", "nxt" ptr points backward. */
        !           113: #define        EXACTLY 8               /* str  Match this string. */
        !           114: #define        NOTHING 9               /* no   Match empty string. */
        !           115: #define        STAR    10              /* node Match this (simple) thing 0 or more
        !           116:                                 * times. */
        !           117: #define        OPEN    20              /* no   Mark this point in input as start of
        !           118:                                 * #n. */
        !           119:  /* OPEN+1 is number 1, etc. */
        !           120: #define        CLOSE   30              /* no   Analogous to OPEN. */
        !           121: 
        !           122: /*
        !           123:  * Opcode notes:
        !           124:  *
        !           125:  * BRANCH      The set of branches constituting a single choice are hooked
        !           126:  *             together with their "nxt" pointers, since precedence prevents
        !           127:  *             anything being concatenated to any individual branch.  The
        !           128:  *             "nxt" pointer of the last BRANCH in a choice points to the
        !           129:  *             thing following the whole choice.  This is also where the
        !           130:  *             final "nxt" pointer of each individual branch points; each
        !           131:  *             branch starts with the operand node of a BRANCH node.
        !           132:  *
        !           133:  * BACK                Normal "nxt" pointers all implicitly point forward; BACK
        !           134:  *             exists to make loop structures possible.
        !           135:  *
        !           136:  * STAR                complex '*', are implemented as circular BRANCH structures 
        !           137:  *             using BACK.  Simple cases (one character per match) are 
        !           138:  *             implemented with STAR for speed and to minimize recursive 
        !           139:  *             plunges.
        !           140:  *
        !           141:  * OPEN,CLOSE  ...are numbered at compile time.
        !           142:  */
        !           143: 
        !           144: /*
        !           145:  * A node is one char of opcode followed by two chars of "nxt" pointer.
        !           146:  * "Nxt" pointers are stored as two 8-bit pieces, high order first.  The
        !           147:  * value is a positive offset from the opcode of the node containing it.
        !           148:  * An operand, if any, simply follows the node.  (Note that much of the
        !           149:  * code generation knows about this implicit relationship.)
        !           150:  *
        !           151:  * Using two bytes for the "nxt" pointer is vast overkill for most things,
        !           152:  * but allows patterns to get big without disasters.
        !           153:  */
        !           154: #define        OP(p)   (*(p))
        !           155: #define        NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
        !           156: #define        OPERAND(p)      ((p) + 3)
        !           157: 
        !           158: /*
        !           159:  * Utility definitions.
        !           160:  */
        !           161: 
        !           162: #define        FAIL(m) { regerror(m); return(NULL); }
        !           163: #define        ISMULT(c)       ((c) == '*')
        !           164: #define        META    "^$.[()|*\\"
        !           165: #ifndef CHARBITS
        !           166: #define        UCHARAT(p)      ((int)*(unsigned char *)(p))
        !           167: #else
        !           168: #define        UCHARAT(p)      ((int)*(p)&CHARBITS)
        !           169: #endif
        !           170: 
        !           171: /*
        !           172:  * Flags to be passed up and down.
        !           173:  */
        !           174: #define        HASWIDTH        01      /* Known never to match null string. */
        !           175: #define        SIMPLE          02      /* Simple enough to be STAR operand. */
        !           176: #define        SPSTART         04      /* Starts with * */
        !           177: #define        WORST           0       /* Worst case. */
        !           178: 
        !           179: /*
        !           180:  * Global work variables for regcomp().
        !           181:  */
        !           182: static char    *regparse;      /* Input-scan pointer. */
        !           183: static int      regnpar;       /* () count. */
        !           184: static char     regdummy;
        !           185: static char    *regcode;       /* Code-emit pointer; &regdummy = don't. */
        !           186: static long     regsize;       /* Code size. */
        !           187: 
        !           188: /*
        !           189:  * Forward declarations for regcomp()'s friends.
        !           190:  */
        !           191: #ifndef STATIC
        !           192: #define        STATIC  static
        !           193: #endif
        !           194: STATIC char    *reg();
        !           195: STATIC char    *regbranch();
        !           196: STATIC char    *regpiece();
        !           197: STATIC char    *regatom();
        !           198: STATIC char    *regnode();
        !           199: STATIC char    *regnext();
        !           200: STATIC void     regc();
        !           201: STATIC void     reginsert();
        !           202: STATIC void     regtail();
        !           203: STATIC void     regoptail();
        !           204: #ifdef STRCSPN
        !           205: STATIC int      strcspn();
        !           206: #endif
        !           207: 
        !           208: /*
        !           209:  - regcomp - compile a regular expression into internal code
        !           210:  *
        !           211:  * We can't allocate space until we know how big the compiled form will be,
        !           212:  * but we can't compile it (and thus know how big it is) until we've got a
        !           213:  * place to put the code.  So we cheat:  we compile it twice, once with code
        !           214:  * generation turned off and size counting turned on, and once "for real".
        !           215:  * This also means that we don't allocate space until we are sure that the
        !           216:  * thing really will compile successfully, and we never have to move the
        !           217:  * code and thus invalidate pointers into it.  (Note that it has to be in
        !           218:  * one piece because free() must be able to free it all.)
        !           219:  *
        !           220:  * Beware that the optimization-preparation code in here knows about some
        !           221:  * of the structure of the compiled regexp.
        !           222:  */
        !           223: regexp *regcomp(exp)
        !           224: char           *exp;
        !           225: {
        !           226:     register regexp *r;
        !           227:     register char  *scan;
        !           228:     register char  *longest;
        !           229:     register int    len;
        !           230:     int             flags;
        !           231:     extern char    *malloc();
        !           232: 
        !           233:     if (exp == (char *)NULL)
        !           234:        FAIL("NULL argument");
        !           235: 
        !           236:     /* First pass: determine size, legality. */
        !           237:     regparse = exp;
        !           238:     regnpar = 1;
        !           239:     regsize = 0L;
        !           240:     regcode = &regdummy;
        !           241:     regc(MAGIC);
        !           242:     if (reg(0, &flags) == (char *)NULL)
        !           243:        return ((regexp *)NULL);
        !           244: 
        !           245:     /* Small enough for pointer-storage convention? */
        !           246:     if (regsize >= 32767L)     /* Probably could be 65535L. */
        !           247:        FAIL("regexp too big");
        !           248: 
        !           249:     /* Allocate space. */
        !           250:     r = (regexp *) malloc(sizeof(regexp) + (unsigned) regsize);
        !           251:     if (r == (regexp *) NULL)
        !           252:        FAIL("out of space");
        !           253: 
        !           254:     /* Second pass: emit code. */
        !           255:     regparse = exp;
        !           256:     regnpar = 1;
        !           257:     regcode = r->program;
        !           258:     regc(MAGIC);
        !           259:     if (reg(0, &flags) == NULL)
        !           260:        return ((regexp *) NULL);
        !           261: 
        !           262:     /* Dig out information for optimizations. */
        !           263:     r->regstart = '\0';                /* Worst-case defaults. */
        !           264:     r->reganch = 0;
        !           265:     r->regmust = NULL;
        !           266:     r->regmlen = 0;
        !           267:     scan = r->program + 1;     /* First BRANCH. */
        !           268:     if (OP(regnext(scan)) == END) {    /* Only one top-level choice. */
        !           269:        scan = OPERAND(scan);
        !           270: 
        !           271:        /* Starting-point info. */
        !           272:        if (OP(scan) == EXACTLY)
        !           273:            r->regstart = *OPERAND(scan);
        !           274:        else if (OP(scan) == BOL)
        !           275:            r->reganch++;
        !           276: 
        !           277:        /*
        !           278:         * If there's something expensive in the r.e., find the longest
        !           279:         * literal string that must appear and make it the regmust.  Resolve
        !           280:         * ties in favor of later strings, since the regstart check works
        !           281:         * with the beginning of the r.e. and avoiding duplication
        !           282:         * strengthens checking.  Not a strong reason, but sufficient in the
        !           283:         * absence of others. 
        !           284:         */
        !           285:        if (flags & SPSTART) {
        !           286:            longest = NULL;
        !           287:            len = 0;
        !           288:            for (; scan != NULL; scan = regnext(scan))
        !           289:                if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
        !           290:                    longest = OPERAND(scan);
        !           291:                    len = strlen(OPERAND(scan));
        !           292:                }
        !           293:            r->regmust = longest;
        !           294:            r->regmlen = len;
        !           295:        }
        !           296:     }
        !           297:     return (r);
        !           298: }
        !           299: 
        !           300: /*
        !           301:  - reg - regular expression, i.e. main body or parenthesized thing
        !           302:  *
        !           303:  * Caller must absorb opening parenthesis.
        !           304:  *
        !           305:  * Combining parenthesis handling with the base level of regular expression
        !           306:  * is a trifle forced, but the need to tie the tails of the branches to what
        !           307:  * follows makes it hard to avoid.
        !           308:  */
        !           309: static char *reg(paren, flagp)
        !           310: int             paren;         /* Parenthesized? */
        !           311: int            *flagp;
        !           312: {
        !           313:     register char  *ret;
        !           314:     register char  *br;
        !           315:     register char  *ender;
        !           316:     register int    parno;
        !           317:     int             flags;
        !           318: 
        !           319:     *flagp = HASWIDTH;         /* Tentatively. */
        !           320: 
        !           321:     /* Make an OPEN node, if parenthesized. */
        !           322:     if (paren) {
        !           323:        if (regnpar >= NSUBEXP)
        !           324:            FAIL("too many ()");
        !           325:        parno = regnpar;
        !           326:        regnpar++;
        !           327:        ret = regnode(OPEN + parno);
        !           328:     } else
        !           329:        ret = (char *)NULL;
        !           330: 
        !           331:     /* Pick up the branches, linking them together. */
        !           332:     br = regbranch(&flags);
        !           333:     if (br == (char *)NULL)
        !           334:        return ((char *)NULL);
        !           335:     if (ret != (char *)NULL)
        !           336:        regtail(ret, br);       /* OPEN -> first. */
        !           337:     else
        !           338:        ret = br;
        !           339:     if (!(flags & HASWIDTH))
        !           340:        *flagp &= ~HASWIDTH;
        !           341:     *flagp |= flags & SPSTART;
        !           342:     while (*regparse == '|') {
        !           343:        regparse++;
        !           344:        br = regbranch(&flags);
        !           345:        if (br == (char *)NULL)
        !           346:            return ((char *)NULL);
        !           347:        regtail(ret, br);       /* BRANCH -> BRANCH. */
        !           348:        if (!(flags & HASWIDTH))
        !           349:            *flagp &= ~HASWIDTH;
        !           350:        *flagp |= flags & SPSTART;
        !           351:     }
        !           352: 
        !           353:     /* Make a closing node, and hook it on the end. */
        !           354:     ender = regnode((paren) ? CLOSE + parno : END);
        !           355:     regtail(ret, ender);
        !           356: 
        !           357:     /* Hook the tails of the branches to the closing node. */
        !           358:     for (br = ret; br != (char *)NULL; br = regnext(br))
        !           359:        regoptail(br, ender);
        !           360: 
        !           361:     /* Check for proper termination. */
        !           362:     if (paren && *regparse++ != ')') {
        !           363:        FAIL("unmatched ()");
        !           364:     } else if (!paren && *regparse != '\0') {
        !           365:        if (*regparse == ')') {
        !           366:            FAIL("unmatched ()");
        !           367:        } else
        !           368:            FAIL("junk on end");/* "Can't happen". */
        !           369:        /* NOTREACHED */
        !           370:     }
        !           371:     return (ret);
        !           372: }
        !           373: 
        !           374: /*
        !           375:  - regbranch - one alternative of an | operator
        !           376:  *
        !           377:  * Implements the concatenation operator.
        !           378:  */
        !           379: static char  *regbranch(flagp)
        !           380: int            *flagp;
        !           381: {
        !           382:     register char  *ret;
        !           383:     register char  *chain;
        !           384:     register char  *latest;
        !           385:     int             flags;
        !           386: 
        !           387:     *flagp = WORST;            /* Tentatively. */
        !           388: 
        !           389:     ret = regnode(BRANCH);
        !           390:     chain = (char *)NULL;
        !           391:     while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
        !           392:        latest = regpiece(&flags);
        !           393:        if (latest == (char *)NULL)
        !           394:            return ((char *)NULL);
        !           395:        *flagp |= flags & HASWIDTH;
        !           396:        if (chain == (char *)NULL)      /* First piece. */
        !           397:            *flagp |= flags & SPSTART;
        !           398:        else
        !           399:            regtail(chain, latest);
        !           400:        chain = latest;
        !           401:     }
        !           402:     if (chain == (char *)NULL)         /* Loop ran zero times. */
        !           403:        regnode(NOTHING);
        !           404: 
        !           405:     return (ret);
        !           406: }
        !           407: 
        !           408: /*
        !           409:  - regpiece - something followed by possible [*]
        !           410:  *
        !           411:  * Note that the branching code sequence used for * is somewhat optimized:  
        !           412:  * they use the same NOTHING node as both the endmarker for their branch 
        !           413:  * list and the body of the last branch.  It might seem that this node could 
        !           414:  * be dispensed with entirely, but the endmarker role is not redundant.
        !           415:  */
        !           416: static char *regpiece(flagp)
        !           417: int            *flagp;
        !           418: {
        !           419:     register char  *ret;
        !           420:     register char   op;
        !           421:     register char  *nxt;
        !           422:     int             flags;
        !           423: 
        !           424:     ret = regatom(&flags);
        !           425:     if (ret == (char *)NULL)
        !           426:        return ((char *)NULL);
        !           427: 
        !           428:     op = *regparse;
        !           429:     if (!ISMULT(op)) {
        !           430:        *flagp = flags;
        !           431:        return (ret);
        !           432:     }
        !           433:     if (!(flags & HASWIDTH))
        !           434:        FAIL("* operand could be empty");
        !           435:     *flagp = (WORST | SPSTART);
        !           436: 
        !           437:     if (op == '*' && (flags & SIMPLE))
        !           438:        reginsert(STAR, ret);
        !           439:     else if (op == '*') {
        !           440:        /* Emit x* as (x&|), where & means "self". */
        !           441:        reginsert(BRANCH, ret); /* Either x */
        !           442:        regoptail(ret, regnode(BACK));  /* and loop */
        !           443:        regoptail(ret, ret);    /* back */
        !           444:        regtail(ret, regnode(BRANCH));  /* or */
        !           445:        regtail(ret, regnode(NOTHING)); /* null. */
        !           446:     } 
        !           447:     regparse++;
        !           448:     if (ISMULT(*regparse))
        !           449:        FAIL("nested *");
        !           450: 
        !           451:     return (ret);
        !           452: }
        !           453: 
        !           454: /*
        !           455:  - regatom - the lowest level
        !           456:  *
        !           457:  * Optimization:  gobbles an entire sequence of ordinary characters so that
        !           458:  * it can turn them into a single node, which is smaller to store and
        !           459:  * faster to run.  Backslashed characters are exceptions, each becoming a
        !           460:  * separate node; the code is simpler that way and it's not worth fixing.
        !           461:  */
        !           462: static char *regatom(flagp)
        !           463: int            *flagp;
        !           464: {
        !           465:     register char  *ret;
        !           466:     int             flags;
        !           467: 
        !           468:     *flagp = WORST;            /* Tentatively. */
        !           469: 
        !           470:     switch (*regparse++) {
        !           471:     case '^':
        !           472:        ret = regnode(BOL);
        !           473:        break;
        !           474:     case '$':
        !           475:        ret = regnode(EOL);
        !           476:        break;
        !           477:     case '.':
        !           478:        ret = regnode(ANY);
        !           479:        *flagp |= HASWIDTH | SIMPLE;
        !           480:        break;
        !           481:     case '[':{
        !           482:            register int    class;
        !           483:            register int    classend;
        !           484: 
        !           485:            if (*regparse == '^') {     /* Complement of range. */
        !           486:                ret = regnode(ANYBUT);
        !           487:                regparse++;
        !           488:            } else
        !           489:                ret = regnode(ANYOF);
        !           490:            if (*regparse == ']' || *regparse == '-')
        !           491:                regc(*regparse++);
        !           492:            while (*regparse != '\0' && *regparse != ']') {
        !           493:                if (*regparse == '-') {
        !           494:                    regparse++;
        !           495:                    if (*regparse == ']' || *regparse == '\0')
        !           496:                        regc('-');
        !           497:                    else {
        !           498:                        class = UCHARAT(regparse - 2) + 1;
        !           499:                        classend = UCHARAT(regparse);
        !           500:                        if (class > classend + 1)
        !           501:                            FAIL("invalid [] range");
        !           502:                        for (; class <= classend; class++)
        !           503:                            regc(class);
        !           504:                        regparse++;
        !           505:                    }
        !           506:                } else
        !           507:                    regc(*regparse++);
        !           508:            }
        !           509:            regc('\0');
        !           510:            if (*regparse != ']')
        !           511:                FAIL("unmatched []");
        !           512:            regparse++;
        !           513:            *flagp |= HASWIDTH | SIMPLE;
        !           514:        }
        !           515:        break;
        !           516:     case '(':
        !           517:        ret = reg(1, &flags);
        !           518:        if (ret == (char *)NULL)
        !           519:            return ((char *)NULL);
        !           520:        *flagp |= flags & (HASWIDTH | SPSTART);
        !           521:        break;
        !           522:     case '\0':
        !           523:     case '|':
        !           524:     case ')':
        !           525:        FAIL("internal urp");   /* Supposed to be caught earlier. */
        !           526:        break;
        !           527:     case '*':
        !           528:        FAIL("* follows nothing");
        !           529:        break;
        !           530:     case '\\':
        !           531:        if (*regparse == '\0')
        !           532:            FAIL("trailing \\");
        !           533:        ret = regnode(EXACTLY);
        !           534:        regc(*regparse++);
        !           535:        regc('\0');
        !           536:        *flagp |= HASWIDTH | SIMPLE;
        !           537:        break;
        !           538:     default:{
        !           539:            register int    len;
        !           540:            register char   ender;
        !           541: 
        !           542:            regparse--;
        !           543:            len = strcspn(regparse, META);
        !           544:            if (len <= 0)
        !           545:                FAIL("internal disaster");
        !           546:            ender = *(regparse + len);
        !           547:            if (len > 1 && ISMULT(ender))
        !           548:                len--;          /* Back off clear of * operand. */
        !           549:            *flagp |= HASWIDTH;
        !           550:            if (len == 1)
        !           551:                *flagp |= SIMPLE;
        !           552:            ret = regnode(EXACTLY);
        !           553:            while (len > 0) {
        !           554:                regc(*regparse++);
        !           555:                len--;
        !           556:            }
        !           557:            regc('\0');
        !           558:        }
        !           559:        break;
        !           560:     }
        !           561: 
        !           562:     return (ret);
        !           563: }
        !           564: 
        !           565: /*
        !           566:  - regnode - emit a node
        !           567:  */
        !           568: static char *regnode(op)
        !           569: char            op;
        !           570: {
        !           571:     register char  *ret;
        !           572:     register char  *ptr;
        !           573: 
        !           574:     ret = regcode;
        !           575:     if (ret == &regdummy) {
        !           576:        regsize += 3;
        !           577:        return (ret);
        !           578:     }
        !           579:     ptr = ret;
        !           580:     *ptr++ = op;
        !           581:     *ptr++ = '\0';             /* Null "nxt" pointer. */
        !           582:     *ptr++ = '\0';
        !           583:     regcode = ptr;
        !           584: 
        !           585:     return (ret);
        !           586: }
        !           587: 
        !           588: /*
        !           589:  - regc - emit (if appropriate) a byte of code
        !           590:  */
        !           591: static void regc(b)
        !           592: char            b;
        !           593: {
        !           594:     if (regcode != &regdummy)
        !           595:        *regcode++ = b;
        !           596:     else
        !           597:        regsize++;
        !           598: }
        !           599: 
        !           600: /*
        !           601:  - reginsert - insert an operator in front of already-emitted operand
        !           602:  *
        !           603:  * Means relocating the operand.
        !           604:  */
        !           605: static void reginsert(op, opnd)
        !           606: char            op;
        !           607: char           *opnd;
        !           608: {
        !           609:     register char  *src;
        !           610:     register char  *dst;
        !           611:     register char  *place;
        !           612: 
        !           613:     if (regcode == &regdummy) {
        !           614:        regsize += 3;
        !           615:        return;
        !           616:     }
        !           617:     src = regcode;
        !           618:     regcode += 3;
        !           619:     dst = regcode;
        !           620:     while (src > opnd)
        !           621:        *--dst = *--src;
        !           622: 
        !           623:     place = opnd;              /* Op node, where operand used to be. */
        !           624:     *place++ = op;
        !           625:     *place++ = '\0';
        !           626:     *place++ = '\0';
        !           627: }
        !           628: 
        !           629: /*
        !           630:  - regtail - set the next-pointer at the end of a node chain
        !           631:  */
        !           632: static void regtail(p, val)
        !           633: char           *p;
        !           634: char           *val;
        !           635: {
        !           636:     register char  *scan;
        !           637:     register char  *temp;
        !           638:     register int    offset;
        !           639: 
        !           640:     if (p == &regdummy)
        !           641:        return;
        !           642: 
        !           643:     /* Find last node. */
        !           644:     scan = p;
        !           645:     for (;;) {
        !           646:        temp = regnext(scan);
        !           647:        if (temp == (char *)NULL)
        !           648:            break;
        !           649:        scan = temp;
        !           650:     }
        !           651: 
        !           652:     if (OP(scan) == BACK)
        !           653:        offset = scan - val;
        !           654:     else
        !           655:        offset = val - scan;
        !           656:     *(scan + 1) = (offset >> 8) & 0377;
        !           657:     *(scan + 2) = offset & 0377;
        !           658: }
        !           659: 
        !           660: /*
        !           661:  - regoptail - regtail on operand of first argument; nop if operandless
        !           662:  */
        !           663: static void regoptail(p, val)
        !           664: char           *p;
        !           665: char           *val;
        !           666: {
        !           667:     /* "Operandless" and "op != BRANCH" are synonymous in practice. */
        !           668:     if (p == (char *)NULL || p == &regdummy || OP(p) != BRANCH)
        !           669:        return;
        !           670:     regtail(OPERAND(p), val);
        !           671: }
        !           672: 
        !           673: /*
        !           674:  * regexec and friends
        !           675:  */
        !           676: 
        !           677: /*
        !           678:  * Global work variables for regexec().
        !           679:  */
        !           680: static char    *reginput;      /* String-input pointer. */
        !           681: static char    *regbol;                /* Beginning of input, for ^ check. */
        !           682: static char   **regstartp;     /* Pointer to startp array. */
        !           683: static char   **regendp;       /* Ditto for endp. */
        !           684: 
        !           685: /*
        !           686:  * Forwards.
        !           687:  */
        !           688: STATIC int      regtry();
        !           689: STATIC int      regmatch();
        !           690: STATIC int      regrepeat();
        !           691: 
        !           692: #ifdef DEBUG
        !           693: int             regnarrate = 0;
        !           694: void            regdump();
        !           695: STATIC char    *regprop();
        !           696: #endif
        !           697: 
        !           698: /*
        !           699:  - regexec - match a regexp against a string
        !           700:  */
        !           701: int regexec(prog, string)
        !           702: register regexp *prog;
        !           703: register char  *string;
        !           704: {
        !           705:     register char  *s;
        !           706: 
        !           707:     /* Be paranoid... */
        !           708:     if (prog == (regexp *)NULL || string == (char *)NULL) {
        !           709:        regerror("NULL parameter");
        !           710:        return (0);
        !           711:     }
        !           712:     /* Check validity of program. */
        !           713:     if (UCHARAT(prog->program) != MAGIC) {
        !           714:        regerror("corrupted program");
        !           715:        return (0);
        !           716:     }
        !           717:     /* If there is a "must appear" string, look for it. */
        !           718:     if (prog->regmust != (char *)NULL) {
        !           719:        s = string;
        !           720:        while ((s = strchr(s, prog->regmust[0])) != (char *)NULL) {
        !           721:            if (strncmp(s, prog->regmust, prog->regmlen) == 0)
        !           722:                break;          /* Found it. */
        !           723:            s++;
        !           724:        }
        !           725:        if (s == (char *)NULL)          /* Not present. */
        !           726:            return (0);
        !           727:     }
        !           728:     /* Mark beginning of line for ^ . */
        !           729:     regbol = string;
        !           730: 
        !           731:     /* Simplest case:  anchored match need be tried only once. */
        !           732:     if (prog->reganch)
        !           733:        return (regtry(prog, string));
        !           734: 
        !           735:     /* Messy cases:  unanchored match. */
        !           736:     s = string;
        !           737:     if (prog->regstart != '\0')
        !           738:        /* We know what char it must start with. */
        !           739:        while ((s = strchr(s, prog->regstart)) != (char *)NULL) {
        !           740:            if (regtry(prog, s))
        !           741:                return (1);
        !           742:            s++;
        !           743:        }
        !           744:     else
        !           745:        /* We don't -- general case. */
        !           746:        do {
        !           747:            if (regtry(prog, s))
        !           748:                return (1);
        !           749:        } while (*s++ != '\0');
        !           750: 
        !           751:     /* Failure. */
        !           752:     return (0);
        !           753: }
        !           754: 
        !           755: /*
        !           756:  - regtry - try match at specific point
        !           757:  */
        !           758: #if __STDC__
        !           759: 
        !           760: static int regtry(regexp *prog, char *string)
        !           761: 
        !           762: #else
        !           763: 
        !           764: static int regtry(prog, string)
        !           765: regexp         *prog;
        !           766: char           *string;
        !           767: 
        !           768: #endif
        !           769: {
        !           770:     register int    i;
        !           771:     register char **sp;
        !           772:     register char **ep;
        !           773: 
        !           774:     reginput = string;
        !           775:     regstartp = prog->startp;
        !           776:     regendp = prog->endp;
        !           777: 
        !           778:     sp = prog->startp;
        !           779:     ep = prog->endp;
        !           780:     for (i = NSUBEXP; i > 0; i--) {
        !           781:        *sp++ = (char *)NULL;
        !           782:        *ep++ = (char *)NULL;
        !           783:     }
        !           784:     if (regmatch(prog->program + 1)) {
        !           785:        prog->startp[0] = string;
        !           786:        prog->endp[0] = reginput;
        !           787:        return (1);
        !           788:     } else
        !           789:        return (0);
        !           790: }
        !           791: 
        !           792: /*
        !           793:  - regmatch - main matching routine
        !           794:  *
        !           795:  * Conceptually the strategy is simple:  check to see whether the current
        !           796:  * node matches, call self recursively to see whether the rest matches,
        !           797:  * and then act accordingly.  In practice we make some effort to avoid
        !           798:  * recursion, in particular by going through "ordinary" nodes (that don't
        !           799:  * need to know whether the rest of the match failed) by a loop instead of
        !           800:  * by recursion.
        !           801:  */
        !           802: #if __STDC__
        !           803: 
        !           804: static int regmatch(char *prog)
        !           805: 
        !           806: #else
        !           807: 
        !           808: static int regmatch(prog)
        !           809: char           *prog;
        !           810: 
        !           811: #endif
        !           812: {
        !           813:     register char  *scan;      /* Current node. */
        !           814:     char           *nxt;       /* nxt node. */
        !           815: 
        !           816:     scan = prog;
        !           817: #ifdef DEBUG
        !           818:     if (scan != (char *)NULL && regnarrate)
        !           819:        fprintf(stderr, "%s(\n", regprop(scan));
        !           820: #endif
        !           821:     while (scan != (char *)NULL) {
        !           822: #ifdef DEBUG
        !           823:        if (regnarrate)
        !           824:            fprintf(stderr, "%s...\n", regprop(scan));
        !           825: #endif
        !           826:        nxt = regnext(scan);
        !           827: 
        !           828:        switch (OP(scan)) {
        !           829:        case BOL:
        !           830:            if (reginput != regbol)
        !           831:                return (0);
        !           832:            break;
        !           833:        case EOL:
        !           834:            if (*reginput != '\0')
        !           835:                return (0);
        !           836:            break;
        !           837:        case ANY:
        !           838:            if (*reginput == '\0')
        !           839:                return (0);
        !           840:            reginput++;
        !           841:            break;
        !           842:        case EXACTLY:{
        !           843:                register int    len;
        !           844:                register char  *opnd;
        !           845: 
        !           846:                opnd = OPERAND(scan);
        !           847:                /* Inline the first character, for speed. */
        !           848:                if (*opnd != *reginput)
        !           849:                    return (0);
        !           850:                len = strlen(opnd);
        !           851:                if (len > 1 && strncmp(opnd, reginput, len) != 0)
        !           852:                    return (0);
        !           853:                reginput += len;
        !           854:            }
        !           855:            break;
        !           856:        case ANYOF:
        !           857:            if (*reginput == '\0' || 
        !           858:                 strchr(OPERAND(scan), *reginput) == (char *)NULL)
        !           859:                return (0);
        !           860:            reginput++;
        !           861:            break;
        !           862:        case ANYBUT:
        !           863:            if (*reginput == '\0' || 
        !           864:                 strchr(OPERAND(scan), *reginput) != (char *)NULL)
        !           865:                return (0);
        !           866:            reginput++;
        !           867:            break;
        !           868:        case NOTHING:
        !           869:            break;
        !           870:        case BACK:
        !           871:            break;
        !           872:        case OPEN + 1:
        !           873:        case OPEN + 2:
        !           874:        case OPEN + 3:
        !           875:        case OPEN + 4:
        !           876:        case OPEN + 5:
        !           877:        case OPEN + 6:
        !           878:        case OPEN + 7:
        !           879:        case OPEN + 8:
        !           880:        case OPEN + 9:{
        !           881:                register int    no;
        !           882:                register char  *save;
        !           883: 
        !           884:                no = OP(scan) - OPEN;
        !           885:                save = reginput;
        !           886: 
        !           887:                if (regmatch(nxt)) {
        !           888:                    /*
        !           889:                     * Don't set startp if some later invocation of the same
        !           890:                     * parentheses already has. 
        !           891:                     */
        !           892:                    if (regstartp[no] == (char *)NULL)
        !           893:                        regstartp[no] = save;
        !           894:                    return (1);
        !           895:                } else
        !           896:                    return (0);
        !           897:            }
        !           898:            break;
        !           899:        case CLOSE + 1:
        !           900:        case CLOSE + 2:
        !           901:        case CLOSE + 3:
        !           902:        case CLOSE + 4:
        !           903:        case CLOSE + 5:
        !           904:        case CLOSE + 6:
        !           905:        case CLOSE + 7:
        !           906:        case CLOSE + 8:
        !           907:        case CLOSE + 9:{
        !           908:                register int    no;
        !           909:                register char  *save;
        !           910: 
        !           911:                no = OP(scan) - CLOSE;
        !           912:                save = reginput;
        !           913: 
        !           914:                if (regmatch(nxt)) {
        !           915:                    /*
        !           916:                     * Don't set endp if some later invocation of the same
        !           917:                     * parentheses already has. 
        !           918:                     */
        !           919:                    if (regendp[no] == (char *)NULL)
        !           920:                        regendp[no] = save;
        !           921:                    return (1);
        !           922:                } else
        !           923:                    return (0);
        !           924:            }
        !           925:            break;
        !           926:        case BRANCH:{
        !           927:                register char  *save;
        !           928: 
        !           929:                if (OP(nxt) != BRANCH)  /* No choice. */
        !           930:                    nxt = OPERAND(scan);        /* Avoid recursion. */
        !           931:                else {
        !           932:                    do {
        !           933:                        save = reginput;
        !           934:                        if (regmatch(OPERAND(scan)))
        !           935:                            return (1);
        !           936:                        reginput = save;
        !           937:                        scan = regnext(scan);
        !           938:                    } while (scan != (char *)NULL && OP(scan) == BRANCH);
        !           939:                    return (0);
        !           940:                    /* NOTREACHED */
        !           941:                }
        !           942:            }
        !           943:            break;
        !           944:        case STAR:{
        !           945:                register char   nextch;
        !           946:                register int    no;
        !           947:                register char  *save;
        !           948:                register int    minimum;
        !           949: 
        !           950:                /*
        !           951:                 * Lookahead to avoid useless match attempts when we know
        !           952:                 * what character comes next. 
        !           953:                 */
        !           954:                nextch = '\0';
        !           955:                if (OP(nxt) == EXACTLY)
        !           956:                    nextch = *OPERAND(nxt);
        !           957:                minimum = (OP(scan) == STAR) ? 0 : 1;
        !           958:                save = reginput;
        !           959:                no = regrepeat(OPERAND(scan));
        !           960:                while (no >= minimum) {
        !           961:                    /* If it could work, try it. */
        !           962:                    if (nextch == '\0' || *reginput == nextch)
        !           963:                        if (regmatch(nxt))
        !           964:                            return (1);
        !           965:                    /* Couldn't or didn't -- back up. */
        !           966:                    no--;
        !           967:                    reginput = save + no;
        !           968:                }
        !           969:                return (0);
        !           970:            }
        !           971:            break;
        !           972:        case END:
        !           973:            return (1);         /* Success! */
        !           974:            break;
        !           975:        default:
        !           976:            regerror("memory corruption");
        !           977:            return (0);
        !           978:            break;
        !           979:        }
        !           980: 
        !           981:        scan = nxt;
        !           982:     }
        !           983: 
        !           984:     /*
        !           985:      * We get here only if there's trouble -- normally "case END" is the
        !           986:      * terminating point. 
        !           987:      */
        !           988:     regerror("corrupted pointers");
        !           989:     return (0);
        !           990: }
        !           991: 
        !           992: /*
        !           993:  - regrepeat - repeatedly match something simple, report how many
        !           994:  */
        !           995: #if __STDC__
        !           996: 
        !           997: static int regrepeat(char *p)
        !           998: 
        !           999: #else
        !          1000: 
        !          1001: static int regrepeat(p)
        !          1002: char           *p;
        !          1003: 
        !          1004: #endif
        !          1005: {
        !          1006:     register int    count = 0;
        !          1007:     register char  *scan;
        !          1008:     register char  *opnd;
        !          1009: 
        !          1010:     scan = reginput;
        !          1011:     opnd = OPERAND(p);
        !          1012:     switch (OP(p)) {
        !          1013:     case ANY:
        !          1014:        count = strlen(scan);
        !          1015:        scan += count;
        !          1016:        break;
        !          1017:     case EXACTLY:
        !          1018:        while (*opnd == *scan) {
        !          1019:            count++;
        !          1020:            scan++;
        !          1021:        }
        !          1022:        break;
        !          1023:     case ANYOF:
        !          1024:        while (*scan != '\0' && strchr(opnd, *scan) != (char *)NULL) {
        !          1025:            count++;
        !          1026:            scan++;
        !          1027:        }
        !          1028:        break;
        !          1029:     case ANYBUT:
        !          1030:        while (*scan != '\0' && strchr(opnd, *scan) == (char *)NULL) {
        !          1031:            count++;
        !          1032:            scan++;
        !          1033:        }
        !          1034:        break;
        !          1035:     default:                   /* Oh dear.  Called inappropriately. */
        !          1036:        regerror("internal foulup");
        !          1037:        count = 0;              /* Best compromise. */
        !          1038:        break;
        !          1039:     }
        !          1040:     reginput = scan;
        !          1041: 
        !          1042:     return (count);
        !          1043: }
        !          1044: 
        !          1045: 
        !          1046: /*
        !          1047:  - regnext - dig the "nxt" pointer out of a node
        !          1048:  */
        !          1049: #if __STDC__
        !          1050: 
        !          1051: static char *regnext(register char *p)
        !          1052: 
        !          1053: #else
        !          1054: 
        !          1055: static char *regnext(p)
        !          1056: register char  *p;
        !          1057: 
        !          1058: #endif
        !          1059: {
        !          1060:     register int    offset;
        !          1061: 
        !          1062:     if (p == &regdummy)
        !          1063:        return ((char *)NULL);
        !          1064: 
        !          1065:     offset = NEXT(p);
        !          1066:     if (offset == 0)
        !          1067:        return ((char *)NULL);
        !          1068: 
        !          1069:     if (OP(p) == BACK)
        !          1070:        return (p - offset);
        !          1071:     else
        !          1072:        return (p + offset);
        !          1073: }
        !          1074: 
        !          1075: #ifdef DEBUG
        !          1076: 
        !          1077: STATIC char    *regprop();
        !          1078: 
        !          1079: /*
        !          1080:  - regdump - dump a regexp onto stdout in vaguely comprehensible form
        !          1081:  */
        !          1082: #if __STDC__
        !          1083: 
        !          1084: void regdump(regexp *r)
        !          1085: 
        !          1086: #else
        !          1087: 
        !          1088: void regdump(r)
        !          1089: regexp         *r;
        !          1090: 
        !          1091: #endif
        !          1092: {
        !          1093:     register char  *s;
        !          1094:     register char   op = EXACTLY;      /* Arbitrary non-END op. */
        !          1095:     register char  *nxt;
        !          1096:     extern char    *strchr();
        !          1097: 
        !          1098: 
        !          1099:     s = r->program + 1;
        !          1100:     while (op != END) {                /* While that wasn't END last time... */
        !          1101:        op = OP(s);
        !          1102:        printf("%2d%s", s - r->program, regprop(s));    /* Where, what. */
        !          1103:        nxt = regnext(s);
        !          1104:        if (nxt == (char *)NULL)        /* nxt ptr. */
        !          1105:            printf("(0)");
        !          1106:        else
        !          1107:            printf("(%d)", (s - r->program) + (nxt - s));
        !          1108:        s += 3;
        !          1109:        if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
        !          1110:            /* Literal string, where present. */
        !          1111:            while (*s != '\0') {
        !          1112:                putchar(*s);
        !          1113:                s++;
        !          1114:            }
        !          1115:            s++;
        !          1116:        }
        !          1117:        putchar('\n');
        !          1118:     }
        !          1119: 
        !          1120:     /* Header fields of interest. */
        !          1121:     if (r->regstart != '\0')
        !          1122:        printf("start `%c' ", r->regstart);
        !          1123:     if (r->reganch)
        !          1124:        printf("anchored ");
        !          1125:     if (r->regmust != (char *)NULL)
        !          1126:        printf("must have \"%s\"", r->regmust);
        !          1127:     printf("\n");
        !          1128: }
        !          1129: 
        !          1130: /*
        !          1131:  - regprop - printable representation of opcode
        !          1132:  */
        !          1133: #if __STDC__
        !          1134: 
        !          1135: static char *regprop(char *op)
        !          1136: 
        !          1137: #else
        !          1138: 
        !          1139: static char *regprop(op)
        !          1140: char           *op;
        !          1141: 
        !          1142: #endif
        !          1143: {
        !          1144:     register char  *p;
        !          1145:     static char     buf[50];
        !          1146: 
        !          1147:     strcpy(buf, ":");
        !          1148: 
        !          1149:     switch (OP(op)) {
        !          1150:     case BOL:
        !          1151:        p = "BOL";
        !          1152:        break;
        !          1153:     case EOL:
        !          1154:        p = "EOL";
        !          1155:        break;
        !          1156:     case ANY:
        !          1157:        p = "ANY";
        !          1158:        break;
        !          1159:     case ANYOF:
        !          1160:        p = "ANYOF";
        !          1161:        break;
        !          1162:     case ANYBUT:
        !          1163:        p = "ANYBUT";
        !          1164:        break;
        !          1165:     case BRANCH:
        !          1166:        p = "BRANCH";
        !          1167:        break;
        !          1168:     case EXACTLY:
        !          1169:        p = "EXACTLY";
        !          1170:        break;
        !          1171:     case NOTHING:
        !          1172:        p = "NOTHING";
        !          1173:        break;
        !          1174:     case BACK:
        !          1175:        p = "BACK";
        !          1176:        break;
        !          1177:     case END:
        !          1178:        p = "END";
        !          1179:        break;
        !          1180:     case OPEN + 1:
        !          1181:     case OPEN + 2:
        !          1182:     case OPEN + 3:
        !          1183:     case OPEN + 4:
        !          1184:     case OPEN + 5:
        !          1185:     case OPEN + 6:
        !          1186:     case OPEN + 7:
        !          1187:     case OPEN + 8:
        !          1188:     case OPEN + 9:
        !          1189:        sprintf(buf + strlen(buf), "OPEN%d", OP(op) - OPEN);
        !          1190:        p = (char *)NULL;
        !          1191:        break;
        !          1192:     case CLOSE + 1:
        !          1193:     case CLOSE + 2:
        !          1194:     case CLOSE + 3:
        !          1195:     case CLOSE + 4:
        !          1196:     case CLOSE + 5:
        !          1197:     case CLOSE + 6:
        !          1198:     case CLOSE + 7:
        !          1199:     case CLOSE + 8:
        !          1200:     case CLOSE + 9:
        !          1201:        sprintf(buf + strlen(buf), "CLOSE%d", OP(op) - CLOSE);
        !          1202:        p = (char *)NULL;
        !          1203:        break;
        !          1204:     case STAR:
        !          1205:        p = "STAR";
        !          1206:        break;
        !          1207:     default:
        !          1208:        regerror("corrupted opcode");
        !          1209:        break;
        !          1210:     }
        !          1211:     if (p != (char *)NULL)
        !          1212:        strcat(buf, p);
        !          1213:     return (buf);
        !          1214: }
        !          1215: #endif
        !          1216: 
        !          1217: /*
        !          1218:  * The following is provided for those people who do not have strcspn() in
        !          1219:  * their C libraries.  They should get off their butts and do something
        !          1220:  * about it; at least one public-domain implementation of those (highly
        !          1221:  * useful) string routines has been published on Usenet.
        !          1222:  */
        !          1223: #ifdef STRCSPN
        !          1224: /*
        !          1225:  * strcspn - find length of initial segment of s1 consisting entirely
        !          1226:  * of characters not from s2
        !          1227:  */
        !          1228: 
        !          1229: #if __STDC__
        !          1230: 
        !          1231: static int strcspn(char *s1, char *s2)
        !          1232: 
        !          1233: #else
        !          1234: 
        !          1235: static int strcspn(s1, s2)
        !          1236: char           *s1;
        !          1237: char           *s2;
        !          1238: 
        !          1239: #endif
        !          1240: {
        !          1241:     register char  *scan1;
        !          1242:     register char  *scan2;
        !          1243:     register int    count;
        !          1244: 
        !          1245:     count = 0;
        !          1246:     for (scan1 = s1; *scan1 != '\0'; scan1++) {
        !          1247:        for (scan2 = s2; *scan2 != '\0';)       /* ++ moved down. */
        !          1248:            if (*scan1 == *scan2++)
        !          1249:                return (count);
        !          1250:        count++;
        !          1251:     }
        !          1252:     return (count);
        !          1253: }
        !          1254: #endif
        !          1255: 
        !          1256: 
        !          1257: /*
        !          1258:  - regsub - perform substitutions after a regexp match
        !          1259:  */
        !          1260: #if __STDC__
        !          1261: 
        !          1262: void regsub(regexp *prog, char *source, char *dest)
        !          1263: 
        !          1264: #else
        !          1265: 
        !          1266: void regsub(prog, source, dest)
        !          1267: regexp         *prog;
        !          1268: char           *source;
        !          1269: char           *dest;
        !          1270: 
        !          1271: #endif
        !          1272: {
        !          1273:     register char  *src;
        !          1274:     register char  *dst;
        !          1275:     register char   c;
        !          1276:     register int    no;
        !          1277:     register int    len;
        !          1278:     extern char    *strncpy();
        !          1279: 
        !          1280:     if (prog == (regexp *)NULL || 
        !          1281:        source == (char *)NULL || dest == (char *)NULL) {
        !          1282:        regerror("NULL parm to regsub");
        !          1283:        return;
        !          1284:     }
        !          1285:     if (UCHARAT(prog->program) != MAGIC) {
        !          1286:        regerror("damaged regexp fed to regsub");
        !          1287:        return;
        !          1288:     }
        !          1289:     src = source;
        !          1290:     dst = dest;
        !          1291:     while ((c = *src++) != '\0') {
        !          1292:        if (c == '&')
        !          1293:            no = 0;
        !          1294:        else if (c == '\\' && '0' <= *src && *src <= '9')
        !          1295:            no = *src++ - '0';
        !          1296:        else
        !          1297:            no = -1;
        !          1298: 
        !          1299:        if (no < 0) {           /* Ordinary character. */
        !          1300:            if (c == '\\' && (*src == '\\' || *src == '&'))
        !          1301:                c = *src++;
        !          1302:            *dst++ = c;
        !          1303:        } else if (prog->startp[no] != (char *)NULL && 
        !          1304:                   prog->endp[no] != (char *)NULL) {
        !          1305:            len = prog->endp[no] - prog->startp[no];
        !          1306:            strncpy(dst, prog->startp[no], len);
        !          1307:            dst += len;
        !          1308:            if (len != 0 && *(dst - 1) == '\0') {       /* strncpy hit NUL. */
        !          1309:                regerror("damaged match string");
        !          1310:                return;
        !          1311:            }
        !          1312:        }
        !          1313:     }
        !          1314:     *dst++ = '\0';
        !          1315: }
        !          1316: 
        !          1317: 
        !          1318: #if __STDC__
        !          1319: 
        !          1320: void regerror(char *s)
        !          1321: 
        !          1322: #else
        !          1323: 
        !          1324: void regerror(s)
        !          1325: char           *s;
        !          1326: 
        !          1327: #endif
        !          1328: {
        !          1329:     fprintf(stderr, "regexp(3): %s", s);
        !          1330:     exit(1);
        !          1331: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.