|
|
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.