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