Annotation of src/usr.bin/mg/search.c, Revision 1.17
1.17 ! cloder 1: /* $OpenBSD: search.c,v 1.14 2005/05/25 23:04:39 cloder Exp $ */
1.4 niklas 2:
1.1 deraadt 3: /*
4: * Search commands.
1.7 mickey 5: * The functions in this file implement the search commands (both plain and
1.3 millert 6: * incremental searches are supported) and the query-replace command.
1.1 deraadt 7: *
1.3 millert 8: * The plain old search code is part of the original MicroEMACS "distribution".
9: * The incremental search code and the query-replace code is by Rich Ellison.
1.1 deraadt 10: */
1.3 millert 11:
12: #include "def.h"
13:
1.1 deraadt 14: #ifndef NO_MACRO
1.3 millert 15: #include "macro.h"
16: #endif /* !NO_MACRO */
1.1 deraadt 17:
1.2 millert 18: #define SRCH_BEGIN (0) /* Search sub-codes. */
1.1 deraadt 19: #define SRCH_FORW (-1)
20: #define SRCH_BACK (-2)
21: #define SRCH_NOPR (-3)
22: #define SRCH_ACCM (-4)
23: #define SRCH_MARK (-5)
24:
1.2 millert 25: typedef struct {
1.3 millert 26: int s_code;
27: LINE *s_dotp;
28: int s_doto;
29: } SRCHCOM;
30:
1.9 millert 31: static int isearch(int);
32: static void is_cpush(int);
33: static void is_lpush(void);
34: static void is_pop(void);
35: static int is_peek(void);
36: static void is_undo(int *, int *);
37: static int is_find(int);
38: static void is_prompt(int, int, int);
39: static void is_dspl(char *, int);
1.13 jason 40: static int eq(int, int, int);
1.3 millert 41:
42: static SRCHCOM cmds[NSRCH];
43: static int cip;
44:
45: int srch_lastdir = SRCH_NOPR; /* Last search flags. */
46:
47: /*
48: * Search forward. Get a search string from the user, and search for it
1.7 mickey 49: * starting at ".". If found, "." gets moved to just after the matched
50: * characters, and display does all the hard stuff. If not found, it just
1.3 millert 51: * prints a message.
1.1 deraadt 52: */
1.2 millert 53: /* ARGSUSED */
1.3 millert 54: int
1.10 cloder 55: forwsearch(int f, int n)
1.1 deraadt 56: {
1.3 millert 57: int s;
1.1 deraadt 58:
1.2 millert 59: if ((s = readpattern("Search")) != TRUE)
1.12 db 60: return (s);
1.1 deraadt 61: if (forwsrch() == FALSE) {
62: ewprintf("Search failed: \"%s\"", pat);
1.12 db 63: return (FALSE);
1.1 deraadt 64: }
65: srch_lastdir = SRCH_FORW;
1.12 db 66: return (TRUE);
1.1 deraadt 67: }
68:
69: /*
1.7 mickey 70: * Reverse search. Get a search string from the user, and search, starting
71: * at "." and proceeding toward the front of the buffer. If found "." is
72: * left pointing at the first character of the pattern [the last character
1.3 millert 73: * that was matched].
1.1 deraadt 74: */
1.2 millert 75: /* ARGSUSED */
1.3 millert 76: int
1.10 cloder 77: backsearch(int f, int n)
1.1 deraadt 78: {
1.3 millert 79: int s;
1.1 deraadt 80:
1.2 millert 81: if ((s = readpattern("Search backward")) != TRUE)
1.1 deraadt 82: return (s);
83: if (backsrch() == FALSE) {
84: ewprintf("Search failed: \"%s\"", pat);
1.12 db 85: return (FALSE);
1.1 deraadt 86: }
87: srch_lastdir = SRCH_BACK;
1.12 db 88: return (TRUE);
1.1 deraadt 89: }
90:
91: /*
1.7 mickey 92: * Search again, using the same search string and direction as the last
93: * search command. The direction has been saved in "srch_lastdir", so you
1.3 millert 94: * know which way to go.
1.1 deraadt 95: */
1.2 millert 96: /* ARGSUSED */
1.3 millert 97: int
1.10 cloder 98: searchagain(int f, int n)
1.1 deraadt 99: {
100: if (srch_lastdir == SRCH_FORW) {
101: if (forwsrch() == FALSE) {
102: ewprintf("Search failed: \"%s\"", pat);
1.12 db 103: return (FALSE);
1.1 deraadt 104: }
1.12 db 105: return (TRUE);
1.1 deraadt 106: }
107: if (srch_lastdir == SRCH_BACK) {
108: if (backsrch() == FALSE) {
109: ewprintf("Search failed: \"%s\"", pat);
1.12 db 110: return (FALSE);
1.1 deraadt 111: }
1.12 db 112: return (TRUE);
1.1 deraadt 113: }
114: ewprintf("No last search");
1.12 db 115: return (FALSE);
1.1 deraadt 116: }
117:
118: /*
1.7 mickey 119: * Use incremental searching, initially in the forward direction.
1.1 deraadt 120: * isearch ignores any explicit arguments.
121: */
1.2 millert 122: /* ARGSUSED */
1.3 millert 123: int
1.10 cloder 124: forwisearch(int f, int n)
1.1 deraadt 125: {
1.12 db 126: return (isearch(SRCH_FORW));
1.1 deraadt 127: }
128:
129: /*
130: * Use incremental searching, initially in the reverse direction.
131: * isearch ignores any explicit arguments.
132: */
1.2 millert 133: /* ARGSUSED */
1.3 millert 134: int
1.10 cloder 135: backisearch(int f, int n)
1.1 deraadt 136: {
1.12 db 137: return (isearch(SRCH_BACK));
1.1 deraadt 138: }
139:
140: /*
141: * Incremental Search.
142: * dir is used as the initial direction to search.
143: * ^S switch direction to forward
144: * ^R switch direction to reverse
145: * ^Q quote next character (allows searching for ^N etc.)
146: * <ESC> exit from Isearch
147: * <DEL> undoes last character typed. (tricky job to do this correctly).
148: * other ^ exit search, don't set mark
149: * else accumulate into search string
150: */
1.3 millert 151: static int
1.10 cloder 152: isearch(int dir)
1.2 millert 153: {
1.3 millert 154: LINE *clp;
155:
156: int c;
157: int cbo;
158: int success;
159: int pptr;
160:
161: char opat[NPAT];
1.1 deraadt 162:
163: #ifndef NO_MACRO
1.2 millert 164: if (macrodef) {
165: ewprintf("Can't isearch in macro");
1.12 db 166: return (FALSE);
1.1 deraadt 167: }
1.3 millert 168: #endif /* !NO_MACRO */
1.2 millert 169: for (cip = 0; cip < NSRCH; cip++)
1.1 deraadt 170: cmds[cip].s_code = SRCH_NOPR;
1.3 millert 171:
1.12 db 172: (void)strlcpy(opat, pat, sizeof(opat));
1.1 deraadt 173: cip = 0;
174: pptr = -1;
175: clp = curwp->w_dotp;
176: cbo = curwp->w_doto;
177: is_lpush();
178: is_cpush(SRCH_BEGIN);
179: success = TRUE;
180: is_prompt(dir, TRUE, success);
1.3 millert 181:
1.1 deraadt 182: for (;;) {
183: update();
1.3 millert 184:
1.1 deraadt 185: switch (c = getkey(FALSE)) {
186: case CCHR('['):
1.5 art 187: /*
188: * If new characters come in the next 300 msec,
189: * we can assume that they belong to a longer
190: * escaped sequence so we should ungetkey the
191: * ESC to avoid writing out garbage.
192: */
193: if (ttwait(300) == FALSE)
194: ungetkey(c);
1.1 deraadt 195: srch_lastdir = dir;
196: curwp->w_markp = clp;
197: curwp->w_marko = cbo;
198: ewprintf("Mark set");
199: return (TRUE);
200: case CCHR('G'):
201: if (success != TRUE) {
202: while (is_peek() == SRCH_ACCM)
203: is_undo(&pptr, &dir);
204: success = TRUE;
205: is_prompt(dir, pptr < 0, success);
206: break;
207: }
208: curwp->w_dotp = clp;
209: curwp->w_doto = cbo;
210: curwp->w_flag |= WFMOVE;
211: srch_lastdir = dir;
1.6 art 212: (void)ctrlg(FFRAND, 0);
1.12 db 213: (void)strlcpy(pat, opat, sizeof(pat));
214: return (ABORT);
1.1 deraadt 215: case CCHR(']'):
216: case CCHR('S'):
217: if (dir == SRCH_BACK) {
218: dir = SRCH_FORW;
219: is_lpush();
220: is_cpush(SRCH_FORW);
221: success = TRUE;
222: }
1.14 cloder 223: if (success == FALSE && dir == SRCH_FORW) {
224: /* wrap the search to beginning */
225: clp = lforw(curbp->b_linep);
226: curwp->w_dotp = clp;
227: curwp->w_doto = 0;
228: if (is_find(dir) != FALSE) {
229: is_cpush(SRCH_MARK);
230: success = TRUE;
231: }
1.1 deraadt 232: break;
1.14 cloder 233: }
234:
1.1 deraadt 235: is_lpush();
236: pptr = strlen(pat);
1.6 art 237: (void)forwchar(FFRAND, 1);
1.2 millert 238: if (is_find(SRCH_FORW) != FALSE)
239: is_cpush(SRCH_MARK);
1.1 deraadt 240: else {
1.6 art 241: (void)backchar(FFRAND, 1);
1.1 deraadt 242: ttbeep();
243: success = FALSE;
244: }
245: is_prompt(dir, pptr < 0, success);
246: break;
247: case CCHR('R'):
248: if (dir == SRCH_FORW) {
249: dir = SRCH_BACK;
250: is_lpush();
251: is_cpush(SRCH_BACK);
252: success = TRUE;
253: }
1.14 cloder 254: if (success == FALSE && dir == SRCH_BACK) {
255: /* wrap the search to end */
256: clp = lback(curbp->b_linep);
257: curwp->w_dotp = clp;
258: curwp->w_doto =
259: llength(curwp->w_dotp);
260: if (is_find(dir) != FALSE) {
261: is_cpush(SRCH_MARK);
262: success = TRUE;
263: }
1.1 deraadt 264: break;
1.14 cloder 265: }
1.1 deraadt 266: is_lpush();
267: pptr = strlen(pat);
1.6 art 268: (void)backchar(FFRAND, 1);
1.2 millert 269: if (is_find(SRCH_BACK) != FALSE)
270: is_cpush(SRCH_MARK);
1.1 deraadt 271: else {
1.6 art 272: (void)forwchar(FFRAND, 1);
1.1 deraadt 273: ttbeep();
274: success = FALSE;
275: }
276: is_prompt(dir, pptr < 0, success);
277: break;
278: case CCHR('H'):
279: case CCHR('?'):
280: is_undo(&pptr, &dir);
1.2 millert 281: if (is_peek() != SRCH_ACCM)
282: success = TRUE;
1.1 deraadt 283: is_prompt(dir, pptr < 0, success);
284: break;
285: case CCHR('\\'):
286: case CCHR('Q'):
1.3 millert 287: c = (char)getkey(FALSE);
1.2 millert 288: goto addchar;
1.1 deraadt 289: case CCHR('M'):
290: c = CCHR('J');
1.2 millert 291: goto addchar;
1.1 deraadt 292: default:
293: if (ISCTRL(c)) {
294: ungetkey(c);
295: curwp->w_markp = clp;
296: curwp->w_marko = cbo;
297: ewprintf("Mark set");
298: curwp->w_flag |= WFMOVE;
1.12 db 299: return (TRUE);
1.1 deraadt 300: } /* and continue */
301: case CCHR('I'):
302: case CCHR('J'):
1.2 millert 303: addchar:
1.1 deraadt 304: if (pptr == -1)
305: pptr = 0;
306: if (pptr == 0)
307: success = TRUE;
308: pat[pptr++] = c;
309: if (pptr == NPAT) {
310: ewprintf("Pattern too long");
1.12 db 311: return (FALSE);
1.1 deraadt 312: }
313: pat[pptr] = '\0';
314: is_lpush();
315: if (success != FALSE) {
316: if (is_find(dir) != FALSE)
317: is_cpush(c);
318: else {
319: success = FALSE;
320: ttbeep();
321: is_cpush(SRCH_ACCM);
322: }
323: } else
324: is_cpush(SRCH_ACCM);
325: is_prompt(dir, FALSE, success);
326: }
327: }
1.2 millert 328: /* NOTREACHED */
1.1 deraadt 329: }
330:
1.6 art 331: static void
1.10 cloder 332: is_cpush(int cmd)
1.2 millert 333: {
1.1 deraadt 334: if (++cip >= NSRCH)
335: cip = 0;
336: cmds[cip].s_code = cmd;
337: }
338:
1.6 art 339: static void
1.10 cloder 340: is_lpush(void)
1.2 millert 341: {
1.3 millert 342: int ctp;
1.1 deraadt 343:
1.2 millert 344: ctp = cip + 1;
1.1 deraadt 345: if (ctp >= NSRCH)
346: ctp = 0;
347: cmds[ctp].s_code = SRCH_NOPR;
348: cmds[ctp].s_doto = curwp->w_doto;
349: cmds[ctp].s_dotp = curwp->w_dotp;
350: }
351:
1.6 art 352: static void
1.10 cloder 353: is_pop(void)
1.2 millert 354: {
1.1 deraadt 355: if (cmds[cip].s_code != SRCH_NOPR) {
1.2 millert 356: curwp->w_doto = cmds[cip].s_doto;
357: curwp->w_dotp = cmds[cip].s_dotp;
1.1 deraadt 358: curwp->w_flag |= WFMOVE;
359: cmds[cip].s_code = SRCH_NOPR;
360: }
361: if (--cip <= 0)
1.2 millert 362: cip = NSRCH - 1;
1.1 deraadt 363: }
364:
365: static int
1.10 cloder 366: is_peek(void)
1.2 millert 367: {
1.12 db 368: return (cmds[cip].s_code);
1.1 deraadt 369: }
370:
371: /* this used to always return TRUE (the return value was checked) */
1.6 art 372: static void
1.10 cloder 373: is_undo(int *pptr, int *dir)
1.2 millert 374: {
1.3 millert 375: int redo = FALSE;
376:
1.1 deraadt 377: switch (cmds[cip].s_code) {
378: case SRCH_BEGIN:
379: case SRCH_NOPR:
380: *pptr = -1;
381: case SRCH_MARK:
382: break;
383: case SRCH_FORW:
384: *dir = SRCH_BACK;
385: redo = TRUE;
386: break;
387: case SRCH_BACK:
388: *dir = SRCH_FORW;
389: redo = TRUE;
390: break;
391: case SRCH_ACCM:
392: default:
393: *pptr -= 1;
394: if (*pptr < 0)
395: *pptr = 0;
396: pat[*pptr] = '\0';
397: break;
398: }
399: is_pop();
1.2 millert 400: if (redo)
401: is_undo(pptr, dir);
1.1 deraadt 402: }
403:
404: static int
1.10 cloder 405: is_find(int dir)
1.2 millert 406: {
1.3 millert 407: int plen, odoto;
408: LINE *odotp;
1.1 deraadt 409:
410: odoto = curwp->w_doto;
411: odotp = curwp->w_dotp;
412: plen = strlen(pat);
413: if (plen != 0) {
1.2 millert 414: if (dir == SRCH_FORW) {
1.6 art 415: (void)backchar(FFARG | FFRAND, plen);
1.1 deraadt 416: if (forwsrch() == FALSE) {
417: curwp->w_doto = odoto;
418: curwp->w_dotp = odotp;
1.12 db 419: return (FALSE);
1.1 deraadt 420: }
1.12 db 421: return (TRUE);
1.1 deraadt 422: }
1.2 millert 423: if (dir == SRCH_BACK) {
1.6 art 424: (void)forwchar(FFARG | FFRAND, plen);
1.1 deraadt 425: if (backsrch() == FALSE) {
426: curwp->w_doto = odoto;
427: curwp->w_dotp = odotp;
1.12 db 428: return (FALSE);
1.1 deraadt 429: }
1.12 db 430: return (TRUE);
1.1 deraadt 431: }
432: ewprintf("bad call to is_find");
1.12 db 433: return (FALSE);
1.1 deraadt 434: }
1.12 db 435: return (FALSE);
1.1 deraadt 436: }
437:
438: /*
1.7 mickey 439: * If called with "dir" not one of SRCH_FORW or SRCH_BACK, this routine used
440: * to print an error message. It also used to return TRUE or FALSE, depending
441: * on if it liked the "dir". However, none of the callers looked at the
1.3 millert 442: * status, so I just made the checking vanish.
1.1 deraadt 443: */
1.6 art 444: static void
1.10 cloder 445: is_prompt(int dir, int flag, int success)
1.2 millert 446: {
1.1 deraadt 447: if (dir == SRCH_FORW) {
448: if (success != FALSE)
449: is_dspl("I-search", flag);
450: else
451: is_dspl("Failing I-search", flag);
452: } else if (dir == SRCH_BACK) {
453: if (success != FALSE)
454: is_dspl("I-search backward", flag);
455: else
456: is_dspl("Failing I-search backward", flag);
1.2 millert 457: } else
458: ewprintf("Broken call to is_prompt");
1.1 deraadt 459: }
460:
461: /*
1.7 mickey 462: * Prompt writing routine for the incremental search. The "prompt" is just
1.3 millert 463: * a string. The "flag" determines whether pat should be printed.
1.1 deraadt 464: */
1.6 art 465: static void
1.10 cloder 466: is_dspl(char *prompt, int flag)
1.2 millert 467: {
1.1 deraadt 468: if (flag != FALSE)
469: ewprintf("%s: ", prompt);
470: else
471: ewprintf("%s: %s", prompt, pat);
472: }
473:
474: /*
475: * Query Replace.
476: * Replace strings selectively. Does a search and replace operation.
477: */
1.2 millert 478: /* ARGSUSED */
1.3 millert 479: int
1.10 cloder 480: queryrepl(int f, int n)
1.1 deraadt 481: {
1.3 millert 482: int s;
483: int rcnt = 0; /* replacements made so far */
484: int plen; /* length of found string */
1.11 vincent 485: char news[NPAT], *rep; /* replacement string */
1.1 deraadt 486:
487: #ifndef NO_MACRO
1.2 millert 488: if (macrodef) {
489: ewprintf("Can't query replace in macro");
1.12 db 490: return (FALSE);
1.1 deraadt 491: }
1.3 millert 492: #endif /* !NO_MACRO */
493:
1.2 millert 494: if ((s = readpattern("Query replace")) != TRUE)
1.1 deraadt 495: return (s);
1.11 vincent 496: if ((rep = ereply("Query replace %s with: ", news, NPAT, pat)) == NULL)
1.12 db 497: return (ABORT);
1.11 vincent 498: else if (rep[0] == '\0')
1.1 deraadt 499: news[0] = '\0';
500: ewprintf("Query replacing %s with %s:", pat, news);
501: plen = strlen(pat);
502:
503: /*
504: * Search forward repeatedly, checking each time whether to insert
505: * or not. The "!" case makes the check always true, so it gets put
506: * into a tighter loop for efficiency.
507: */
508: while (forwsrch() == TRUE) {
1.2 millert 509: retry:
1.1 deraadt 510: update();
511: switch (getkey(FALSE)) {
512: case ' ':
1.3 millert 513: if (lreplace((RSIZE)plen, news, f) == FALSE)
1.1 deraadt 514: return (FALSE);
515: rcnt++;
516: break;
517: case '.':
1.3 millert 518: if (lreplace((RSIZE)plen, news, f) == FALSE)
1.1 deraadt 519: return (FALSE);
520: rcnt++;
521: goto stopsearch;
1.3 millert 522: /* ^G or ESC */
523: case CCHR('G'):
1.6 art 524: (void)ctrlg(FFRAND, 0);
1.1 deraadt 525: case CCHR('['):
526: goto stopsearch;
527: case '!':
528: do {
1.3 millert 529: if (lreplace((RSIZE)plen, news, f) == FALSE)
1.1 deraadt 530: return (FALSE);
531: rcnt++;
532: } while (forwsrch() == TRUE);
533: goto stopsearch;
534: case CCHR('H'):
1.3 millert 535: /* To not replace */
536: case CCHR('?'):
1.1 deraadt 537: break;
538: default:
1.2 millert 539: ewprintf("<SP> replace, [.] rep-end, <DEL> don't, [!] repl rest <ESC> quit");
1.1 deraadt 540: goto retry;
541: }
542: }
543: stopsearch:
544: curwp->w_flag |= WFHARD;
545: update();
546: if (rcnt == 0)
547: ewprintf("(No replacements done)");
548: else if (rcnt == 1)
549: ewprintf("(1 replacement done)");
550: else
551: ewprintf("(%d replacements done)", rcnt);
1.17 ! cloder 552: return (TRUE);
! 553: }
! 554:
! 555: /*
! 556: * Replace string globally without individual prompting.
! 557: */
! 558: /* ARGSUSED */
! 559: int
! 560: replstr(int f, int n)
! 561: {
! 562: char news[NPAT];
! 563: int s, plen, rcnt = 0;
! 564: char *r;
! 565:
! 566: if ((s = readpattern("Replace string")) != TRUE)
! 567: return s;
! 568:
! 569: r = ereply("Replace string %s with: ", news, NPAT, pat);
! 570: if (r == NULL)
! 571: return (ABORT);
! 572:
! 573: plen = strlen(pat);
! 574: while (forwsrch() == TRUE) {
! 575: update();
! 576: if (lreplace((RSIZE)plen, news, f) == FALSE)
! 577: return (FALSE);
! 578:
! 579: rcnt++;
! 580: }
! 581:
! 582: curwp->w_flag |= WFHARD;
! 583: update();
! 584:
! 585: if (rcnt == 1)
! 586: ewprintf("(1 replacement done)");
! 587: else
! 588: ewprintf("(%d replacements done)", rcnt);
! 589:
1.12 db 590: return (TRUE);
1.1 deraadt 591: }
592:
593: /*
1.7 mickey 594: * This routine does the real work of a forward search. The pattern is sitting
1.3 millert 595: * in the external variable "pat". If found, dot is updated, the window system
1.7 mickey 596: * is notified of the change, and TRUE is returned. If the string isn't found,
1.3 millert 597: * FALSE is returned.
1.1 deraadt 598: */
1.3 millert 599: int
1.10 cloder 600: forwsrch(void)
1.2 millert 601: {
1.3 millert 602: LINE *clp, *tlp;
1.13 jason 603: int cbo, tbo, c, i, xcase = 0;
1.3 millert 604: char *pp;
1.1 deraadt 605:
606: clp = curwp->w_dotp;
607: cbo = curwp->w_doto;
1.13 jason 608: for (i = 0; pat[i]; i++)
609: if (ISUPPER(CHARMASK(pat[i])))
610: xcase = 1;
1.2 millert 611: for (;;) {
1.1 deraadt 612: if (cbo == llength(clp)) {
1.2 millert 613: if ((clp = lforw(clp)) == curbp->b_linep)
614: break;
1.1 deraadt 615: cbo = 0;
616: c = CCHR('J');
617: } else
618: c = lgetc(clp, cbo++);
1.13 jason 619: if (eq(c, pat[0], xcase) != FALSE) {
1.1 deraadt 620: tlp = clp;
621: tbo = cbo;
1.2 millert 622: pp = &pat[1];
1.1 deraadt 623: while (*pp != 0) {
624: if (tbo == llength(tlp)) {
625: tlp = lforw(tlp);
626: if (tlp == curbp->b_linep)
627: goto fail;
628: tbo = 0;
629: c = CCHR('J');
630: } else
631: c = lgetc(tlp, tbo++);
1.13 jason 632: if (eq(c, *pp++, xcase) == FALSE)
1.1 deraadt 633: goto fail;
634: }
1.2 millert 635: curwp->w_dotp = tlp;
636: curwp->w_doto = tbo;
1.1 deraadt 637: curwp->w_flag |= WFMOVE;
1.12 db 638: return (TRUE);
1.1 deraadt 639: }
1.2 millert 640: fail: ;
1.1 deraadt 641: }
1.12 db 642: return (FALSE);
1.1 deraadt 643: }
644:
645: /*
1.7 mickey 646: * This routine does the real work of a backward search. The pattern is
647: * sitting in the external variable "pat". If found, dot is updated, the
1.3 millert 648: * window system is notified of the change, and TRUE is returned. If the
1.1 deraadt 649: * string isn't found, FALSE is returned.
650: */
1.3 millert 651: int
1.10 cloder 652: backsrch(void)
1.2 millert 653: {
1.3 millert 654: LINE *clp, *tlp;
1.13 jason 655: int cbo, tbo, c, i, xcase = 0;
1.3 millert 656: char *epp, *pp;
1.1 deraadt 657:
1.2 millert 658: for (epp = &pat[0]; epp[1] != 0; ++epp);
1.1 deraadt 659: clp = curwp->w_dotp;
660: cbo = curwp->w_doto;
1.13 jason 661: for (i = 0; pat[i]; i++)
662: if (ISUPPER(CHARMASK(pat[i])))
663: xcase = 1;
1.1 deraadt 664: for (;;) {
665: if (cbo == 0) {
666: clp = lback(clp);
667: if (clp == curbp->b_linep)
1.12 db 668: return (FALSE);
1.2 millert 669: cbo = llength(clp) + 1;
1.1 deraadt 670: }
671: if (--cbo == llength(clp))
672: c = CCHR('J');
673: else
1.2 millert 674: c = lgetc(clp, cbo);
1.13 jason 675: if (eq(c, *epp, xcase) != FALSE) {
1.1 deraadt 676: tlp = clp;
677: tbo = cbo;
1.2 millert 678: pp = epp;
1.1 deraadt 679: while (pp != &pat[0]) {
680: if (tbo == 0) {
681: tlp = lback(tlp);
682: if (tlp == curbp->b_linep)
683: goto fail;
1.2 millert 684: tbo = llength(tlp) + 1;
1.1 deraadt 685: }
686: if (--tbo == llength(tlp))
687: c = CCHR('J');
688: else
1.2 millert 689: c = lgetc(tlp, tbo);
1.13 jason 690: if (eq(c, *--pp, xcase) == FALSE)
1.1 deraadt 691: goto fail;
692: }
1.2 millert 693: curwp->w_dotp = tlp;
694: curwp->w_doto = tbo;
1.1 deraadt 695: curwp->w_flag |= WFMOVE;
1.12 db 696: return (TRUE);
1.1 deraadt 697: }
1.2 millert 698: fail: ;
1.1 deraadt 699: }
1.2 millert 700: /* NOTREACHED */
1.1 deraadt 701: }
702:
703: /*
1.7 mickey 704: * Compare two characters. The "bc" comes from the buffer. It has its case
1.3 millert 705: * folded out. The "pc" is from the pattern.
1.1 deraadt 706: */
707: static int
1.13 jason 708: eq(int bc, int pc, int xcase)
1.1 deraadt 709: {
710: bc = CHARMASK(bc);
711: pc = CHARMASK(pc);
1.2 millert 712: if (bc == pc)
1.12 db 713: return (TRUE);
1.13 jason 714: if (xcase)
715: return (FALSE);
1.2 millert 716: if (ISUPPER(bc))
1.12 db 717: return (TOLOWER(bc) == pc);
1.2 millert 718: if (ISUPPER(pc))
1.12 db 719: return (bc == TOLOWER(pc));
720: return (FALSE);
1.1 deraadt 721: }
722:
723: /*
1.7 mickey 724: * Read a pattern. Stash it in the external variable "pat". The "pat" is not
725: * updated if the user types in an empty line. If the user typed an empty
726: * line, and there is no old pattern, it is an error. Display the old pattern,
727: * in the style of Jeff Lomicka. There is some do-it-yourself control
1.3 millert 728: * expansion.
1.1 deraadt 729: */
1.3 millert 730: int
1.10 cloder 731: readpattern(char *prompt)
1.2 millert 732: {
1.11 vincent 733: char tpat[NPAT], *rep;
1.12 db 734: int retval;
1.1 deraadt 735:
1.16 cloder 736: if (pat[0] == '\0')
1.11 vincent 737: rep = ereply("%s: ", tpat, NPAT, prompt);
1.2 millert 738: else
1.11 vincent 739: rep = ereply("%s: (default %s) ", tpat, NPAT, prompt, pat);
1.1 deraadt 740:
1.3 millert 741: /* specified */
1.15 cloder 742: if (rep == NULL) {
743: retval = ABORT;
744: } else if (*rep != '\0') {
1.12 db 745: (void) strlcpy(pat, tpat, sizeof(pat));
1.11 vincent 746: retval = TRUE;
1.15 cloder 747: } else if (pat[0] != '\0') {
1.11 vincent 748: retval = TRUE;
749: } else
750: retval = FALSE;
1.12 db 751: return (retval);
1.1 deraadt 752: }