Annotation of 43BSD/contrib/rn/search.c, revision 1.1.1.1

1.1       root        1: /* $Header: search.c,v 4.3 85/05/01 11:50:16 lwall Exp $
                      2:  *
                      3:  * $Log:       search.c,v $
                      4:  * Revision 4.3  85/05/01  11:50:16  lwall
                      5:  * Baseline for release with 4.3bsd.
                      6:  * 
                      7:  */
                      8: 
                      9: /* string search routines */
                     10:  
                     11: /*             Copyright (c) 1981,1980 James Gosling           */
                     12:  
                     13: /* Modified Aug. 12, 1981 by Tom London to include regular expressions
                     14:    as in ed.  RE stuff hacked over by jag to correct a few major problems,
                     15:    mainly dealing with searching within the buffer rather than copying
                     16:    each line to a separate array.  Newlines can now appear in RE's */
                     17: 
                     18: /* Ripped to shreds and glued back together to make a search package,
                     19:  * July 6, 1984, by Larry Wall. (If it doesn't work, it's probably my fault.)
                     20:  * Changes include:
                     21:  *     Buffer, window, and mlisp stuff gone.
                     22:  *     Translation tables reduced to 1 table.
                     23:  *     Expression buffer is now dynamically allocated.
                     24:  *     Character classes now implemented with a bitmap.
                     25:  */
                     26: 
                     27: #include "EXTERN.h"
                     28: #include "common.h"
                     29: #include "util.h"
                     30: #include "INTERN.h"
                     31: #include "search.h"
                     32: 
                     33: #ifndef BITSPERBYTE
                     34: #define BITSPERBYTE 8
                     35: #endif
                     36: 
                     37: #define BMAPSIZ (127 / BITSPERBYTE + 1)
                     38: 
                     39: /* meta characters in the "compiled" form of a regular expression */
                     40: #define        CBRA    2               /* \( -- begin bracket */
                     41: #define        CCHR    4               /* a vanilla character */
                     42: #define        CDOT    6               /* . -- match anything except a newline */
                     43: #define        CCL     8               /* [...] -- character class */
                     44: #define        NCCL    10              /* [^...] -- negated character class */
                     45: #define        CDOL    12              /* $ -- matches the end of a line */
                     46: #define        CEND    14              /* The end of the pattern */
                     47: #define        CKET    16              /* \) -- close bracket */
                     48: #define        CBACK   18              /* \N -- backreference to the Nth bracketed
                     49:                                   string */
                     50: #define CIRC   20              /* ^ matches the beginning of a line */
                     51: 
                     52: #define WORD   32              /* matches word character \w */
                     53: #define NWORD  34              /* matches non-word characer \W */
                     54: #define WBOUND 36              /* matches word boundary \b */
                     55: #define NWBOUND        38              /* matches non-(word boundary) \B */
                     56:  
                     57: #define        STAR    01              /* * -- Kleene star, repeats the previous
                     58:                                   REas many times as possible; the value
                     59:                                   ORs with the other operator types */
                     60:  
                     61: #define ASCSIZ 0200
                     62: typedef char   TRANSTABLE[ASCSIZ];
                     63: 
                     64: static TRANSTABLE trans = {
                     65: 0000,0001,0002,0003,0004,0005,0006,0007,
                     66: 0010,0011,0012,0013,0014,0015,0016,0017,
                     67: 0020,0021,0022,0023,0024,0025,0026,0027,
                     68: 0030,0031,0032,0033,0034,0035,0036,0037,
                     69: 0040,0041,0042,0043,0044,0045,0046,0047,
                     70: 0050,0051,0052,0053,0054,0055,0056,0057,
                     71: 0060,0061,0062,0063,0064,0065,0066,0067,
                     72: 0070,0071,0072,0073,0074,0075,0076,0077,
                     73: 0100,0101,0102,0103,0104,0105,0106,0107,
                     74: 0110,0111,0112,0113,0114,0115,0116,0117,
                     75: 0120,0121,0122,0123,0124,0125,0126,0127,
                     76: 0130,0131,0132,0133,0134,0135,0136,0137,
                     77: 0140,0141,0142,0143,0144,0145,0146,0147,
                     78: 0150,0151,0152,0153,0154,0155,0156,0157,
                     79: 0160,0161,0162,0163,0164,0165,0166,0167,
                     80: 0170,0171,0172,0173,0174,0175,0176,0177,
                     81: };
                     82: static bool folding = FALSE;
                     83: 
                     84: static int err;
                     85: static char *FirstCharacter;
                     86: 
                     87: void
                     88: search_init()
                     89: {
                     90: #ifdef UNDEF
                     91:     register int    i;
                     92:     
                     93:     for (i = 0; i < ASCSIZ; i++)
                     94:        trans[i] = i;
                     95: #else
                     96:     ;
                     97: #endif
                     98: }
                     99: 
                    100: void
                    101: init_compex(compex)
                    102: register COMPEX *compex;
                    103: {
                    104:     /* the following must start off zeroed */
                    105: 
                    106:     compex->eblen = 0;
                    107:     compex->brastr = Nullch;
                    108: }
                    109: 
                    110: void
                    111: free_compex(compex)
                    112: register COMPEX *compex;
                    113: {
                    114:     if (compex->eblen) {
                    115:        free(compex->expbuf);
                    116:        compex->eblen = 0;
                    117:     }
                    118:     if (compex->brastr) {
                    119:        free(compex->brastr);
                    120:        compex->brastr = Nullch;
                    121:     }
                    122: }
                    123: 
                    124: static char *gbr_str = Nullch;
                    125: static int gbr_siz = 0;
                    126: 
                    127: char *
                    128: getbracket(compex,n)
                    129: register COMPEX *compex;
                    130: int n;
                    131: {
                    132:     int length = compex->braelist[n] - compex->braslist[n];
                    133: 
                    134:     if (!compex->nbra || n > compex->nbra || !compex->braelist[n] || length<0)
                    135:        return nullstr;
                    136:     growstr(&gbr_str, &gbr_siz, length+1);
                    137:     safecpy(gbr_str, compex->braslist[n], length+1);
                    138:     return gbr_str;
                    139: }
                    140: 
                    141: void
                    142: case_fold(which)
                    143: int which;
                    144: {
                    145:     register int i;
                    146: 
                    147:     if (which != folding) {
                    148:        if (which) {
                    149:            for (i = 'A'; i <= 'Z'; i++)
                    150:                trans[i] = tolower(i);
                    151:        }
                    152:        else {
                    153:            for (i = 'A'; i <= 'Z'; i++)
                    154:                trans[i] = i;
                    155:        }
                    156:        folding = which;
                    157:     }
                    158: }
                    159: 
                    160: /* Compile the given regular expression into a [secret] internal format */
                    161: 
                    162: char *
                    163: compile (compex, strp, RE, fold)
                    164: register COMPEX *compex;
                    165: register char   *strp;
                    166: int RE;
                    167: int fold;
                    168: {
                    169:     register int c;
                    170:     register char  *ep;
                    171:     char   *lastep;
                    172:     char    bracket[NBRA],
                    173:           *bracketp;
                    174:     char **alt = compex->alternatives;
                    175:     char *retmes = "Badly formed search string";
                    176:  
                    177:     case_fold(compex->do_folding = fold);
                    178:     if (!compex->eblen) {
                    179:        compex->expbuf = safemalloc(84);
                    180:        compex->eblen = 80;
                    181:     }
                    182:     ep = compex->expbuf;               /* point at expression buffer */
                    183:     *alt++ = ep;                       /* first alternative starts here */
                    184:     bracketp = bracket;                        /* first bracket goes here */
                    185:     if (*strp == 0) {                  /* nothing to compile? */
                    186:        if (*ep == 0)                   /* nothing there yet? */
                    187:            return "Null search string";
                    188:        return Nullch;                  /* just keep old expression */
                    189:     }
                    190:     compex->nbra = 0;                  /* no brackets yet */
                    191:     lastep = 0;
                    192:     for (;;) {
                    193:        if (ep - compex->expbuf >= compex->eblen)
                    194:            grow_eb(compex);
                    195:        c = *strp++;                    /* fetch next char of pattern */
                    196:        if (c == 0) {                   /* end of pattern? */
                    197:            if (bracketp != bracket) {  /* balanced brackets? */
                    198: #ifdef VERBOSE
                    199:                retmes = "Unbalanced parens";
                    200: #endif
                    201:                goto cerror;
                    202:            }
                    203:            *ep++ = CEND;               /* terminate expression */
                    204:            *alt++ = 0;                 /* terminal alternative list */
                    205:            /*
                    206:            compex->eblen = ep - compex->expbuf + 1;
                    207:            compex->expbuf = saferealloc(compex->expbuf,compex->eblen+4); */
                    208:            return Nullch;              /* return success */
                    209:        }
                    210:        if (c != '*')
                    211:            lastep = ep;
                    212:        if (!RE) {                      /* just a normal search string? */
                    213:            *ep++ = CCHR;               /* everything is a normal char */
                    214:            *ep++ = c;
                    215:        }
                    216:        else                            /* it is a regular expression */
                    217:            switch (c) {
                    218:  
                    219:                case '\\':              /* meta something */
                    220:                    switch (c = *strp++) {
                    221:                    case '(':
                    222:                        if (compex->nbra >= NBRA) {
                    223: #ifdef VERBOSE
                    224:                            retmes = "Too many parens";
                    225: #endif
                    226:                            goto cerror;
                    227:                        }
                    228:                        *bracketp++ = ++compex->nbra;
                    229:                        *ep++ = CBRA;
                    230:                        *ep++ = compex->nbra;
                    231:                        break;
                    232:                    case '|':
                    233:                        if (bracketp>bracket) {
                    234: #ifdef VERBOSE
                    235:                            retmes = "No \\| in parens";        /* Alas! */
                    236: #endif
                    237:                            goto cerror;
                    238:                        }
                    239:                        *ep++ = CEND;
                    240:                        *alt++ = ep;
                    241:                        break;
                    242:                    case ')':
                    243:                        if (bracketp <= bracket) {
                    244: #ifdef VERBOSE
                    245:                            retmes = "Unmatched right paren";
                    246: #endif
                    247:                            goto cerror;
                    248:                        }
                    249:                        *ep++ = CKET;
                    250:                        *ep++ = *--bracketp;
                    251:                        break;
                    252:                    case 'w':
                    253:                        *ep++ = WORD;
                    254:                        break;
                    255:                    case 'W':
                    256:                        *ep++ = NWORD;
                    257:                        break;
                    258:                    case 'b':
                    259:                        *ep++ = WBOUND;
                    260:                        break;
                    261:                    case 'B':
                    262:                        *ep++ = NWBOUND;
                    263:                        break;
                    264:                    case '0': case '1': case '2': case '3': case '4':
                    265:                    case '5': case '6': case '7': case '8': case '9':
                    266:                        *ep++ = CBACK;
                    267:                        *ep++ = c - '0';
                    268:                        break;
                    269:                    default:
                    270:                        *ep++ = CCHR;
                    271:                        if (c == '\0')
                    272:                            goto cerror;
                    273:                        *ep++ = c;
                    274:                        break;
                    275:                    }
                    276:                    break;
                    277:                case '.':
                    278:                    *ep++ = CDOT;
                    279:                    continue;
                    280:  
                    281:                case '*':
                    282:                    if (lastep == 0 || *lastep == CBRA || *lastep == CKET
                    283:                        || *lastep == CIRC
                    284:                        || (*lastep&STAR)|| *lastep>NWORD)
                    285:                        goto defchar;
                    286:                    *lastep |= STAR;
                    287:                    continue;
                    288:  
                    289:                case '^':
                    290:                    if (ep != compex->expbuf && ep[-1] != CEND)
                    291:                        goto defchar;
                    292:                    *ep++ = CIRC;
                    293:                    continue;
                    294:  
                    295:                case '$':
                    296:                    if (*strp != 0 && (*strp != '\\' || strp[1] != '|'))
                    297:                        goto defchar;
                    298:                    *ep++ = CDOL;
                    299:                    continue;
                    300:  
                    301:                case '[': {             /* character class */
                    302:                    register int i;
                    303:                    
                    304:                    if (ep - compex->expbuf >= compex->eblen - BMAPSIZ)
                    305:                        grow_eb(compex);        /* reserve bitmap */
                    306:                    for (i = BMAPSIZ; i; --i)
                    307:                        ep[i] = 0;
                    308:                    
                    309:                    if ((c = *strp++) == '^') {
                    310:                        c = *strp++;
                    311:                        *ep++ = NCCL;   /* negated */
                    312:                    }
                    313:                    else
                    314:                        *ep++ = CCL;    /* normal */
                    315:                    
                    316:                    i = 0;              /* remember oldchar */
                    317:                    do {
                    318:                        if (c == '\0') {
                    319: #ifdef VERBOSE
                    320:                            retmes = "Missing ]";
                    321: #endif
                    322:                            goto cerror;
                    323:                        }
                    324:                        if (*strp == '-' && *(++strp))
                    325:                            i = *strp++;
                    326:                        else
                    327:                            i = c;
                    328:                        while (c <= i) {
                    329:                            ep[c / BITSPERBYTE] |= 1 << (c % BITSPERBYTE);
                    330:                            if (fold && isalpha(c))
                    331:                                ep[(c ^ 32) / BITSPERBYTE] |=
                    332:                                    1 << ((c ^ 32) % BITSPERBYTE);
                    333:                                        /* set the other bit too */
                    334:                            c++;
                    335:                        }
                    336:                    } while ((c = *strp++) != ']');
                    337:                    ep += BMAPSIZ;
                    338:                    continue;
                    339:                }
                    340:  
                    341:            defchar:
                    342:                default:
                    343:                    *ep++ = CCHR;
                    344:                    *ep++ = c;
                    345:            }
                    346:     }
                    347: cerror:
                    348:     compex->expbuf[0] = 0;
                    349:     compex->nbra = 0;
                    350:     return retmes;
                    351: }
                    352: 
                    353: void
                    354: grow_eb(compex)
                    355: register COMPEX *compex;
                    356: {
                    357:     compex->eblen += 80;
                    358:     compex->expbuf = saferealloc(compex->expbuf, (MEM_SIZE)compex->eblen + 4);
                    359: }
                    360: 
                    361: char *
                    362: execute (compex, addr)
                    363: register COMPEX *compex;
                    364: char *addr;
                    365: {
                    366:     register char *p1 = addr;
                    367:     register char *trt = trans;
                    368:     register int c;
                    369:  
                    370:     if (addr == Nullch)
                    371:        return Nullch;
                    372:     if (compex->nbra) {                        /* any brackets? */
                    373:        for (c = 0; c <= compex->nbra; c++)
                    374:            compex->braslist[c] = compex->braelist[c] = Nullch;
                    375:        if (compex->brastr)
                    376:            free(compex->brastr);
                    377:        compex->brastr = savestr(p1);   /* in case p1 is not static */
                    378:        p1 = compex->brastr;            /* ! */
                    379:     }
                    380:     case_fold(compex->do_folding);     /* make sure table is correct */
                    381:     FirstCharacter = p1;               /* for ^ tests */
                    382:     if (compex->expbuf[0] == CCHR && !compex->alternatives[1]) {
                    383:        c = trt[compex->expbuf[1]];     /* fast check for first character */
                    384:        do {
                    385:            if (trt[*p1] == c && advance (compex, p1, compex->expbuf))
                    386:                return p1;
                    387:            p1++;
                    388:        } while (*p1 && !err);
                    389:        return Nullch;
                    390:     }
                    391:     else {                     /* regular algorithm */
                    392:        do {
                    393:            register char **alt = compex->alternatives;
                    394:            while (*alt) {
                    395:                if (advance (compex, p1, *alt++))
                    396:                    return p1;
                    397:            }
                    398:            p1++;
                    399:        } while (*p1 && !err);
                    400:        return Nullch;
                    401:     }
                    402: }
                    403:  
                    404: /* advance the match of the regular expression starting at ep along the
                    405:    string lp, simulates an NDFSA */
                    406: bool
                    407: advance (compex, lp, ep)
                    408: register COMPEX *compex;
                    409: register char *ep;
                    410: register char *lp;
                    411: {
                    412:     register char *curlp;
                    413:     register char *trt = trans;
                    414:     register int i;
                    415:  
                    416:     while ((*ep & STAR) || *lp || *ep == CIRC || *ep == CKET)
                    417:        switch (*ep++) {
                    418:  
                    419:            case CCHR:
                    420:                if (trt[*ep++] != trt[*lp]) return FALSE;
                    421:                lp++;
                    422:                continue;
                    423:  
                    424:            case CDOT:
                    425:                if (*lp == '\n') return FALSE;
                    426:                lp++;
                    427:                continue;
                    428:  
                    429:            case CDOL:
                    430:                if (!*lp || *lp == '\n')
                    431:                    continue;
                    432:                return FALSE;
                    433:  
                    434:            case CIRC:
                    435:                if (lp == FirstCharacter || lp[-1]=='\n')
                    436:                    continue;
                    437:                return FALSE;
                    438:  
                    439:            case WORD:
                    440:                if (isalnum(*lp)) {
                    441:                    lp++;
                    442:                    continue;
                    443:                }
                    444:                return FALSE;
                    445:  
                    446:            case NWORD:
                    447:                if (!isalnum(*lp)) {
                    448:                    lp++;
                    449:                    continue;
                    450:                }
                    451:                return FALSE;
                    452:  
                    453:            case WBOUND:
                    454:                if ((lp == FirstCharacter || !isalnum(lp[-1])) !=
                    455:                        (!*lp || !isalnum(*lp)) )
                    456:                    continue;
                    457:                return FALSE;
                    458:  
                    459:            case NWBOUND:
                    460:                if ((lp == FirstCharacter || !isalnum(lp[-1])) ==
                    461:                        (!*lp || !isalnum(*lp)))
                    462:                    continue;
                    463:                return FALSE;
                    464:  
                    465:            case CEND:
                    466:                return TRUE;
                    467:  
                    468:            case CCL:
                    469:                if (cclass (ep, *lp, 1)) {
                    470:                    ep += BMAPSIZ;
                    471:                    lp++;
                    472:                    continue;
                    473:                }
                    474:                return FALSE;
                    475:  
                    476:            case NCCL:
                    477:                if (cclass (ep, *lp, 0)) {
                    478:                    ep += BMAPSIZ;
                    479:                    lp++;
                    480:                    continue;
                    481:                }
                    482:                return FALSE;
                    483:  
                    484:            case CBRA:
                    485:                compex->braslist[*ep++] = lp;
                    486:                continue;
                    487:  
                    488:            case CKET:
                    489:                i = *ep++;
                    490:                compex->braelist[i] = lp;
                    491:                compex->braelist[0] = lp;
                    492:                compex->braslist[0] = compex->braslist[i];
                    493:                continue;
                    494:  
                    495:            case CBACK:
                    496:                if (compex->braelist[i = *ep++] == 0) {
                    497:                    fputs("bad braces\n",stdout) FLUSH;
                    498:                    err = TRUE;
                    499:                    return FALSE;
                    500:                }
                    501:                if (backref (compex, i, lp)) {
                    502:                    lp += compex->braelist[i] - compex->braslist[i];
                    503:                    continue;
                    504:                }
                    505:                return FALSE;
                    506:  
                    507:            case CBACK | STAR:
                    508:                if (compex->braelist[i = *ep++] == 0) {
                    509:                    fputs("bad braces\n",stdout) FLUSH;
                    510:                    err = TRUE;
                    511:                    return FALSE;
                    512:                }
                    513:                curlp = lp;
                    514:                while (backref (compex, i, lp)) {
                    515:                    lp += compex->braelist[i] - compex->braslist[i];
                    516:                }
                    517:                while (lp >= curlp) {
                    518:                    if (advance (compex, lp, ep))
                    519:                        return TRUE;
                    520:                    lp -= compex->braelist[i] - compex->braslist[i];
                    521:                }
                    522:                continue;
                    523:  
                    524:            case CDOT | STAR:
                    525:                curlp = lp;
                    526:                while (*lp++ && lp[-1] != '\n');
                    527:                goto star;
                    528:  
                    529:            case WORD | STAR:
                    530:                curlp = lp;
                    531:                while (*lp++ && isalnum(lp[-1]));
                    532:                goto star;
                    533:  
                    534:            case NWORD | STAR:
                    535:                curlp = lp;
                    536:                while (*lp++ && !isalnum(lp[-1]));
                    537:                goto star;
                    538:  
                    539:            case CCHR | STAR:
                    540:                curlp = lp;
                    541:                while (*lp++ && trt[lp[-1]] == trt[*ep]);
                    542:                ep++;
                    543:                goto star;
                    544:  
                    545:            case CCL | STAR:
                    546:            case NCCL | STAR:
                    547:                curlp = lp;
                    548:                while (*lp++ && cclass (ep, lp[-1], ep[-1] == (CCL | STAR)));
                    549:                ep += BMAPSIZ;
                    550:                goto star;
                    551:  
                    552:        star:
                    553:                do {
                    554:                    lp--;
                    555:                    if (advance (compex, lp, ep))
                    556:                        return TRUE;
                    557:                } while (lp > curlp);
                    558:                return FALSE;
                    559:  
                    560:            default:
                    561:                fputs("Badly compiled pattern\n",stdout) FLUSH;
                    562:                err = TRUE;
                    563:                return -1;
                    564:        }
                    565:        if (*ep == CEND || *ep == CDOL) {
                    566:            return TRUE;
                    567:     }
                    568:     return FALSE;
                    569: }
                    570:  
                    571: bool
                    572: backref (compex, i, lp)
                    573: register COMPEX *compex;
                    574: register int i;
                    575: register char *lp;
                    576: {
                    577:     register char *bp;
                    578:  
                    579:     bp = compex->braslist[i];
                    580:     while (*lp && *bp == *lp) {
                    581:        bp++;
                    582:        lp++;
                    583:        if (bp >= compex->braelist[i])
                    584:            return TRUE;
                    585:     }
                    586:     return FALSE;
                    587: }
                    588: 
                    589: bool
                    590: cclass (set, c, af)
                    591: register char  *set;
                    592: register int c;
                    593: {
                    594:     c &= 0177;
                    595: #if BITSPERBYTE == 8
                    596:     if (set[c >> 3] & 1 << (c & 7))
                    597: #else
                    598:     if (set[c / BITSPERBYTE] & 1 << (c % BITSPERBYTE))
                    599: #endif
                    600:        return af;
                    601:     return !af;
                    602: }

unix.superglobalmegacorp.com

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