xref: /csrg-svn/lib/libedit/search.c (revision 61275)
154231Sbostic /*-
2*61275Sbostic  * Copyright (c) 1992, 1993
3*61275Sbostic  *	The Regents of the University of California.  All rights reserved.
454231Sbostic  *
554231Sbostic  * This code is derived from software contributed to Berkeley by
654231Sbostic  * Christos Zoulas of Cornell University.
754231Sbostic  *
854231Sbostic  * %sccs.include.redist.c%
954231Sbostic  */
1054231Sbostic 
1154624Schristos #if !defined(lint) && !defined(SCCSID)
12*61275Sbostic static char sccsid[] = "@(#)search.c	8.1 (Berkeley) 06/04/93";
1354624Schristos #endif /* not lint && not SCCSID */
1454231Sbostic 
1554231Sbostic /*
1654624Schristos  * search.c: History and character search functions
1754231Sbostic  */
1854231Sbostic #include "sys.h"
1954231Sbostic #include <stdlib.h>
2054679Schristos #ifdef REGEXP
2154231Sbostic #include <regexp.h>
2254231Sbostic #endif
2354231Sbostic #include "el.h"
2454231Sbostic 
2554624Schristos /*
2654624Schristos  * Adjust cursor in vi mode to include the character under it
2754624Schristos  */
2854624Schristos #define EL_CURSOR(el) \
2954624Schristos     ((el)->el_line.cursor + (((el)->el_map.type == MAP_VI) && \
3054624Schristos 			    ((el)->el_map.current == (el)->el_map.alt)))
3154231Sbostic 
3254231Sbostic /* search_init():
3354231Sbostic  *	Initialize the search stuff
3454231Sbostic  */
3554231Sbostic protected int
search_init(el)3654231Sbostic search_init(el)
3754231Sbostic     EditLine *el;
3854231Sbostic {
3954231Sbostic     el->el_search.patbuf = (char *) el_malloc(EL_BUFSIZ);
4054231Sbostic     el->el_search.patlen = 0;
4154231Sbostic     el->el_search.patdir = -1;
4254231Sbostic     el->el_search.chacha = '\0';
4354231Sbostic     el->el_search.chadir = -1;
4454231Sbostic     return 0;
4554231Sbostic }
4654231Sbostic 
4754231Sbostic 
4854231Sbostic /* search_end():
4954231Sbostic  *	Initialize the search stuff
5054231Sbostic  */
5154231Sbostic protected void
search_end(el)5254231Sbostic search_end(el)
5354231Sbostic     EditLine *el;
5454231Sbostic {
5554231Sbostic     el_free((ptr_t) el->el_search.patbuf);
5654231Sbostic     el->el_search.patbuf = NULL;
5754231Sbostic }
5854231Sbostic 
5954679Schristos #ifdef REGEXP
6054231Sbostic /* regerror():
6154231Sbostic  *	Handle regular expression errors
6254231Sbostic  */
6354231Sbostic public void
6454231Sbostic /*ARGSUSED*/
regerror(msg)6554231Sbostic regerror(msg)
6654231Sbostic     const char *msg;
6754231Sbostic {
6854231Sbostic }
6954231Sbostic #endif
7054231Sbostic 
7154231Sbostic /* el_match():
7254231Sbostic  *	Return if string matches pattern
7354231Sbostic  */
7454624Schristos protected int
el_match(str,pat)7554231Sbostic el_match(str, pat)
7654231Sbostic     const char *str;
7754231Sbostic     const char *pat;
7854231Sbostic {
7954679Schristos #ifndef REGEXP
8054231Sbostic     extern char *re_comp __P((const char *));
8154231Sbostic     extern int re_exec __P((const char *));
8254231Sbostic #else
8354231Sbostic     regexp *re;
8454231Sbostic     int rv;
8554231Sbostic #endif
8654231Sbostic 
8754231Sbostic     if (strstr(str, pat) != NULL)
8854231Sbostic 	return 1;
8954679Schristos #ifndef REGEXP
9054231Sbostic     if (re_comp(pat) != NULL)
9154231Sbostic 	return 0;
9254231Sbostic     else
9354231Sbostic     return re_exec(str) == 1;
9454231Sbostic #else
9555353Schristos     if ((re = regcomp(pat)) != NULL) {
9654231Sbostic 	rv = regexec(re, str);
9754231Sbostic 	free((ptr_t) re);
9854231Sbostic     }
9954231Sbostic     else
10054231Sbostic 	rv = 0;
10154231Sbostic     return rv;
10254231Sbostic #endif
10354231Sbostic 
10454231Sbostic }
10554231Sbostic 
10654231Sbostic 
10754231Sbostic /* c_hmatch():
10854231Sbostic  *	 return True if the pattern matches the prefix
10954231Sbostic  */
11054231Sbostic protected int
c_hmatch(el,str)11154231Sbostic c_hmatch(el, str)
11254231Sbostic     EditLine *el;
11354231Sbostic     const char *str;
11454231Sbostic {
11554231Sbostic #ifdef SDEBUG
11654231Sbostic     (void) fprintf(el->el_errfile, "match `%s' with `%s'\n",
11754231Sbostic 		   el->el_search.patbuf, str);
11854231Sbostic #endif /* SDEBUG */
11954231Sbostic 
12054231Sbostic     return el_match(str, el->el_search.patbuf);
12154231Sbostic }
12254231Sbostic 
12354231Sbostic 
12454231Sbostic /* c_setpat():
12554231Sbostic  *	Set the history seatch pattern
12654231Sbostic  */
12754231Sbostic protected void
c_setpat(el)12854231Sbostic c_setpat(el)
12954231Sbostic     EditLine *el;
13054231Sbostic {
13154231Sbostic     if (el->el_state.lastcmd != ED_SEARCH_PREV_HISTORY &&
13254231Sbostic 	el->el_state.lastcmd != ED_SEARCH_NEXT_HISTORY) {
13354624Schristos 	el->el_search.patlen = EL_CURSOR(el) - el->el_line.buffer;
13454231Sbostic 	if (el->el_search.patlen >= EL_BUFSIZ)
13554231Sbostic 	    el->el_search.patlen = EL_BUFSIZ -1;
13654231Sbostic 	if (el->el_search.patlen >= 0)  {
13754231Sbostic 	    (void) strncpy(el->el_search.patbuf, el->el_line.buffer,
13854231Sbostic 			   el->el_search.patlen);
13954231Sbostic 	    el->el_search.patbuf[el->el_search.patlen] = '\0';
14054231Sbostic 	}
14154231Sbostic 	else
14254231Sbostic 	    el->el_search.patlen = strlen(el->el_search.patbuf);
14354231Sbostic     }
14454231Sbostic #ifdef SDEBUG
14554231Sbostic     (void) fprintf(el->el_errfile, "\neventno = %d\n", el->el_history.eventno);
14654231Sbostic     (void) fprintf(el->el_errfile, "patlen = %d\n", el->el_search.patlen);
14754231Sbostic     (void) fprintf(el->el_errfile, "patbuf = \"%s\"\n", el->el_search.patbuf);
14854231Sbostic     (void) fprintf(el->el_errfile, "cursor %d lastchar %d\n",
14954624Schristos 		   EL_CURSOR(el) - el->el_line.buffer,
15054231Sbostic 		   el->el_line.lastchar - el->el_line.buffer);
15154231Sbostic #endif
15254231Sbostic }
15354231Sbostic 
15454231Sbostic 
15554231Sbostic /* ce_inc_search():
15654231Sbostic  *	Emacs incremental search
15754231Sbostic  */
15854231Sbostic protected el_action_t
ce_inc_search(el,dir)15954231Sbostic ce_inc_search(el, dir)
16054231Sbostic     EditLine *el;
16154231Sbostic     int dir;
16254231Sbostic {
16354231Sbostic     static char STRfwd[] = { 'f', 'w', 'd', '\0' },
16454231Sbostic 		STRbck[] = { 'b', 'c', 'k', '\0' };
16554231Sbostic     static char pchar = ':';	/* ':' = normal, '?' = failed */
16654231Sbostic     static char endcmd[2] = { '\0', '\0' };
16754231Sbostic     char ch, *cp, *ocursor = el->el_line.cursor, oldpchar = pchar;
16854231Sbostic 
16954231Sbostic     el_action_t ret = CC_NORM;
17054231Sbostic 
17154231Sbostic     int ohisteventno = el->el_history.eventno,
17254231Sbostic 	oldpatlen = el->el_search.patlen,
17354231Sbostic 	newdir = dir,
17454231Sbostic         done, redo;
17554231Sbostic 
17654231Sbostic     if (el->el_line.lastchar + sizeof(STRfwd) / sizeof(char) + 2 +
17754231Sbostic 	el->el_search.patlen >= el->el_line.limit)
17854231Sbostic 	return CC_ERROR;
17954231Sbostic 
18054231Sbostic     for (;;) {
18154231Sbostic 
18254231Sbostic 	if (el->el_search.patlen == 0) {	/* first round */
18354231Sbostic 	    pchar = ':';
18454231Sbostic #ifdef ANCHOR
18554231Sbostic 	    el->el_search.patbuf[el->el_search.patlen++] = '.';
18654231Sbostic 	    el->el_search.patbuf[el->el_search.patlen++] = '*';
18754231Sbostic #endif
18854231Sbostic 	}
18954231Sbostic 	done = redo = 0;
19054231Sbostic 	*el->el_line.lastchar++ = '\n';
19154231Sbostic 	for (cp = newdir == ED_SEARCH_PREV_HISTORY ? STRbck : STRfwd;
19254231Sbostic 	     *cp; *el->el_line.lastchar++ = *cp++)
19354231Sbostic 	     continue;
19454231Sbostic 	*el->el_line.lastchar++ = pchar;
19554231Sbostic 	for (cp = &el->el_search.patbuf[1];
19654231Sbostic 	      cp < &el->el_search.patbuf[el->el_search.patlen];
19754231Sbostic 	      *el->el_line.lastchar++ = *cp++)
19854231Sbostic 	    continue;
19954231Sbostic 	*el->el_line.lastchar = '\0';
20054231Sbostic 	re_refresh(el);
20154231Sbostic 
20254231Sbostic 	if (el_getc(el, &ch) != 1)
20354231Sbostic 	    return ed_end_of_file(el, 0);
20454231Sbostic 
20554231Sbostic 	switch (el->el_map.current[(unsigned char) ch]) {
20654231Sbostic 	case ED_INSERT:
20754231Sbostic 	case ED_DIGIT:
20854231Sbostic 	    if (el->el_search.patlen > EL_BUFSIZ - 3)
20954231Sbostic 		term_beep(el);
21054231Sbostic 	    else {
21154231Sbostic 		el->el_search.patbuf[el->el_search.patlen++] = ch;
21254231Sbostic 		*el->el_line.lastchar++ = ch;
21354231Sbostic 		*el->el_line.lastchar = '\0';
21454231Sbostic 		re_refresh(el);
21554231Sbostic 	    }
21654231Sbostic 	    break;
21754231Sbostic 
21854231Sbostic 	case EM_INC_SEARCH_NEXT:
21954231Sbostic 	    newdir = ED_SEARCH_NEXT_HISTORY;
22054231Sbostic 	    redo++;
22154231Sbostic 	    break;
22254231Sbostic 
22354231Sbostic 	case EM_INC_SEARCH_PREV:
22454231Sbostic 	    newdir = ED_SEARCH_PREV_HISTORY;
22554231Sbostic 	    redo++;
22654231Sbostic 	    break;
22754231Sbostic 
22854231Sbostic 	case ED_DELETE_PREV_CHAR:
22954231Sbostic 	    if (el->el_search.patlen > 1)
23054231Sbostic 		done++;
23154231Sbostic 	    else
23254231Sbostic 		term_beep(el);
23354231Sbostic 	    break;
23454231Sbostic 
23554231Sbostic 	default:
23654231Sbostic 	    switch (ch) {
23754231Sbostic 	    case 0007:		/* ^G: Abort */
23854231Sbostic 		ret = CC_ERROR;
23954231Sbostic 		done++;
24054231Sbostic 		break;
24154231Sbostic 
24254231Sbostic 	    case 0027:		/* ^W: Append word */
24354231Sbostic 		/* No can do if globbing characters in pattern */
24454231Sbostic 		for (cp = &el->el_search.patbuf[1]; ; cp++)
24554231Sbostic 		    if (cp >= &el->el_search.patbuf[el->el_search.patlen]) {
24654231Sbostic 			el->el_line.cursor += el->el_search.patlen - 1;
24754231Sbostic 			cp = c__next_word(el->el_line.cursor,
24854231Sbostic 					  el->el_line.lastchar, 1, ce__isword);
24954231Sbostic 			while (el->el_line.cursor < cp &&
25054231Sbostic 			       *el->el_line.cursor != '\n') {
25154231Sbostic 			    if (el->el_search.patlen > EL_BUFSIZ - 3) {
25254231Sbostic 				term_beep(el);
25354231Sbostic 				break;
25454231Sbostic 			    }
25554231Sbostic 			    el->el_search.patbuf[el->el_search.patlen++] =
25654231Sbostic 				*el->el_line.cursor;
25754231Sbostic 			    *el->el_line.lastchar++ = *el->el_line.cursor++;
25854231Sbostic 			}
25954231Sbostic 			el->el_line.cursor = ocursor;
26054231Sbostic 			*el->el_line.lastchar = '\0';
26154231Sbostic 			re_refresh(el);
26254231Sbostic 			break;
26354231Sbostic 		    } else if (isglob(*cp)) {
26454231Sbostic 			term_beep(el);
26554231Sbostic 			break;
26654231Sbostic 		    }
26754231Sbostic 		break;
26854231Sbostic 
26954231Sbostic 	    default:		/* Terminate and execute cmd */
27054231Sbostic 		endcmd[0] = ch;
27154231Sbostic 		el_push(el, endcmd);
27254231Sbostic 		/*FALLTHROUGH*/
27354231Sbostic 
27454231Sbostic 	    case 0033:		/* ESC: Terminate */
27554231Sbostic 		ret = CC_REFRESH;
27654231Sbostic 		done++;
27754231Sbostic 		break;
27854231Sbostic 	    }
27954231Sbostic 	    break;
28054231Sbostic 	}
28154231Sbostic 
28254231Sbostic 	while (el->el_line.lastchar > el->el_line.buffer &&
28354231Sbostic 	       *el->el_line.lastchar != '\n')
28454231Sbostic 	    *el->el_line.lastchar-- = '\0';
28554231Sbostic 	*el->el_line.lastchar = '\0';
28654231Sbostic 
28754231Sbostic 	if (!done) {
28854231Sbostic 
28954231Sbostic 	    /* Can't search if unmatched '[' */
29054231Sbostic 	    for (cp = &el->el_search.patbuf[el->el_search.patlen-1], ch = ']';
29154231Sbostic 		 cp > el->el_search.patbuf; cp--)
29254231Sbostic 		if (*cp == '[' || *cp == ']') {
29354231Sbostic 		    ch = *cp;
29454231Sbostic 		    break;
29554231Sbostic 		}
29654231Sbostic 
29754231Sbostic 	    if (el->el_search.patlen > 1 && ch != '[') {
29854231Sbostic 		if (redo && newdir == dir) {
29954231Sbostic 		    if (pchar == '?') {	/* wrap around */
30054231Sbostic 			el->el_history.eventno =
30154231Sbostic 			    newdir == ED_SEARCH_PREV_HISTORY ? 0 : 0x7fffffff;
30254231Sbostic 			if (hist_get(el) == CC_ERROR)
30354231Sbostic 			    /* el->el_history.eventno was fixed by first call */
30454231Sbostic 			    (void) hist_get(el);
30554231Sbostic 			el->el_line.cursor = newdir == ED_SEARCH_PREV_HISTORY ?
30654231Sbostic 			    el->el_line.lastchar : el->el_line.buffer;
30754231Sbostic 		    } else
30854231Sbostic 			el->el_line.cursor +=
30954231Sbostic 				newdir == ED_SEARCH_PREV_HISTORY ? -1 : 1;
31054231Sbostic 		}
31154231Sbostic #ifdef ANCHOR
31254231Sbostic 		el->el_search.patbuf[el->el_search.patlen++] = '.';
31354231Sbostic 		el->el_search.patbuf[el->el_search.patlen++] = '*';
31454231Sbostic #endif
31554231Sbostic 		el->el_search.patbuf[el->el_search.patlen] = '\0';
31654231Sbostic 		if (el->el_line.cursor < el->el_line.buffer ||
31754231Sbostic 		    el->el_line.cursor > el->el_line.lastchar ||
31854231Sbostic 		    (ret = ce_search_line(el, &el->el_search.patbuf[1],
31954231Sbostic 					  newdir)) == CC_ERROR) {
32054231Sbostic 		    /* avoid c_setpat */
32154231Sbostic 		    el->el_state.lastcmd = (el_action_t) newdir;
32254231Sbostic 		    ret = newdir == ED_SEARCH_PREV_HISTORY ?
32354231Sbostic 			ed_search_prev_history(el, 0) :
32454231Sbostic 			ed_search_next_history(el, 0);
32554231Sbostic 		    if (ret != CC_ERROR) {
32654231Sbostic 			el->el_line.cursor = newdir == ED_SEARCH_PREV_HISTORY ?
32754231Sbostic 			    el->el_line.lastchar : el->el_line.buffer;
32854231Sbostic 			(void) ce_search_line(el, &el->el_search.patbuf[1],
32954231Sbostic 					      newdir);
33054231Sbostic 		    }
33154231Sbostic 		}
33254231Sbostic 		el->el_search.patbuf[--el->el_search.patlen] = '\0';
33354231Sbostic 		if (ret == CC_ERROR) {
33454231Sbostic 		    term_beep(el);
33554231Sbostic 		    if (el->el_history.eventno != ohisteventno) {
33654231Sbostic 			el->el_history.eventno = ohisteventno;
33754231Sbostic 			if (hist_get(el) == CC_ERROR)
33854231Sbostic 			    return CC_ERROR;
33954231Sbostic 		    }
34054231Sbostic 		    el->el_line.cursor = ocursor;
34154231Sbostic 		    pchar = '?';
34254231Sbostic 		} else {
34354231Sbostic 		    pchar = ':';
34454231Sbostic 		}
34554231Sbostic 	    }
34654231Sbostic 
34754231Sbostic 	    ret = ce_inc_search(el, newdir);
34854231Sbostic 
34954231Sbostic 	    if (ret == CC_ERROR && pchar == '?' && oldpchar == ':')
35054231Sbostic 		/* break abort of failed search at last non-failed */
35154231Sbostic 		ret = CC_NORM;
35254231Sbostic 
35354231Sbostic 	}
35454231Sbostic 
35554231Sbostic 	if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) {
35654231Sbostic 	    /* restore on normal return or error exit */
35754231Sbostic 	    pchar = oldpchar;
35854231Sbostic 	    el->el_search.patlen = oldpatlen;
35954231Sbostic 	    if (el->el_history.eventno != ohisteventno) {
36054231Sbostic 		el->el_history.eventno = ohisteventno;
36154231Sbostic 		if (hist_get(el) == CC_ERROR)
36254231Sbostic 		    return CC_ERROR;
36354231Sbostic 	    }
36454231Sbostic 	    el->el_line.cursor = ocursor;
36554231Sbostic 	    if (ret == CC_ERROR)
36654231Sbostic 		re_refresh(el);
36754231Sbostic 	}
36854231Sbostic 	if (done || ret != CC_NORM)
36954231Sbostic 	    return ret;
37054231Sbostic     }
37154231Sbostic }
37254231Sbostic 
37354231Sbostic 
37454231Sbostic /* cv_search():
37554231Sbostic  *	Vi search.
37654231Sbostic  */
37754231Sbostic protected el_action_t
cv_search(el,dir)37854231Sbostic cv_search(el, dir)
37954231Sbostic     EditLine *el;
38054231Sbostic     int dir;
38154231Sbostic {
38254231Sbostic     char ch;
38354231Sbostic     char tmpbuf[EL_BUFSIZ];
38454231Sbostic     int tmplen;
38554231Sbostic 
38654231Sbostic     tmplen = 0;
38754231Sbostic #ifdef ANCHOR
38854231Sbostic     tmpbuf[tmplen++] = '.';
38954231Sbostic     tmpbuf[tmplen++] = '*';
39054231Sbostic #endif
39154231Sbostic 
39254231Sbostic     el->el_line.buffer[0] = '\0';
39354231Sbostic     el->el_line.lastchar = el->el_line.buffer;
39454231Sbostic     el->el_line.cursor = el->el_line.buffer;
39554231Sbostic     el->el_search.patdir = dir;
39654231Sbostic 
39754231Sbostic     c_insert(el, 2);	/* prompt + '\n' */
39854231Sbostic     *el->el_line.cursor++ = '\n';
39955300Smarc     *el->el_line.cursor++ = dir == ED_SEARCH_PREV_HISTORY ? '/' : '?';
40054231Sbostic     re_refresh(el);
40154231Sbostic 
40254231Sbostic #ifdef ANCHOR
40354231Sbostic # define LEN 2
40454231Sbostic #else
40554231Sbostic # define LEN 0
40654231Sbostic #endif
40754231Sbostic 
40854231Sbostic     tmplen = c_gets(el, &tmpbuf[LEN]) + LEN;
40954231Sbostic     ch = tmpbuf[tmplen];
41054231Sbostic     tmpbuf[tmplen] = '\0';
41154231Sbostic 
41254231Sbostic     if (tmplen == LEN) {
41354231Sbostic 	/*
41454231Sbostic 	 * Use the old pattern, but wild-card it.
41554231Sbostic 	 */
41654231Sbostic 	if (el->el_search.patlen == 0) {
41754231Sbostic 	    el->el_line.buffer[0] = '\0';
41854231Sbostic 	    el->el_line.lastchar = el->el_line.buffer;
41954231Sbostic 	    el->el_line.cursor = el->el_line.buffer;
42054231Sbostic 	    re_refresh(el);
42154231Sbostic 	    return CC_ERROR;
42254231Sbostic 	}
42354231Sbostic #ifdef ANCHOR
42454231Sbostic 	if (el->el_search.patbuf[0] != '.' && el->el_search.patbuf[0] != '*') {
42554231Sbostic 	    (void) strcpy(tmpbuf, el->el_search.patbuf);
42654231Sbostic 	    el->el_search.patbuf[0] = '.';
42754231Sbostic 	    el->el_search.patbuf[1] = '*';
42854231Sbostic 	    (void) strcpy(&el->el_search.patbuf[2], tmpbuf);
42954231Sbostic 	    el->el_search.patlen++;
43054231Sbostic 	    el->el_search.patbuf[el->el_search.patlen++] = '.';
43154231Sbostic 	    el->el_search.patbuf[el->el_search.patlen++] = '*';
43254231Sbostic 	    el->el_search.patbuf[el->el_search.patlen] = '\0';
43354231Sbostic 	}
43454231Sbostic #endif
43554231Sbostic     }
43654231Sbostic     else {
43754231Sbostic #ifdef ANCHOR
43854231Sbostic 	tmpbuf[tmplen++] = '.';
43954231Sbostic 	tmpbuf[tmplen++] = '*';
44054231Sbostic #endif
44154231Sbostic 	tmpbuf[tmplen] = '\0';
44254231Sbostic 	(void) strcpy(el->el_search.patbuf, tmpbuf);
44354231Sbostic 	el->el_search.patlen = tmplen;
44454231Sbostic     }
44554231Sbostic     el->el_state.lastcmd = (el_action_t) dir; /* avoid c_setpat */
44654231Sbostic     el->el_line.cursor = el->el_line.lastchar = el->el_line.buffer;
44754231Sbostic     if ((dir == ED_SEARCH_PREV_HISTORY ? ed_search_prev_history(el, 0) :
44854231Sbostic 			        ed_search_next_history(el, 0)) == CC_ERROR) {
44954231Sbostic 	re_refresh(el);
45054231Sbostic 	return CC_ERROR;
45154231Sbostic     }
45254231Sbostic     else {
45354231Sbostic 	if (ch == 0033) {
45454231Sbostic 	    re_refresh(el);
45554231Sbostic 	    *el->el_line.lastchar++ = '\n';
45654231Sbostic 	    *el->el_line.lastchar = '\0';
45754231Sbostic 	    re_goto_bottom(el);
45854231Sbostic 	    return CC_NEWLINE;
45954231Sbostic 	}
46054231Sbostic 	else
46154231Sbostic 	    return CC_REFRESH;
46254231Sbostic     }
46354231Sbostic }
46454231Sbostic 
46554231Sbostic 
46654231Sbostic /* ce_search_line():
46754231Sbostic  *	Look for a pattern inside a line
46854231Sbostic  */
46954231Sbostic protected el_action_t
ce_search_line(el,pattern,dir)47054231Sbostic ce_search_line(el, pattern, dir)
47154231Sbostic     EditLine *el;
47254231Sbostic     char *pattern;
47354231Sbostic     int dir;
47454231Sbostic {
47554231Sbostic     char *cp;
47654231Sbostic 
47754231Sbostic     if (dir == ED_SEARCH_PREV_HISTORY) {
47854231Sbostic 	for (cp = el->el_line.cursor; cp >= el->el_line.buffer; cp--)
47954231Sbostic 	    if (el_match(cp, pattern)) {
48054231Sbostic 		el->el_line.cursor = cp;
48154231Sbostic 		return CC_NORM;
48254231Sbostic 	    }
48354231Sbostic 	return CC_ERROR;
48454231Sbostic     } else {
48554231Sbostic 	for (cp = el->el_line.cursor; *cp != '\0' &&
48654231Sbostic 	     cp < el->el_line.limit; cp++)
48754231Sbostic 	    if (el_match(cp, pattern)) {
48854231Sbostic 		el->el_line.cursor = cp;
48954231Sbostic 		return CC_NORM;
49054231Sbostic 	    }
49154231Sbostic 	return CC_ERROR;
49254231Sbostic     }
49354231Sbostic }
49454231Sbostic 
49554231Sbostic 
49654231Sbostic /* cv_repeat_srch():
49754231Sbostic  *	Vi repeat search
49854231Sbostic  */
49954231Sbostic protected el_action_t
cv_repeat_srch(el,c)50054231Sbostic cv_repeat_srch(el, c)
50154231Sbostic     EditLine *el;
50254231Sbostic     int c;
50354231Sbostic {
50454231Sbostic #ifdef SDEBUG
50554231Sbostic     (void) fprintf(el->el_errfile, "dir %d patlen %d patbuf %s\n",
50654231Sbostic 		   c, el->el_search.patlen, el->el_search.patbuf);
50754231Sbostic #endif
50854231Sbostic 
50954231Sbostic     el->el_state.lastcmd = (el_action_t) c;  /* Hack to stop c_setpat */
51054231Sbostic     el->el_line.lastchar = el->el_line.buffer;
51154231Sbostic 
51254231Sbostic     switch (c) {
51354231Sbostic     case ED_SEARCH_NEXT_HISTORY:
51454231Sbostic 	return ed_search_next_history(el, 0);
51554231Sbostic     case ED_SEARCH_PREV_HISTORY:
51654231Sbostic 	return ed_search_prev_history(el, 0);
51754231Sbostic     default:
51854231Sbostic 	return CC_ERROR;
51954231Sbostic     }
52054231Sbostic }
52154231Sbostic 
52254231Sbostic 
52354231Sbostic /* cv_csearch_back():
52454231Sbostic  *	Vi character search reverse
52554231Sbostic  */
52654231Sbostic protected el_action_t
cv_csearch_back(el,ch,count,tflag)52754231Sbostic cv_csearch_back(el, ch, count, tflag)
52854231Sbostic     EditLine *el;
52954231Sbostic     int ch, count, tflag;
53054231Sbostic {
53154231Sbostic     char *cp;
53254231Sbostic 
53354231Sbostic     cp = el->el_line.cursor;
53454231Sbostic     while (count--) {
53554231Sbostic 	if (*cp == ch)
53654231Sbostic 	    cp--;
53754231Sbostic 	while (cp > el->el_line.buffer && *cp != ch)
53854231Sbostic 	    cp--;
53954231Sbostic     }
54054231Sbostic 
54154231Sbostic     if (cp < el->el_line.buffer || (cp == el->el_line.buffer && *cp != ch))
54254231Sbostic 	return CC_ERROR;
54354231Sbostic 
54454231Sbostic     if (*cp == ch && tflag)
54554231Sbostic 	cp++;
54654231Sbostic 
54754231Sbostic     el->el_line.cursor = cp;
54854231Sbostic 
54954231Sbostic     if (el->el_chared.c_vcmd.action & DELETE) {
55054231Sbostic 	el->el_line.cursor++;
55154231Sbostic 	cv_delfini(el);
55254231Sbostic 	return CC_REFRESH;
55354231Sbostic     }
55454231Sbostic 
55554231Sbostic     re_refresh_cursor(el);
55654231Sbostic     return CC_NORM;
55754231Sbostic }
55854231Sbostic 
55954231Sbostic 
56054231Sbostic /* cv_csearch_fwd():
56154231Sbostic  *	Vi character search forward
56254231Sbostic  */
56354231Sbostic protected el_action_t
cv_csearch_fwd(el,ch,count,tflag)56454231Sbostic cv_csearch_fwd(el, ch, count, tflag)
56554231Sbostic     EditLine *el;
56654231Sbostic     int ch, count, tflag;
56754231Sbostic {
56854231Sbostic     char *cp;
56954231Sbostic 
57054231Sbostic     cp = el->el_line.cursor;
57154231Sbostic     while (count--) {
57254231Sbostic 	if(*cp == ch)
57354231Sbostic 	    cp++;
57454231Sbostic 	while (cp < el->el_line.lastchar && *cp != ch)
57554231Sbostic 	    cp++;
57654231Sbostic     }
57754231Sbostic 
57854231Sbostic     if (cp >= el->el_line.lastchar)
57954231Sbostic 	return CC_ERROR;
58054231Sbostic 
58154231Sbostic     if (*cp == ch && tflag)
58254231Sbostic 	cp--;
58354231Sbostic 
58454231Sbostic     el->el_line.cursor = cp;
58554231Sbostic 
58654231Sbostic     if (el->el_chared.c_vcmd.action & DELETE) {
58754231Sbostic 	el->el_line.cursor++;
58854231Sbostic 	cv_delfini(el);
58954231Sbostic 	return CC_REFRESH;
59054231Sbostic     }
59154231Sbostic     re_refresh_cursor(el);
59254231Sbostic     return CC_NORM;
59354231Sbostic }
594