1: /***************************************************************************
   2:  * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
   3:  * is provided to you without charge, and with no warranty.  You may give  *
   4:  * away copies of JOVE, including sources, provided that this notice is    *
   5:  * included in all the files.                                              *
   6:  ***************************************************************************/
   7: 
   8: /* search package */
   9: 
  10: #include "jove.h"
  11: #include "ctype.h"
  12: #ifdef MAC
  13: #	undef private
  14: #	define private
  15: #endif
  16: 
  17: #ifdef  LINT_ARGS
  18: private char * insert(char *, char *, int);
  19: 
  20: private void
  21:     REreset(void),
  22:     search(int, int, int);
  23: private int
  24:     backref(int, char *),
  25:     do_comp(int),
  26:     member(char *, int, int),
  27:     REgetc(void),
  28:     REmatch(char *, char *);
  29: #else
  30: private char * insert();
  31: 
  32: private void
  33:     REreset(),
  34:     search();
  35: private int
  36:     backref(),
  37:     do_comp(),
  38:     member(),
  39:     REgetc(),
  40:     REmatch();
  41: #endif	/* LINT_ARGS */
  42: 
  43: #ifdef MAC
  44: #	undef private
  45: #	define private static
  46: #endif
  47: 
  48: #define NALTS   16  /* number of alternate search strings */
  49: 
  50: char    searchstr[128],
  51:     compbuf[256],       /* global default compbuf */
  52:     rep_search[128],    /* replace search string */
  53:     rep_str[128],       /* contains replacement string */
  54:     *cur_compb,     /* usually points at compbuf */
  55:     REbuf[LBSIZE],      /* points at line we're scanning */
  56:     *alternates[NALTS];
  57: 
  58: int REdirection;
  59: 
  60: int CaseIgnore = 0,
  61:     WrapScan = 0,
  62:     UseRE = 0;
  63: 
  64: #define cind_cmp(a, b)  (CaseEquiv[a] == CaseEquiv[b])
  65: 
  66: private int REpeekc;
  67: private char    *REptr;
  68: 
  69: private int
  70: REgetc()
  71: {
  72:     int c;
  73: 
  74:     if ((c = REpeekc) != -1)
  75:         REpeekc = -1;
  76:     else if (*REptr)
  77:         c = *REptr++;
  78:     else
  79:         c = 0;
  80: 
  81:     return c;
  82: }
  83: 
  84: #define STAR    01  /* Match any number of last RE. */
  85: #define AT_BOL  2   /* ^ */
  86: #define AT_EOL  4   /* $ */
  87: #define AT_BOW  6   /* \< */
  88: #define AT_EOW  8   /* \> */
  89: #define OPENP   10  /* \( */
  90: #define CLOSEP  12  /* \) */
  91: #define CURLYB  14  /* \{ */
  92: 
  93: #define NOSTR   14  /* Codes <= NOSTR can't be *'d. */
  94: 
  95: #define ANYC    NOSTR+2     /* . */
  96: #define NORMC   ANYC+2      /* normal character */
  97: #define CINDC   NORMC+2     /* case independent character */
  98: #define ONE_OF  CINDC+2     /* [xxx] */
  99: #define NONE_OF ONE_OF+2    /* [^xxx] */
 100: #define BACKREF NONE_OF+2   /* \# */
 101: #define EOP BACKREF+2   /* end of pattern */
 102: 
 103: #define NPAR    10  /* [0-9] - 0th is the entire matched string, i.e. & */
 104: private int nparens;
 105: private char    *comp_p,
 106:         *start_p,
 107:         **alt_p,
 108:         **alt_endp;
 109: 
 110: void
 111: REcompile(pattern, re, into_buf, alt_bufp)
 112: char    *pattern,
 113:     *into_buf,
 114:     **alt_bufp;
 115: {
 116:     REptr = pattern;
 117:     REpeekc = -1;
 118:     comp_p = cur_compb = start_p = into_buf;
 119:     alt_p = alt_bufp;
 120:     alt_endp = alt_p + NALTS;
 121:     *alt_p++ = comp_p;
 122:     nparens = 0;
 123:     (void) do_comp(re ? OKAY_RE : NORM);
 124:     *alt_p = 0;
 125: }
 126: 
 127: /* compile the pattern into an internal code */
 128: 
 129: private int
 130: do_comp(kind)
 131: {
 132:     char    *last_p,
 133:         *chr_cnt = 0;
 134:     int parens[NPAR],
 135:         *parenp,
 136:         c,
 137:         ret_code;
 138: 
 139:     parenp = parens;
 140:     last_p = 0;
 141:     ret_code = 1;
 142: 
 143:     if (kind == OKAY_RE) {
 144:         *comp_p++ = OPENP;
 145:         *comp_p++ = nparens;
 146:         *parenp++ = nparens++;
 147:         start_p = comp_p;
 148:     }
 149: 
 150:     while (c = REgetc()) {
 151:         if (comp_p > &cur_compb[(sizeof compbuf) - 6])
 152: toolong:        complain("Search string too long/complex.");
 153:         if (c != '*')
 154:             last_p = comp_p;
 155: 
 156:         if (kind == NORM && index(".[*", c) != 0)
 157:             goto defchar;
 158:         switch (c) {
 159:         case '\\':
 160:             switch (c = REgetc()) {
 161:             case 0:
 162:                 complain("Premature end of pattern.");
 163: 
 164:             case '{':
 165:                 {
 166:                     char    *wcntp;     /* word count */
 167: 
 168:                     *comp_p++ = CURLYB;
 169:                     wcntp = comp_p;
 170:                     *comp_p++ = 0;
 171:                     for (;;) {
 172:                         int comp_val;
 173:                         char    *comp_len;
 174: 
 175:                         comp_len = comp_p++;
 176:                         comp_val = do_comp(IN_CB);
 177:                         *comp_len = comp_p - comp_len;
 178:                         (*wcntp) += 1;
 179:                         if (comp_val == 0)
 180:                             break;
 181:                     }
 182:                     break;
 183:                 }
 184: 
 185:             case '}':
 186:                 if (kind != IN_CB)
 187:                     complain("Unexpected \\}.");
 188:                 ret_code = 0;
 189:                 goto outahere;
 190: 
 191:             case '(':
 192:                 if (nparens >= NPAR)
 193:                     complain("Too many ('s; max is %d.", NPAR);
 194:                 *comp_p++ = OPENP;
 195:                 *comp_p++ = nparens;
 196:                 *parenp++ = nparens++;
 197:                 break;
 198: 
 199:             case ')':
 200:                 if (parenp == parens)
 201:                     complain("Too many )'s.");
 202:                 *comp_p++ = CLOSEP;
 203:                 *comp_p++ = *--parenp;
 204:                 break;
 205: 
 206:             case '|':
 207:                 if (alt_p >= alt_endp)
 208:                     complain("Too many alternates; max %d.", NALTS);
 209:                 *comp_p++ = CLOSEP;
 210:                 *comp_p++ = *--parenp;
 211:                 *comp_p++ = EOP;
 212:                 *alt_p++ = comp_p;
 213:                 nparens = 0;
 214:                 *comp_p++ = OPENP;
 215:                 *comp_p++ = nparens;
 216:                 *parenp++ = nparens++;
 217:                 start_p = comp_p;
 218:                 break;
 219: 
 220:             case '1':
 221:             case '2':
 222:             case '3':
 223:             case '4':
 224:             case '5':
 225:             case '6':
 226:             case '7':
 227:             case '8':
 228:             case '9':
 229:                 *comp_p++ = BACKREF;
 230:                 *comp_p++ = c - '0';
 231:                 break;
 232: 
 233:             case '<':
 234:                 *comp_p++ = AT_BOW;
 235:                 break;
 236: 
 237:             case '>':
 238:                 *comp_p++ = AT_EOW;
 239:                 break;
 240: 
 241:             default:
 242:                 goto defchar;
 243:             }
 244:             break;
 245: 
 246:         case ',':
 247:             if (kind != IN_CB)
 248:                 goto defchar;
 249:             goto outahere;
 250: 
 251:         case '.':
 252:             *comp_p++ = ANYC;
 253:             break;
 254: 
 255:         case '^':
 256:             if (comp_p == start_p) {
 257:                 *comp_p++ = AT_BOL;
 258:                 break;
 259:             }
 260:             goto defchar;
 261: 
 262:         case '$':
 263:             if ((REpeekc = REgetc()) != 0 && REpeekc != '\\')
 264:                 goto defchar;
 265:             *comp_p++ = AT_EOL;
 266:             break;
 267: 
 268:         case '[':
 269:             {
 270:                 int chrcnt;
 271: 
 272:                 *comp_p++ = ONE_OF;
 273:             if (comp_p + 16 >= &cur_compb[(sizeof compbuf)])
 274:                 goto toolong;
 275:                 bzero(comp_p, 16);
 276:                 if ((REpeekc = REgetc()) == '^') {
 277:                     *last_p = NONE_OF;
 278:                     /* Get it for real this time. */
 279:                     (void) REgetc();
 280:                 }
 281:                 chrcnt = 1;
 282:                 while ((c = REgetc()) != ']' && c != 0) {
 283:                     if (c == '\\')
 284:                         c = REgetc();
 285:                 else if ((REpeekc = REgetc()) == '-') {
 286:                     int c2;
 287: 
 288:                     (void) REgetc();     /* reread '-' */
 289:                     c2 = REgetc();
 290:                     while (c < c2) {
 291:                         comp_p[c/8] |= (1 << (c%8));
 292:                         c += 1;
 293:                     }
 294:                 }
 295:                 comp_p[c/8] |= (1 << (c%8));
 296:                     chrcnt += 1;
 297:                 }
 298:                 if (c == 0)
 299:                     complain("Missing ].");
 300:                 if (chrcnt == 1)
 301:                     complain("Empty [].");
 302:                 comp_p += 16;
 303:                 break;
 304:             }
 305: 
 306:         case '*':
 307:             if (last_p == 0 || *last_p <= NOSTR)
 308:                 goto defchar;
 309: 
 310:             /* The * operator applies only to the previous
 311: 			   character.  If we were building a chr_cnt at
 312: 			   the time we got the *, we have to remove the
 313: 			   last character from the chr_cnt (by decrementing
 314: 			   *chr_cnt) and replacing it with a new STAR entry.
 315: 
 316: 			   If we are decrementing the count to 0, we just
 317: 			   delete the chr_cnt entry altogether, replacing
 318: 			   it with the STAR entry. */
 319: 
 320:             if (chr_cnt) {
 321:                 char    lastc = chr_cnt[*chr_cnt];
 322: 
 323:             /* The * operator applies only to the previous
 324:  			   character.  If we were building a chr_cnt at
 325:  			   the time we got the *, we have to remove the
 326:  			   last character from the chr_cnt (by decrementing
 327:  			   *chr_cnt) and replacing it with a new STAR entry.
 328: 
 329:  			   If we are decrementing the count to 0, we just
 330:  			   delete the chr_cnt entry altogether, replacing
 331:  			   it with the STAR entry. */
 332: 
 333:                 if (*chr_cnt == 1) {
 334:                     comp_p = chr_cnt;
 335:                     comp_p[-1] |= STAR;
 336:                     *comp_p++ = lastc;
 337:                 } else {
 338:                     comp_p = chr_cnt + *chr_cnt;
 339:                     (*chr_cnt) -= 1;
 340:                     *comp_p++ = chr_cnt[-1] | STAR;
 341:                     *comp_p++ = lastc;
 342:                 }
 343:             } else
 344:                 *last_p |= STAR;
 345:             break;
 346:         default:
 347: defchar:        if (chr_cnt)
 348:                 (*chr_cnt) += 1;
 349:             else {
 350:                 *comp_p++ = (CaseIgnore) ? CINDC : NORMC;
 351:                 chr_cnt = comp_p++;
 352:                 *chr_cnt = 1;   /* last_p[1] = 1; */
 353:             }
 354:             *comp_p++ = c;
 355:             continue;
 356:         }
 357:         chr_cnt = FALSE;
 358:     }
 359: outahere:
 360:     /* End of pattern, let's do some error checking. */
 361:     if (kind == OKAY_RE) {
 362:         *comp_p++ = CLOSEP;
 363:         *comp_p++ = *--parenp;
 364:     }
 365:     if (parenp != parens)
 366:         complain("Unmatched ()'s.");
 367:     if (kind == IN_CB && c == 0)    /* End of pattern with \}. */
 368:         complain("Missing \\}.");
 369:     *comp_p++ = EOP;
 370: 
 371:     return ret_code;
 372: }
 373: 
 374: private char    *pstrtlst[NPAR],    /* index into REbuf */
 375:         *pendlst[NPAR],
 376:         *REbolp,
 377:         *locs,
 378:         *loc1,
 379:         *loc2;
 380: 
 381: int REbom,
 382:     REeom,      /* beginning and end of match */
 383:     REalt_num;  /* if alternatives, which one matched? */
 384: 
 385: private int
 386: backref(n, linep)
 387: register char   *linep;
 388: {
 389:     register char   *backsp,
 390:             *backep;
 391: 
 392:     backsp = pstrtlst[n];
 393:     backep = pendlst[n];
 394:     while (*backsp++ == *linep++)
 395:         if (backsp >= backep)
 396:             return 1;
 397:     return 0;
 398: }
 399: 
 400: private int
 401: member(comp_p, c, af)
 402: register char   *comp_p;
 403: register int    c,
 404:         af;
 405: {
 406:     if (c == 0)
 407:         return 0;   /* try to match EOL always fails */
 408:     if (comp_p[c/8] & (1 << (c%8)))
 409:         return af;
 410:     return !af;
 411: }
 412: 
 413: private int
 414: REmatch(linep, comp_p)
 415: register char   *linep,
 416:         *comp_p;
 417: {
 418:     char    *first_p = linep;
 419:     register int    n;
 420: 
 421:     for (;;) switch (*comp_p++) {
 422:     case NORMC:
 423:         n = *comp_p++;
 424:         while (--n >= 0)
 425:             if (*linep++ != *comp_p++)
 426:                 return 0;
 427:         continue;
 428: 
 429:     case CINDC: /* case independent comparison */
 430:         n = *comp_p++;
 431:         while (--n >= 0)
 432:             if (!cind_cmp(*linep++, *comp_p++))
 433:                 return 0;
 434:         continue;
 435: 
 436:     case EOP:
 437:         loc2 = linep;
 438:         REeom = (loc2 - REbolp);
 439:         return 1;   /* Success! */
 440: 
 441:     case AT_BOL:
 442:         if (linep == REbolp)
 443:             continue;
 444:         return 0;
 445: 
 446:     case AT_EOL:
 447:         if (*linep == 0)
 448:             continue;
 449:         return 0;
 450: 
 451:     case ANYC:
 452:         if (*linep++ != 0)
 453:             continue;
 454:         return 0;
 455: 
 456:     case AT_BOW:
 457:         if (ismword(*linep) && (linep == REbolp || !ismword(linep[-1])))
 458:             continue;
 459:         return 0;
 460: 
 461:     case AT_EOW:
 462:         if ((*linep == 0 || !ismword(*linep)) &&
 463:             (linep != REbolp && ismword(linep[-1])))
 464:             continue;
 465:         return 0;
 466: 
 467:     case ONE_OF:
 468:     case NONE_OF:
 469:         if (member(comp_p, *linep++, comp_p[-1] == ONE_OF)) {
 470:             comp_p += 16;
 471:             continue;
 472:         }
 473:         return 0;
 474: 
 475:     case OPENP:
 476:         pstrtlst[*comp_p++] = linep;
 477:         continue;
 478: 
 479:     case CLOSEP:
 480:         pendlst[*comp_p++] = linep;
 481:         continue;
 482: 
 483:     case BACKREF:
 484:         if (pstrtlst[n = *comp_p++] == 0) {
 485:             s_mess("\\%d was not specified.", n + 1);
 486:             return 0;
 487:         }
 488:         if (backref(n, linep)) {
 489:             linep += pendlst[n] - pstrtlst[n];
 490:             continue;
 491:         }
 492:         return 0;
 493: 
 494:     case CURLYB:
 495:         {
 496:             int wcnt,
 497:                 any;
 498: 
 499:             wcnt = *comp_p++;
 500:             any = 0;
 501: 
 502:             while (--wcnt >= 0) {
 503:                 if (any == 0)
 504:                     any = REmatch(linep, comp_p + 1);
 505:                 comp_p += *comp_p;
 506:             }
 507:             if (any == 0)
 508:                 return 0;
 509:             linep = loc2;
 510:             continue;
 511:         }
 512: 
 513:     case ANYC | STAR:
 514:         first_p = linep;
 515:         while (*linep++)
 516:             ;
 517:         goto star;
 518: 
 519:     case NORMC | STAR:
 520:         first_p = linep;
 521:         while (*comp_p == *linep++)
 522:             ;
 523:         comp_p += 1;
 524:         goto star;
 525: 
 526:     case CINDC | STAR:
 527:         first_p = linep;
 528:         while (cind_cmp(*comp_p, *linep++))
 529:             ;
 530:         comp_p += 1;
 531:         goto star;
 532: 
 533:     case ONE_OF | STAR:
 534:     case NONE_OF | STAR:
 535:         first_p = linep;
 536:         while (member(comp_p, *linep++, comp_p[-1] == (ONE_OF | STAR)))
 537:             ;
 538:         comp_p += 16;
 539:         goto star;
 540: 
 541:     case BACKREF | STAR:
 542:         first_p = linep;
 543:         n = *comp_p++;
 544:         while (backref(n, linep))
 545:             linep += pendlst[n] - pstrtlst[n];
 546:         while (linep >= first_p) {
 547:             if (REmatch(linep, comp_p))
 548:                 return 1;
 549:             linep -= pendlst[n] - pstrtlst[n];
 550:         }
 551:         continue;
 552: 
 553: star:       do {
 554:             linep -= 1;
 555:             if (linep < locs)
 556:                 break;
 557:             if (REmatch(linep, comp_p))
 558:                 return 1;
 559:         } while (linep > first_p);
 560:         return 0;
 561: 
 562:     default:
 563:         complain("RE error match (%d).", comp_p[-1]);
 564:     }
 565:     /* NOTREACHED. */
 566: }
 567: 
 568: private void
 569: REreset()
 570: {
 571:     register int    i;
 572: 
 573:     for (i = 0; i < NPAR; i++)
 574:         pstrtlst[i] = pendlst[i] = 0;
 575: }
 576: 
 577: /* Index LINE at OFFSET, the compiled EXPR, with alternates ALTS.  If
 578:    lbuf_okay is nonzero it's okay to use linebuf if LINE is the current
 579:    line.  This should save lots of time in things like paren matching in
 580:    LISP mode.  Saves all that copying from linebuf to REbuf.  substitute()
 581:    is the guy who calls re_lindex with lbuf_okay as 0, since the substitution
 582:    gets placed in linebuf ... doesn't work too well when the source and
 583:    destination strings are the same.  I hate all these arguments!
 584: 
 585:    This code is cumbersome, repetetive for reasons of efficiency.  Fast
 586:    search is a must as far as I am concerned. */
 587: 
 588: int
 589: re_lindex(line, offset, expr, alts, lbuf_okay)
 590: Line    *line;
 591: char    *expr,
 592:     **alts;
 593: {
 594:     int isquick;
 595:     register int    firstc,
 596:             c;
 597:     register char   *resp;
 598: 
 599:     REreset();
 600:     if (lbuf_okay) {
 601:         REbolp = lbptr(line);
 602:         if (offset == -1)
 603:             offset = strlen(REbolp);    /* arg! */
 604:     } else {
 605:         REbolp = ltobuf(line, REbuf);
 606:         if (offset == -1) { /* Reverse search, find end of line. */
 607:             extern int  Jr_Len;
 608: 
 609:             offset = Jr_Len;    /* Just Read Len. */
 610:         }
 611:     }
 612:     resp = REbolp;
 613:     isquick = ((expr[0] == NORMC || expr[0] == CINDC) &&
 614:            (alternates[1] == 0));
 615:     if (isquick) {
 616:         firstc = expr[2];
 617:         if (expr[0] == CINDC)
 618:             firstc = CaseEquiv[firstc];
 619:     }
 620:     locs = REbolp + offset;
 621: 
 622:     if (REdirection == FORWARD) {
 623:         do {
 624:         char    **altp = alts;
 625: 
 626:         if (isquick) {
 627:             if (expr[0] == NORMC)
 628:                 while ((c = *locs++) != 0 && c != firstc)
 629:                     ;
 630:             else
 631:                 while (((c = *locs++) != 0) &&
 632:                     (CaseEquiv[c] != firstc))
 633:                     ;
 634:             if (*--locs == 0)
 635:                 break;
 636:         }
 637:         REalt_num = 1;
 638:         while (*altp) {
 639:             if (REmatch(locs, *altp++)) {
 640:                 loc1 = locs;
 641:                 REbom = loc1 - REbolp;
 642:                 return 1;
 643:             }
 644:             REalt_num += 1;
 645:         }
 646:         } while (*locs++);
 647:     } else {
 648:         do {
 649:         char    **altp = alts;
 650: 
 651:         if (isquick) {
 652:             if (expr[0] == NORMC) {
 653:                 while (locs >= REbolp && *locs-- != firstc)
 654:                     ;
 655:                 if (*++locs != firstc)
 656:                     break;
 657:             } else {
 658:                 while (locs >= REbolp && CaseEquiv[*locs--] != firstc)
 659:                     ;
 660:                 if (CaseEquiv[*++locs] != firstc)
 661:                     break;
 662:             }
 663:         }
 664:         REalt_num = 1;
 665:         while (*altp) {
 666:             if (REmatch(locs, *altp++)) {
 667:                 loc1 = locs;
 668:                 REbom = loc1 - REbolp;
 669:                 return 1;
 670:             }
 671:             REalt_num += 1;
 672:         }
 673:         } while (--locs >= resp);
 674:     }
 675: 
 676:     return 0;
 677: }
 678: 
 679: int okay_wrap = 0;  /* Do a wrap search ... not when we're
 680: 			   parsing errors ... */
 681: 
 682: Bufpos *
 683: dosearch(pattern, dir, re)
 684: char    *pattern;
 685: {
 686:     Bufpos  *pos;
 687: 
 688:     if (bobp() && eobp())   /* Can't match!  There's no buffer. */
 689:         return 0;
 690: 
 691:     REcompile(pattern, re, compbuf, alternates);
 692: 
 693:     pos = docompiled(dir, compbuf, alternates);
 694:     return pos;
 695: }
 696: 
 697: Bufpos *
 698: docompiled(dir, expr, alts)
 699: char    *expr,
 700:     **alts;
 701: {
 702:     static Bufpos   ret;
 703:     register Line   *lp;
 704:     register int    offset;
 705:     int we_wrapped = NO;
 706: 
 707:     lsave();
 708:     /* Search now lsave()'s so it doesn't make any assumptions on
 709: 	   whether the the contents of curline/curchar are in linebuf.
 710: 	   Nowhere does search write all over linebuf.  However, we have to
 711: 	   be careful about what calls we make here, because many of them
 712: 	   assume (and rightly so) that curline is in linebuf. */
 713: 
 714:     REdirection = dir;
 715:     lp = curline;
 716:     offset = curchar;
 717:     if (dir == BACKWARD) {
 718:         if (bobp()) {
 719:             if (okay_wrap && WrapScan)
 720:                 goto doit;
 721:             return 0;
 722:         }
 723:         /* here we simulate BackChar() */
 724:         if (bolp()) {
 725:             lp = lp->l_prev;
 726:             offset = strlen(lbptr(lp));
 727:         } else
 728:             offset -= 1;
 729:     } else if ((dir == FORWARD) &&
 730:            (lbptr(lp)[offset] == '\0') &&
 731:            !lastp(lp)) {
 732:         lp = lp->l_next;
 733:         offset = 0;
 734:     }
 735: 
 736:     do {
 737:         if (re_lindex(lp, offset, expr, alts, YES))
 738:             break;
 739: doit:       lp = (dir == FORWARD) ? lp->l_next : lp->l_prev;
 740:         if (lp == 0) {
 741:             if (okay_wrap && WrapScan) {
 742:                 lp = (dir == FORWARD) ?
 743:                      curbuf->b_first : curbuf->b_last;
 744:                 we_wrapped = YES;
 745:             } else
 746:                  break;
 747:         }
 748:         if (dir == FORWARD)
 749:             offset = 0;
 750:         else
 751:             offset = -1;    /* signals re_lindex ... */
 752:     } while (lp != curline);
 753: 
 754:     if (lp == curline && we_wrapped)
 755:         lp = 0;
 756:     if (lp == 0)
 757:         return 0;
 758:     ret.p_line = lp;
 759:     ret.p_char = (dir == FORWARD) ? REeom : REbom;
 760:     return &ret;
 761: }
 762: 
 763: private char *
 764: insert(off, endp, which)
 765: char    *off,
 766:     *endp;
 767: {
 768:     register char   *pp;
 769:     register int    n;
 770: 
 771:     n = pendlst[which] - pstrtlst[which];
 772:     pp = pstrtlst[which];
 773:     while (--n >= 0) {
 774:         *off++ = *pp++;
 775:         if (off >= endp)
 776:             len_error(ERROR);
 777:     }
 778:     return off;
 779: }
 780: 
 781: /* Perform the substitution.  If DELP is nonzero the matched string is
 782:    deleted, i.e., the substitution string is not inserted. */
 783: 
 784: void
 785: re_dosub(tobuf, delp)
 786: char    *tobuf;
 787: {
 788:     register char   *tp,
 789:             *rp,
 790:             *repp;
 791:     int c;
 792:     char    *endp;
 793: 
 794:     tp = tobuf;
 795:     endp = tp + LBSIZE;
 796:     rp = REbuf;
 797:     repp = rep_str;
 798: 
 799:     while (rp < loc1)
 800:         *tp++ = *rp++;
 801: 
 802:     if (!delp) while (c = *repp++) {
 803:         if (c == '\\') {
 804:             c = *repp++;
 805:             if (c == '\0') {
 806:                 *tp++ = '\\';
 807:                 goto endchk;
 808:             } else if (c >= '1' && c <= nparens + '1') {
 809:                 tp = insert(tp, endp, c - '0');
 810:                 continue;
 811:             }
 812:         } else if (c == '&') {
 813:             tp = insert(tp, endp, 0);
 814:             continue;
 815:         }
 816:         *tp++ = c;
 817: endchk:     if (tp >= endp)
 818:             len_error(ERROR);
 819:     }
 820:     rp = loc2;
 821:     loc2 = REbuf + max(1, tp - tobuf);
 822:     REeom = loc2 - REbuf;
 823:     /* At least one character past the match, to prevent an infinite
 824: 	   number of replacements in the same position, e.g.,
 825: 	   replace "^" with "". */
 826:     while (*tp++ = *rp++)
 827:         if (tp >= endp)
 828:             len_error(ERROR);
 829: }
 830: 
 831: void
 832: putmatch(which, buf, size)
 833: char    *buf;
 834: {
 835:     *(insert(buf, buf + size, which)) = 0;
 836: }
 837: 
 838: void
 839: setsearch(str)
 840: char    *str;
 841: {
 842:     strcpy(searchstr, str);
 843: }
 844: 
 845: char *
 846: getsearch()
 847: {
 848:     return searchstr;
 849: }
 850: 
 851: void
 852: RErecur()
 853: {
 854:     char    sbuf[sizeof searchstr],
 855:         cbuf[sizeof compbuf],
 856:         repbuf[sizeof rep_str],
 857:         *altbuf[NALTS];
 858:     int npars;
 859:     Mark    *m = MakeMark(curline, REbom, M_FLOATER);
 860: 
 861:     message("Type C-X C-C to continue with query replace.");
 862: 
 863:     npars = nparens;
 864:     byte_copy(compbuf, cbuf, sizeof compbuf);
 865:     byte_copy(searchstr, sbuf, sizeof searchstr);
 866:     byte_copy(rep_str, repbuf, sizeof rep_str);
 867:     byte_copy((char *) alternates, (char *) altbuf, sizeof alternates);
 868:     Recur();
 869:     nparens = npars;
 870:     byte_copy(cbuf, compbuf, sizeof compbuf);
 871:     byte_copy(sbuf, searchstr, sizeof searchstr);
 872:     byte_copy(repbuf, rep_str, sizeof rep_str);
 873:     byte_copy((char *) altbuf, (char *) alternates, sizeof alternates);
 874:     if (!is_an_arg())
 875:         ToMark(m);
 876:     DelMark(m);
 877: }
 878: 
 879: void
 880: ForSearch()
 881: {
 882:     search(FORWARD, UseRE, YES);
 883: }
 884: 
 885: void
 886: RevSearch()
 887: {
 888:     search(BACKWARD, UseRE, YES);
 889: }
 890: 
 891: void
 892: FSrchND()
 893: {
 894:     search(FORWARD, UseRE, NO);
 895: }
 896: 
 897: void
 898: RSrchND()
 899: {
 900:     search(BACKWARD, UseRE, NO);
 901: }
 902: 
 903: private void
 904: search(dir, re, setdefault)
 905: {
 906:     Bufpos  *newdot;
 907:     char    *s;
 908: 
 909:     s = ask(searchstr, ProcFmt);
 910:     if (setdefault)
 911:         setsearch(s);
 912:     okay_wrap = YES;
 913:     newdot = dosearch(s, dir, re);
 914:     okay_wrap = NO;
 915:     if (newdot == 0) {
 916:         if (WrapScan)
 917:             complain("No \"%s\" in buffer.", s);
 918:         else
 919:             complain("No \"%s\" found to %s.", s,
 920:                  (dir == FORWARD) ? "bottom" : "top");
 921:     }
 922:     PushPntp(newdot->p_line);
 923:     SetDot(newdot);
 924: }
 925: 
 926: /* Do we match PATTERN at OFFSET in BUF? */
 927: 
 928: int
 929: LookingAt(pattern, buf, offset)
 930: char    *pattern,
 931:     *buf;
 932: {
 933:     register char   **alt = alternates;
 934: 
 935:     REcompile(pattern, 1, compbuf, alternates);
 936:     REreset();
 937:     locs = buf + offset;
 938:     REbolp = buf;
 939: 
 940:     while (*alt)
 941:         if (REmatch(locs, *alt++))
 942:             return 1;
 943:     return 0;
 944: }
 945: 
 946: int
 947: look_at(expr)
 948: char    *expr;
 949: {
 950:     REcompile(expr, 0, compbuf, alternates);
 951:     REreset();
 952:     locs = linebuf + curchar;
 953:     REbolp = linebuf;
 954:     if (REmatch(locs, alternates[0]))
 955:         return 1;
 956:     return 0;
 957: }

Defined functions

FSrchND defined in line 891; used 4 times
ForSearch defined in line 879; used 4 times
REgetc defined in line 69; used 12 times
REmatch defined in line 413; used 9 times
RErecur defined in line 851; used 3 times
REreset defined in line 568; used 5 times
RSrchND defined in line 897; used 4 times
RevSearch defined in line 885; used 4 times
backref defined in line 385; used 4 times
do_comp defined in line 129; used 4 times
docompiled defined in line 697; used 5 times
getsearch defined in line 845; used 3 times
insert defined in line 763; used 5 times
look_at defined in line 946; used 3 times
member defined in line 400; used 4 times
re_dosub defined in line 784; used 4 times
re_lindex defined in line 588; used 4 times
search defined in line 903; used 6 times
setsearch defined in line 838; used 4 times

Defined variables

CaseIgnore defined in line 60; used 4 times
REalt_num defined in line 383; used 4 times
REbolp defined in line 376; used 15 times
REbom defined in line 381; used 5 times
REbuf defined in line 55; used 4 times
REdirection defined in line 58; used 3 times
REeom defined in line 382; used 6 times
REpeekc defined in line 66; used 7 times
REptr defined in line 67; used 3 times
alt_endp defined in line 108; used 2 times
alt_p defined in line 107; used 6 times
alternates defined in line 56; used 13 times
comp_p defined in line 105; used 80 times
compbuf defined in line 51; used 13 times
cur_compb defined in line 54; used 3 times
loc1 defined in line 378; used 5 times
loc2 defined in line 379; used 6 times
locs defined in line 377; used 21 times
nparens defined in line 104; used 12 times
okay_wrap defined in line 679; used 4 times
pendlst defined in line 375; used 7 times
private defined in line 903; never used
pstrtlst defined in line 374; used 9 times
rep_search defined in line 52; used 5 times
rep_str defined in line 53; used 8 times
searchstr defined in line 50; used 8 times
start_p defined in line 106; used 4 times

Defined macros

ANYC defined in line 95; used 3 times
AT_BOL defined in line 85; used 1 times
AT_BOW defined in line 87; used 1 times
AT_EOL defined in line 86; used 1 times
AT_EOW defined in line 88; used 1 times
BACKREF defined in line 100; used 3 times
CINDC defined in line 97; used 5 times
CLOSEP defined in line 90; used 3 times
CURLYB defined in line 91; used 1 times
EOP defined in line 101; used 2 times
NALTS defined in line 48; used 4 times
NONE_OF defined in line 99; used 3 times
NORMC defined in line 96; used 6 times
NOSTR defined in line 93; used 2 times
NPAR defined in line 103; used 6 times
ONE_OF defined in line 98; used 5 times
OPENP defined in line 89; used 3 times
STAR defined in line 84; used 4 times
cind_cmp defined in line 64; used 2 times
private defined in line 45; used 18 times
Last modified: 1988-12-26
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 620
Valid CSS Valid XHTML 1.0 Strict