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