Annotation of src/usr.bin/mg/search.c, Revision 1.12
1.12 ! db 1: /* $OpenBSD: search.c,v 1.11 2004/07/22 01:25:25 vincent 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);
40: static int eq(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.2 millert 223: if (success == FALSE && dir == SRCH_FORW)
1.1 deraadt 224: break;
225: is_lpush();
226: pptr = strlen(pat);
1.6 art 227: (void)forwchar(FFRAND, 1);
1.2 millert 228: if (is_find(SRCH_FORW) != FALSE)
229: is_cpush(SRCH_MARK);
1.1 deraadt 230: else {
1.6 art 231: (void)backchar(FFRAND, 1);
1.1 deraadt 232: ttbeep();
233: success = FALSE;
234: }
235: is_prompt(dir, pptr < 0, success);
236: break;
237: case CCHR('R'):
238: if (dir == SRCH_FORW) {
239: dir = SRCH_BACK;
240: is_lpush();
241: is_cpush(SRCH_BACK);
242: success = TRUE;
243: }
1.2 millert 244: if (success == FALSE && dir == SRCH_BACK)
1.1 deraadt 245: break;
246: is_lpush();
247: pptr = strlen(pat);
1.6 art 248: (void)backchar(FFRAND, 1);
1.2 millert 249: if (is_find(SRCH_BACK) != FALSE)
250: is_cpush(SRCH_MARK);
1.1 deraadt 251: else {
1.6 art 252: (void)forwchar(FFRAND, 1);
1.1 deraadt 253: ttbeep();
254: success = FALSE;
255: }
256: is_prompt(dir, pptr < 0, success);
257: break;
258: case CCHR('H'):
259: case CCHR('?'):
260: is_undo(&pptr, &dir);
1.2 millert 261: if (is_peek() != SRCH_ACCM)
262: success = TRUE;
1.1 deraadt 263: is_prompt(dir, pptr < 0, success);
264: break;
265: case CCHR('\\'):
266: case CCHR('Q'):
1.3 millert 267: c = (char)getkey(FALSE);
1.2 millert 268: goto addchar;
1.1 deraadt 269: case CCHR('M'):
270: c = CCHR('J');
1.2 millert 271: goto addchar;
1.1 deraadt 272: default:
273: if (ISCTRL(c)) {
274: ungetkey(c);
275: curwp->w_markp = clp;
276: curwp->w_marko = cbo;
277: ewprintf("Mark set");
278: curwp->w_flag |= WFMOVE;
1.12 ! db 279: return (TRUE);
1.1 deraadt 280: } /* and continue */
281: case CCHR('I'):
282: case CCHR('J'):
1.2 millert 283: addchar:
1.1 deraadt 284: if (pptr == -1)
285: pptr = 0;
286: if (pptr == 0)
287: success = TRUE;
288: pat[pptr++] = c;
289: if (pptr == NPAT) {
290: ewprintf("Pattern too long");
1.12 ! db 291: return (FALSE);
1.1 deraadt 292: }
293: pat[pptr] = '\0';
294: is_lpush();
295: if (success != FALSE) {
296: if (is_find(dir) != FALSE)
297: is_cpush(c);
298: else {
299: success = FALSE;
300: ttbeep();
301: is_cpush(SRCH_ACCM);
302: }
303: } else
304: is_cpush(SRCH_ACCM);
305: is_prompt(dir, FALSE, success);
306: }
307: }
1.2 millert 308: /* NOTREACHED */
1.1 deraadt 309: }
310:
1.6 art 311: static void
1.10 cloder 312: is_cpush(int cmd)
1.2 millert 313: {
1.1 deraadt 314: if (++cip >= NSRCH)
315: cip = 0;
316: cmds[cip].s_code = cmd;
317: }
318:
1.6 art 319: static void
1.10 cloder 320: is_lpush(void)
1.2 millert 321: {
1.3 millert 322: int ctp;
1.1 deraadt 323:
1.2 millert 324: ctp = cip + 1;
1.1 deraadt 325: if (ctp >= NSRCH)
326: ctp = 0;
327: cmds[ctp].s_code = SRCH_NOPR;
328: cmds[ctp].s_doto = curwp->w_doto;
329: cmds[ctp].s_dotp = curwp->w_dotp;
330: }
331:
1.6 art 332: static void
1.10 cloder 333: is_pop(void)
1.2 millert 334: {
1.1 deraadt 335: if (cmds[cip].s_code != SRCH_NOPR) {
1.2 millert 336: curwp->w_doto = cmds[cip].s_doto;
337: curwp->w_dotp = cmds[cip].s_dotp;
1.1 deraadt 338: curwp->w_flag |= WFMOVE;
339: cmds[cip].s_code = SRCH_NOPR;
340: }
341: if (--cip <= 0)
1.2 millert 342: cip = NSRCH - 1;
1.1 deraadt 343: }
344:
345: static int
1.10 cloder 346: is_peek(void)
1.2 millert 347: {
1.12 ! db 348: return (cmds[cip].s_code);
1.1 deraadt 349: }
350:
351: /* this used to always return TRUE (the return value was checked) */
1.6 art 352: static void
1.10 cloder 353: is_undo(int *pptr, int *dir)
1.2 millert 354: {
1.3 millert 355: int redo = FALSE;
356:
1.1 deraadt 357: switch (cmds[cip].s_code) {
358: case SRCH_BEGIN:
359: case SRCH_NOPR:
360: *pptr = -1;
361: case SRCH_MARK:
362: break;
363: case SRCH_FORW:
364: *dir = SRCH_BACK;
365: redo = TRUE;
366: break;
367: case SRCH_BACK:
368: *dir = SRCH_FORW;
369: redo = TRUE;
370: break;
371: case SRCH_ACCM:
372: default:
373: *pptr -= 1;
374: if (*pptr < 0)
375: *pptr = 0;
376: pat[*pptr] = '\0';
377: break;
378: }
379: is_pop();
1.2 millert 380: if (redo)
381: is_undo(pptr, dir);
1.1 deraadt 382: }
383:
384: static int
1.10 cloder 385: is_find(int dir)
1.2 millert 386: {
1.3 millert 387: int plen, odoto;
388: LINE *odotp;
1.1 deraadt 389:
390: odoto = curwp->w_doto;
391: odotp = curwp->w_dotp;
392: plen = strlen(pat);
393: if (plen != 0) {
1.2 millert 394: if (dir == SRCH_FORW) {
1.6 art 395: (void)backchar(FFARG | FFRAND, plen);
1.1 deraadt 396: if (forwsrch() == FALSE) {
397: curwp->w_doto = odoto;
398: curwp->w_dotp = odotp;
1.12 ! db 399: return (FALSE);
1.1 deraadt 400: }
1.12 ! db 401: return (TRUE);
1.1 deraadt 402: }
1.2 millert 403: if (dir == SRCH_BACK) {
1.6 art 404: (void)forwchar(FFARG | FFRAND, plen);
1.1 deraadt 405: if (backsrch() == FALSE) {
406: curwp->w_doto = odoto;
407: curwp->w_dotp = odotp;
1.12 ! db 408: return (FALSE);
1.1 deraadt 409: }
1.12 ! db 410: return (TRUE);
1.1 deraadt 411: }
412: ewprintf("bad call to is_find");
1.12 ! db 413: return (FALSE);
1.1 deraadt 414: }
1.12 ! db 415: return (FALSE);
1.1 deraadt 416: }
417:
418: /*
1.7 mickey 419: * If called with "dir" not one of SRCH_FORW or SRCH_BACK, this routine used
420: * to print an error message. It also used to return TRUE or FALSE, depending
421: * on if it liked the "dir". However, none of the callers looked at the
1.3 millert 422: * status, so I just made the checking vanish.
1.1 deraadt 423: */
1.6 art 424: static void
1.10 cloder 425: is_prompt(int dir, int flag, int success)
1.2 millert 426: {
1.1 deraadt 427: if (dir == SRCH_FORW) {
428: if (success != FALSE)
429: is_dspl("I-search", flag);
430: else
431: is_dspl("Failing I-search", flag);
432: } else if (dir == SRCH_BACK) {
433: if (success != FALSE)
434: is_dspl("I-search backward", flag);
435: else
436: is_dspl("Failing I-search backward", flag);
1.2 millert 437: } else
438: ewprintf("Broken call to is_prompt");
1.1 deraadt 439: }
440:
441: /*
1.7 mickey 442: * Prompt writing routine for the incremental search. The "prompt" is just
1.3 millert 443: * a string. The "flag" determines whether pat should be printed.
1.1 deraadt 444: */
1.6 art 445: static void
1.10 cloder 446: is_dspl(char *prompt, int flag)
1.2 millert 447: {
1.1 deraadt 448: if (flag != FALSE)
449: ewprintf("%s: ", prompt);
450: else
451: ewprintf("%s: %s", prompt, pat);
452: }
453:
454: /*
455: * Query Replace.
456: * Replace strings selectively. Does a search and replace operation.
457: */
1.2 millert 458: /* ARGSUSED */
1.3 millert 459: int
1.10 cloder 460: queryrepl(int f, int n)
1.1 deraadt 461: {
1.3 millert 462: int s;
463: int rcnt = 0; /* replacements made so far */
464: int plen; /* length of found string */
1.11 vincent 465: char news[NPAT], *rep; /* replacement string */
1.1 deraadt 466:
467: #ifndef NO_MACRO
1.2 millert 468: if (macrodef) {
469: ewprintf("Can't query replace in macro");
1.12 ! db 470: return (FALSE);
1.1 deraadt 471: }
1.3 millert 472: #endif /* !NO_MACRO */
473:
1.2 millert 474: if ((s = readpattern("Query replace")) != TRUE)
1.1 deraadt 475: return (s);
1.11 vincent 476: if ((rep = ereply("Query replace %s with: ", news, NPAT, pat)) == NULL)
1.12 ! db 477: return (ABORT);
1.11 vincent 478: else if (rep[0] == '\0')
1.1 deraadt 479: news[0] = '\0';
480: ewprintf("Query replacing %s with %s:", pat, news);
481: plen = strlen(pat);
482:
483: /*
484: * Search forward repeatedly, checking each time whether to insert
485: * or not. The "!" case makes the check always true, so it gets put
486: * into a tighter loop for efficiency.
487: */
488: while (forwsrch() == TRUE) {
1.2 millert 489: retry:
1.1 deraadt 490: update();
491: switch (getkey(FALSE)) {
492: case ' ':
1.3 millert 493: if (lreplace((RSIZE)plen, news, f) == FALSE)
1.1 deraadt 494: return (FALSE);
495: rcnt++;
496: break;
497: case '.':
1.3 millert 498: if (lreplace((RSIZE)plen, news, f) == FALSE)
1.1 deraadt 499: return (FALSE);
500: rcnt++;
501: goto stopsearch;
1.3 millert 502: /* ^G or ESC */
503: case CCHR('G'):
1.6 art 504: (void)ctrlg(FFRAND, 0);
1.1 deraadt 505: case CCHR('['):
506: goto stopsearch;
507: case '!':
508: do {
1.3 millert 509: if (lreplace((RSIZE)plen, news, f) == FALSE)
1.1 deraadt 510: return (FALSE);
511: rcnt++;
512: } while (forwsrch() == TRUE);
513: goto stopsearch;
514: case CCHR('H'):
1.3 millert 515: /* To not replace */
516: case CCHR('?'):
1.1 deraadt 517: break;
518: default:
1.2 millert 519: ewprintf("<SP> replace, [.] rep-end, <DEL> don't, [!] repl rest <ESC> quit");
1.1 deraadt 520: goto retry;
521: }
522: }
523: stopsearch:
524: curwp->w_flag |= WFHARD;
525: update();
526: if (rcnt == 0)
527: ewprintf("(No replacements done)");
528: else if (rcnt == 1)
529: ewprintf("(1 replacement done)");
530: else
531: ewprintf("(%d replacements done)", rcnt);
1.12 ! db 532: return (TRUE);
1.1 deraadt 533: }
534:
535: /*
1.7 mickey 536: * This routine does the real work of a forward search. The pattern is sitting
1.3 millert 537: * in the external variable "pat". If found, dot is updated, the window system
1.7 mickey 538: * is notified of the change, and TRUE is returned. If the string isn't found,
1.3 millert 539: * FALSE is returned.
1.1 deraadt 540: */
1.3 millert 541: int
1.10 cloder 542: forwsrch(void)
1.2 millert 543: {
1.3 millert 544: LINE *clp, *tlp;
545: int cbo, tbo, c;
546: char *pp;
1.1 deraadt 547:
548: clp = curwp->w_dotp;
549: cbo = curwp->w_doto;
1.2 millert 550: for (;;) {
1.1 deraadt 551: if (cbo == llength(clp)) {
1.2 millert 552: if ((clp = lforw(clp)) == curbp->b_linep)
553: break;
1.1 deraadt 554: cbo = 0;
555: c = CCHR('J');
556: } else
557: c = lgetc(clp, cbo++);
558: if (eq(c, pat[0]) != FALSE) {
559: tlp = clp;
560: tbo = cbo;
1.2 millert 561: pp = &pat[1];
1.1 deraadt 562: while (*pp != 0) {
563: if (tbo == llength(tlp)) {
564: tlp = lforw(tlp);
565: if (tlp == curbp->b_linep)
566: goto fail;
567: tbo = 0;
568: c = CCHR('J');
569: } else
570: c = lgetc(tlp, tbo++);
571: if (eq(c, *pp++) == FALSE)
572: goto fail;
573: }
1.2 millert 574: curwp->w_dotp = tlp;
575: curwp->w_doto = tbo;
1.1 deraadt 576: curwp->w_flag |= WFMOVE;
1.12 ! db 577: return (TRUE);
1.1 deraadt 578: }
1.2 millert 579: fail: ;
1.1 deraadt 580: }
1.12 ! db 581: return (FALSE);
1.1 deraadt 582: }
583:
584: /*
1.7 mickey 585: * This routine does the real work of a backward search. The pattern is
586: * sitting in the external variable "pat". If found, dot is updated, the
1.3 millert 587: * window system is notified of the change, and TRUE is returned. If the
1.1 deraadt 588: * string isn't found, FALSE is returned.
589: */
1.3 millert 590: int
1.10 cloder 591: backsrch(void)
1.2 millert 592: {
1.3 millert 593: LINE *clp, *tlp;
594: int cbo, tbo, c;
595: char *epp, *pp;
1.1 deraadt 596:
1.2 millert 597: for (epp = &pat[0]; epp[1] != 0; ++epp);
1.1 deraadt 598: clp = curwp->w_dotp;
599: cbo = curwp->w_doto;
600: for (;;) {
601: if (cbo == 0) {
602: clp = lback(clp);
603: if (clp == curbp->b_linep)
1.12 ! db 604: return (FALSE);
1.2 millert 605: cbo = llength(clp) + 1;
1.1 deraadt 606: }
607: if (--cbo == llength(clp))
608: c = CCHR('J');
609: else
1.2 millert 610: c = lgetc(clp, cbo);
1.1 deraadt 611: if (eq(c, *epp) != FALSE) {
612: tlp = clp;
613: tbo = cbo;
1.2 millert 614: pp = epp;
1.1 deraadt 615: while (pp != &pat[0]) {
616: if (tbo == 0) {
617: tlp = lback(tlp);
618: if (tlp == curbp->b_linep)
619: goto fail;
1.2 millert 620: tbo = llength(tlp) + 1;
1.1 deraadt 621: }
622: if (--tbo == llength(tlp))
623: c = CCHR('J');
624: else
1.2 millert 625: c = lgetc(tlp, tbo);
1.1 deraadt 626: if (eq(c, *--pp) == FALSE)
627: goto fail;
628: }
1.2 millert 629: curwp->w_dotp = tlp;
630: curwp->w_doto = tbo;
1.1 deraadt 631: curwp->w_flag |= WFMOVE;
1.12 ! db 632: return (TRUE);
1.1 deraadt 633: }
1.2 millert 634: fail: ;
1.1 deraadt 635: }
1.2 millert 636: /* NOTREACHED */
1.1 deraadt 637: }
638:
639: /*
1.7 mickey 640: * Compare two characters. The "bc" comes from the buffer. It has its case
1.3 millert 641: * folded out. The "pc" is from the pattern.
1.1 deraadt 642: */
643: static int
1.10 cloder 644: eq(int bc, int pc)
1.1 deraadt 645: {
646: bc = CHARMASK(bc);
647: pc = CHARMASK(pc);
1.2 millert 648: if (bc == pc)
1.12 ! db 649: return (TRUE);
1.2 millert 650: if (ISUPPER(bc))
1.12 ! db 651: return (TOLOWER(bc) == pc);
1.2 millert 652: if (ISUPPER(pc))
1.12 ! db 653: return (bc == TOLOWER(pc));
! 654: return (FALSE);
1.1 deraadt 655: }
656:
657: /*
1.7 mickey 658: * Read a pattern. Stash it in the external variable "pat". The "pat" is not
659: * updated if the user types in an empty line. If the user typed an empty
660: * line, and there is no old pattern, it is an error. Display the old pattern,
661: * in the style of Jeff Lomicka. There is some do-it-yourself control
1.3 millert 662: * expansion.
1.1 deraadt 663: */
1.3 millert 664: int
1.10 cloder 665: readpattern(char *prompt)
1.2 millert 666: {
1.11 vincent 667: char tpat[NPAT], *rep;
1.12 ! db 668: int retval;
1.1 deraadt 669:
1.2 millert 670: if (tpat[0] == '\0')
1.11 vincent 671: rep = ereply("%s: ", tpat, NPAT, prompt);
1.2 millert 672: else
1.11 vincent 673: rep = ereply("%s: (default %s) ", tpat, NPAT, prompt, pat);
1.1 deraadt 674:
1.3 millert 675: /* specified */
1.11 vincent 676: if (rep != NULL && *rep != '\0') {
1.12 ! db 677: (void) strlcpy(pat, tpat, sizeof(pat));
1.11 vincent 678: retval = TRUE;
679: } else if (*rep == '\0' && pat[0] != '\0') {
680: retval = TRUE;
681: } else
682: retval = FALSE;
1.12 ! db 683: return (retval);
1.1 deraadt 684: }