11573Srgrimes/*-
21573Srgrimes * Copyright (c) 1992, 1993
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * This code is derived from software contributed to Berkeley by
61573Srgrimes * Christos Zoulas of Cornell University.
71573Srgrimes *
81573Srgrimes * Redistribution and use in source and binary forms, with or without
91573Srgrimes * modification, are permitted provided that the following conditions
101573Srgrimes * are met:
111573Srgrimes * 1. Redistributions of source code must retain the above copyright
121573Srgrimes *    notice, this list of conditions and the following disclaimer.
131573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141573Srgrimes *    notice, this list of conditions and the following disclaimer in the
151573Srgrimes *    documentation and/or other materials provided with the distribution.
16148834Sstefanf * 3. Neither the name of the University nor the names of its contributors
171573Srgrimes *    may be used to endorse or promote products derived from this software
181573Srgrimes *    without specific prior written permission.
191573Srgrimes *
201573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301573Srgrimes * SUCH DAMAGE.
3184260Sobrien *
32237448Spfg *	$NetBSD: search.c,v 1.21 2009/02/15 21:55:23 christos Exp $
331573Srgrimes */
341573Srgrimes
351573Srgrimes#if !defined(lint) && !defined(SCCSID)
361573Srgrimesstatic char sccsid[] = "@(#)search.c	8.1 (Berkeley) 6/4/93";
371573Srgrimes#endif /* not lint && not SCCSID */
3884260Sobrien#include <sys/cdefs.h>
3984260Sobrien__FBSDID("$FreeBSD$");
401573Srgrimes
411573Srgrimes/*
421573Srgrimes * search.c: History and character search functions
431573Srgrimes */
441573Srgrimes#include "sys.h"
451573Srgrimes#include <stdlib.h>
4626926Smsmith#if defined(REGEX)
473285Sache#include <regex.h>
4826926Smsmith#elif defined(REGEXP)
491573Srgrimes#include <regexp.h>
501573Srgrimes#endif
511573Srgrimes#include "el.h"
521573Srgrimes
531573Srgrimes/*
541573Srgrimes * Adjust cursor in vi mode to include the character under it
551573Srgrimes */
5684260Sobrien#define	EL_CURSOR(el) \
571573Srgrimes    ((el)->el_line.cursor + (((el)->el_map.type == MAP_VI) && \
581573Srgrimes			    ((el)->el_map.current == (el)->el_map.alt)))
591573Srgrimes
601573Srgrimes/* search_init():
611573Srgrimes *	Initialize the search stuff
621573Srgrimes */
631573Srgrimesprotected int
6484260Sobriensearch_init(EditLine *el)
651573Srgrimes{
6684260Sobrien
6784260Sobrien	el->el_search.patbuf = (char *) el_malloc(EL_BUFSIZ);
6884260Sobrien	if (el->el_search.patbuf == NULL)
6984260Sobrien		return (-1);
7084260Sobrien	el->el_search.patlen = 0;
7184260Sobrien	el->el_search.patdir = -1;
7284260Sobrien	el->el_search.chacha = '\0';
73148834Sstefanf	el->el_search.chadir = CHAR_FWD;
74148834Sstefanf	el->el_search.chatflg = 0;
7584260Sobrien	return (0);
761573Srgrimes}
771573Srgrimes
781573Srgrimes
791573Srgrimes/* search_end():
801573Srgrimes *	Initialize the search stuff
811573Srgrimes */
821573Srgrimesprotected void
8384260Sobriensearch_end(EditLine *el)
841573Srgrimes{
8584260Sobrien
8684260Sobrien	el_free((ptr_t) el->el_search.patbuf);
8784260Sobrien	el->el_search.patbuf = NULL;
881573Srgrimes}
891573Srgrimes
9084260Sobrien
911573Srgrimes#ifdef REGEXP
921573Srgrimes/* regerror():
931573Srgrimes *	Handle regular expression errors
941573Srgrimes */
958870Srgrimespublic void
961573Srgrimes/*ARGSUSED*/
9784260Sobrienregerror(const char *msg)
981573Srgrimes{
991573Srgrimes}
1001573Srgrimes#endif
1011573Srgrimes
10284260Sobrien
1031573Srgrimes/* el_match():
1041573Srgrimes *	Return if string matches pattern
1051573Srgrimes */
1061573Srgrimesprotected int
10784260Sobrienel_match(const char *str, const char *pat)
1081573Srgrimes{
10926926Smsmith#if defined (REGEX)
11084260Sobrien	regex_t re;
11184260Sobrien	int rv;
11226926Smsmith#elif defined (REGEXP)
11384260Sobrien	regexp *rp;
11484260Sobrien	int rv;
11584260Sobrien#else
11684260Sobrien	extern char	*re_comp(const char *);
11784260Sobrien	extern int	 re_exec(const char *);
1181573Srgrimes#endif
1191573Srgrimes
12084260Sobrien	if (strstr(str, pat) != NULL)
12184260Sobrien		return (1);
12226926Smsmith
12326926Smsmith#if defined(REGEX)
12484260Sobrien	if (regcomp(&re, pat, 0) == 0) {
12584260Sobrien		rv = regexec(&re, str, 0, NULL, 0) == 0;
12684260Sobrien		regfree(&re);
12784260Sobrien	} else {
12884260Sobrien		rv = 0;
12984260Sobrien	}
13084260Sobrien	return (rv);
13126926Smsmith#elif defined(REGEXP)
13284260Sobrien	if ((re = regcomp(pat)) != NULL) {
13384260Sobrien		rv = regexec(re, str);
13484260Sobrien		free((ptr_t) re);
13584260Sobrien	} else {
13684260Sobrien		rv = 0;
13784260Sobrien	}
13884260Sobrien	return (rv);
1393285Sache#else
14084260Sobrien	if (re_comp(pat) != NULL)
14184260Sobrien		return (0);
14284260Sobrien	else
14384260Sobrien		return (re_exec(str) == 1);
1441573Srgrimes#endif
1451573Srgrimes}
1461573Srgrimes
1471573Srgrimes
1481573Srgrimes/* c_hmatch():
1491573Srgrimes *	 return True if the pattern matches the prefix
1501573Srgrimes */
1511573Srgrimesprotected int
15284260Sobrienc_hmatch(EditLine *el, const char *str)
1531573Srgrimes{
1541573Srgrimes#ifdef SDEBUG
15584260Sobrien	(void) fprintf(el->el_errfile, "match `%s' with `%s'\n",
15684260Sobrien	    el->el_search.patbuf, str);
1571573Srgrimes#endif /* SDEBUG */
1588870Srgrimes
15984260Sobrien	return (el_match(str, el->el_search.patbuf));
1601573Srgrimes}
1611573Srgrimes
1621573Srgrimes
1638870Srgrimes/* c_setpat():
1641573Srgrimes *	Set the history seatch pattern
1651573Srgrimes */
1661573Srgrimesprotected void
16784260Sobrienc_setpat(EditLine *el)
1681573Srgrimes{
16984260Sobrien	if (el->el_state.lastcmd != ED_SEARCH_PREV_HISTORY &&
17084260Sobrien	    el->el_state.lastcmd != ED_SEARCH_NEXT_HISTORY) {
17184260Sobrien		el->el_search.patlen = EL_CURSOR(el) - el->el_line.buffer;
17284260Sobrien		if (el->el_search.patlen >= EL_BUFSIZ)
17384260Sobrien			el->el_search.patlen = EL_BUFSIZ - 1;
17484260Sobrien		if (el->el_search.patlen != 0) {
17584260Sobrien			(void) strncpy(el->el_search.patbuf, el->el_line.buffer,
17684260Sobrien			    el->el_search.patlen);
17784260Sobrien			el->el_search.patbuf[el->el_search.patlen] = '\0';
17884260Sobrien		} else
17984260Sobrien			el->el_search.patlen = strlen(el->el_search.patbuf);
1801573Srgrimes	}
1811573Srgrimes#ifdef SDEBUG
18284260Sobrien	(void) fprintf(el->el_errfile, "\neventno = %d\n",
18384260Sobrien	    el->el_history.eventno);
18484260Sobrien	(void) fprintf(el->el_errfile, "patlen = %d\n", el->el_search.patlen);
18584260Sobrien	(void) fprintf(el->el_errfile, "patbuf = \"%s\"\n",
18684260Sobrien	    el->el_search.patbuf);
18784260Sobrien	(void) fprintf(el->el_errfile, "cursor %d lastchar %d\n",
18884260Sobrien	    EL_CURSOR(el) - el->el_line.buffer,
18984260Sobrien	    el->el_line.lastchar - el->el_line.buffer);
1901573Srgrimes#endif
1911573Srgrimes}
1921573Srgrimes
1931573Srgrimes
1941573Srgrimes/* ce_inc_search():
1951573Srgrimes *	Emacs incremental search
1961573Srgrimes */
1971573Srgrimesprotected el_action_t
19884260Sobrience_inc_search(EditLine *el, int dir)
1991573Srgrimes{
20084260Sobrien	static const char STRfwd[] = {'f', 'w', 'd', '\0'},
20184260Sobrien	     STRbck[] = {'b', 'c', 'k', '\0'};
20284260Sobrien	static char pchar = ':';/* ':' = normal, '?' = failed */
20384260Sobrien	static char endcmd[2] = {'\0', '\0'};
20484260Sobrien	char ch, *ocursor = el->el_line.cursor, oldpchar = pchar;
20584260Sobrien	const char *cp;
2061573Srgrimes
20784260Sobrien	el_action_t ret = CC_NORM;
2081573Srgrimes
20984260Sobrien	int ohisteventno = el->el_history.eventno;
210237448Spfg	size_t oldpatlen = el->el_search.patlen;
21184260Sobrien	int newdir = dir;
21284260Sobrien	int done, redo;
2131573Srgrimes
21484260Sobrien	if (el->el_line.lastchar + sizeof(STRfwd) / sizeof(char) + 2 +
21584260Sobrien	    el->el_search.patlen >= el->el_line.limit)
21684260Sobrien		return (CC_ERROR);
2171573Srgrimes
21884260Sobrien	for (;;) {
2191573Srgrimes
22084260Sobrien		if (el->el_search.patlen == 0) {	/* first round */
22184260Sobrien			pchar = ':';
2221573Srgrimes#ifdef ANCHOR
223148834Sstefanf#define	LEN	2
22484260Sobrien			el->el_search.patbuf[el->el_search.patlen++] = '.';
22584260Sobrien			el->el_search.patbuf[el->el_search.patlen++] = '*';
226148834Sstefanf#else
227148834Sstefanf#define	LEN	0
2281573Srgrimes#endif
22984260Sobrien		}
23084260Sobrien		done = redo = 0;
23184260Sobrien		*el->el_line.lastchar++ = '\n';
23284260Sobrien		for (cp = (newdir == ED_SEARCH_PREV_HISTORY) ? STRbck : STRfwd;
23384260Sobrien		    *cp; *el->el_line.lastchar++ = *cp++)
23484260Sobrien			continue;
23584260Sobrien		*el->el_line.lastchar++ = pchar;
236148834Sstefanf		for (cp = &el->el_search.patbuf[LEN];
23784260Sobrien		    cp < &el->el_search.patbuf[el->el_search.patlen];
23884260Sobrien		    *el->el_line.lastchar++ = *cp++)
23984260Sobrien			continue;
2401573Srgrimes		*el->el_line.lastchar = '\0';
2411573Srgrimes		re_refresh(el);
2421573Srgrimes
24384260Sobrien		if (el_getc(el, &ch) != 1)
24484260Sobrien			return (ed_end_of_file(el, 0));
2451573Srgrimes
24684260Sobrien		switch (el->el_map.current[(unsigned char) ch]) {
24784260Sobrien		case ED_INSERT:
24884260Sobrien		case ED_DIGIT:
249148834Sstefanf			if (el->el_search.patlen >= EL_BUFSIZ - LEN)
25084260Sobrien				term_beep(el);
25184260Sobrien			else {
25284260Sobrien				el->el_search.patbuf[el->el_search.patlen++] =
25384260Sobrien				    ch;
25484260Sobrien				*el->el_line.lastchar++ = ch;
25584260Sobrien				*el->el_line.lastchar = '\0';
25684260Sobrien				re_refresh(el);
25784260Sobrien			}
25884260Sobrien			break;
2591573Srgrimes
26084260Sobrien		case EM_INC_SEARCH_NEXT:
26184260Sobrien			newdir = ED_SEARCH_NEXT_HISTORY;
26284260Sobrien			redo++;
26384260Sobrien			break;
2641573Srgrimes
26584260Sobrien		case EM_INC_SEARCH_PREV:
26684260Sobrien			newdir = ED_SEARCH_PREV_HISTORY;
26784260Sobrien			redo++;
26884260Sobrien			break;
2691573Srgrimes
270148834Sstefanf		case EM_DELETE_PREV_CHAR:
27184260Sobrien		case ED_DELETE_PREV_CHAR:
272148834Sstefanf			if (el->el_search.patlen > LEN)
27384260Sobrien				done++;
27484260Sobrien			else
2751573Srgrimes				term_beep(el);
2761573Srgrimes			break;
2778870Srgrimes
27884260Sobrien		default:
27984260Sobrien			switch (ch) {
28084260Sobrien			case 0007:	/* ^G: Abort */
28184260Sobrien				ret = CC_ERROR;
28284260Sobrien				done++;
28384260Sobrien				break;
2841573Srgrimes
28584260Sobrien			case 0027:	/* ^W: Append word */
28684260Sobrien			/* No can do if globbing characters in pattern */
287148834Sstefanf				for (cp = &el->el_search.patbuf[LEN];; cp++)
288148834Sstefanf				    if (cp >= &el->el_search.patbuf[
289148834Sstefanf					el->el_search.patlen]) {
29084260Sobrien					el->el_line.cursor +=
291148834Sstefanf					    el->el_search.patlen - LEN - 1;
29284260Sobrien					cp = c__next_word(el->el_line.cursor,
29384260Sobrien					    el->el_line.lastchar, 1,
29484260Sobrien					    ce__isword);
29584260Sobrien					while (el->el_line.cursor < cp &&
29684260Sobrien					    *el->el_line.cursor != '\n') {
297148834Sstefanf						if (el->el_search.patlen >=
298148834Sstefanf						    EL_BUFSIZ - LEN) {
29984260Sobrien							term_beep(el);
30084260Sobrien							break;
30184260Sobrien						}
30284260Sobrien						el->el_search.patbuf[el->el_search.patlen++] =
30384260Sobrien						    *el->el_line.cursor;
30484260Sobrien						*el->el_line.lastchar++ =
30584260Sobrien						    *el->el_line.cursor++;
30684260Sobrien					}
30784260Sobrien					el->el_line.cursor = ocursor;
30884260Sobrien					*el->el_line.lastchar = '\0';
30984260Sobrien					re_refresh(el);
31084260Sobrien					break;
31184260Sobrien				    } else if (isglob(*cp)) {
31284260Sobrien					    term_beep(el);
31384260Sobrien					    break;
31484260Sobrien				    }
31584260Sobrien				break;
3161573Srgrimes
31784260Sobrien			default:	/* Terminate and execute cmd */
31884260Sobrien				endcmd[0] = ch;
31984260Sobrien				el_push(el, endcmd);
32084260Sobrien				/* FALLTHROUGH */
3211573Srgrimes
32284260Sobrien			case 0033:	/* ESC: Terminate */
32384260Sobrien				ret = CC_REFRESH;
32484260Sobrien				done++;
32584260Sobrien				break;
32684260Sobrien			}
32784260Sobrien			break;
3281573Srgrimes		}
3291573Srgrimes
33084260Sobrien		while (el->el_line.lastchar > el->el_line.buffer &&
33184260Sobrien		    *el->el_line.lastchar != '\n')
33284260Sobrien			*el->el_line.lastchar-- = '\0';
33384260Sobrien		*el->el_line.lastchar = '\0';
33484260Sobrien
33584260Sobrien		if (!done) {
33684260Sobrien
33784260Sobrien			/* Can't search if unmatched '[' */
33884260Sobrien			for (cp = &el->el_search.patbuf[el->el_search.patlen-1],
33984260Sobrien			    ch = ']';
340148834Sstefanf			    cp >= &el->el_search.patbuf[LEN];
34184260Sobrien			    cp--)
34284260Sobrien				if (*cp == '[' || *cp == ']') {
34384260Sobrien					ch = *cp;
34484260Sobrien					break;
34584260Sobrien				}
346148834Sstefanf			if (el->el_search.patlen > LEN && ch != '[') {
34784260Sobrien				if (redo && newdir == dir) {
34884260Sobrien					if (pchar == '?') { /* wrap around */
34984260Sobrien						el->el_history.eventno =
35084260Sobrien						    newdir == ED_SEARCH_PREV_HISTORY ? 0 : 0x7fffffff;
35184260Sobrien						if (hist_get(el) == CC_ERROR)
35284260Sobrien							/* el->el_history.event
35384260Sobrien							 * no was fixed by
35484260Sobrien							 * first call */
35584260Sobrien							(void) hist_get(el);
35684260Sobrien						el->el_line.cursor = newdir ==
35784260Sobrien						    ED_SEARCH_PREV_HISTORY ?
35884260Sobrien						    el->el_line.lastchar :
35984260Sobrien						    el->el_line.buffer;
36084260Sobrien					} else
36184260Sobrien						el->el_line.cursor +=
36284260Sobrien						    newdir ==
36384260Sobrien						    ED_SEARCH_PREV_HISTORY ?
36484260Sobrien						    -1 : 1;
36584260Sobrien				}
3661573Srgrimes#ifdef ANCHOR
36784260Sobrien				el->el_search.patbuf[el->el_search.patlen++] =
36884260Sobrien				    '.';
36984260Sobrien				el->el_search.patbuf[el->el_search.patlen++] =
37084260Sobrien				    '*';
3711573Srgrimes#endif
37284260Sobrien				el->el_search.patbuf[el->el_search.patlen] =
37384260Sobrien				    '\0';
37484260Sobrien				if (el->el_line.cursor < el->el_line.buffer ||
37584260Sobrien				    el->el_line.cursor > el->el_line.lastchar ||
376148834Sstefanf				    (ret = ce_search_line(el, newdir))
377148834Sstefanf				    == CC_ERROR) {
37884260Sobrien					/* avoid c_setpat */
37984260Sobrien					el->el_state.lastcmd =
38084260Sobrien					    (el_action_t) newdir;
38184260Sobrien					ret = newdir == ED_SEARCH_PREV_HISTORY ?
38284260Sobrien					    ed_search_prev_history(el, 0) :
38384260Sobrien					    ed_search_next_history(el, 0);
38484260Sobrien					if (ret != CC_ERROR) {
38584260Sobrien						el->el_line.cursor = newdir ==
38684260Sobrien						    ED_SEARCH_PREV_HISTORY ?
38784260Sobrien						    el->el_line.lastchar :
38884260Sobrien						    el->el_line.buffer;
38984260Sobrien						(void) ce_search_line(el,
39084260Sobrien						    newdir);
39184260Sobrien					}
39284260Sobrien				}
393148834Sstefanf				el->el_search.patlen -= LEN;
394148834Sstefanf				el->el_search.patbuf[el->el_search.patlen] =
39584260Sobrien				    '\0';
39684260Sobrien				if (ret == CC_ERROR) {
39784260Sobrien					term_beep(el);
39884260Sobrien					if (el->el_history.eventno !=
39984260Sobrien					    ohisteventno) {
40084260Sobrien						el->el_history.eventno =
40184260Sobrien						    ohisteventno;
40284260Sobrien						if (hist_get(el) == CC_ERROR)
40384260Sobrien							return (CC_ERROR);
40484260Sobrien					}
40584260Sobrien					el->el_line.cursor = ocursor;
40684260Sobrien					pchar = '?';
40784260Sobrien				} else {
40884260Sobrien					pchar = ':';
40984260Sobrien				}
41084260Sobrien			}
41184260Sobrien			ret = ce_inc_search(el, newdir);
41284260Sobrien
41384260Sobrien			if (ret == CC_ERROR && pchar == '?' && oldpchar == ':')
41484260Sobrien				/*
41584260Sobrien				 * break abort of failed search at last
41684260Sobrien				 * non-failed
41784260Sobrien				 */
41884260Sobrien				ret = CC_NORM;
41984260Sobrien
4201573Srgrimes		}
42184260Sobrien		if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) {
42284260Sobrien			/* restore on normal return or error exit */
42384260Sobrien			pchar = oldpchar;
42484260Sobrien			el->el_search.patlen = oldpatlen;
42584260Sobrien			if (el->el_history.eventno != ohisteventno) {
42684260Sobrien				el->el_history.eventno = ohisteventno;
42784260Sobrien				if (hist_get(el) == CC_ERROR)
42884260Sobrien					return (CC_ERROR);
42984260Sobrien			}
43084260Sobrien			el->el_line.cursor = ocursor;
43184260Sobrien			if (ret == CC_ERROR)
43284260Sobrien				re_refresh(el);
4331573Srgrimes		}
43484260Sobrien		if (done || ret != CC_NORM)
43584260Sobrien			return (ret);
4361573Srgrimes	}
4371573Srgrimes}
4381573Srgrimes
4391573Srgrimes
4401573Srgrimes/* cv_search():
4411573Srgrimes *	Vi search.
4421573Srgrimes */
4431573Srgrimesprotected el_action_t
44484260Sobriencv_search(EditLine *el, int dir)
4451573Srgrimes{
44684260Sobrien	char ch;
44784260Sobrien	char tmpbuf[EL_BUFSIZ];
44884260Sobrien	int tmplen;
4491573Srgrimes
4501573Srgrimes#ifdef ANCHOR
451148834Sstefanf	tmpbuf[0] = '.';
452148834Sstefanf	tmpbuf[1] = '*';
4531573Srgrimes#endif
454148834Sstefanf	tmplen = LEN;
4551573Srgrimes
45684260Sobrien	el->el_search.patdir = dir;
4571573Srgrimes
458148834Sstefanf	tmplen = c_gets(el, &tmpbuf[LEN],
459148834Sstefanf		dir == ED_SEARCH_PREV_HISTORY ? "\n/" : "\n?" );
460148834Sstefanf	if (tmplen == -1)
461148834Sstefanf		return CC_REFRESH;
4621573Srgrimes
463148834Sstefanf	tmplen += LEN;
46484260Sobrien	ch = tmpbuf[tmplen];
46584260Sobrien	tmpbuf[tmplen] = '\0';
4661573Srgrimes
46784260Sobrien	if (tmplen == LEN) {
46884260Sobrien		/*
46984260Sobrien		 * Use the old pattern, but wild-card it.
47084260Sobrien		 */
47184260Sobrien		if (el->el_search.patlen == 0) {
47284260Sobrien			re_refresh(el);
47384260Sobrien			return (CC_ERROR);
47484260Sobrien		}
4751573Srgrimes#ifdef ANCHOR
47684260Sobrien		if (el->el_search.patbuf[0] != '.' &&
47784260Sobrien		    el->el_search.patbuf[0] != '*') {
47884260Sobrien			(void) strncpy(tmpbuf, el->el_search.patbuf,
47984260Sobrien			    sizeof(tmpbuf) - 1);
48084260Sobrien			el->el_search.patbuf[0] = '.';
48184260Sobrien			el->el_search.patbuf[1] = '*';
48284260Sobrien			(void) strncpy(&el->el_search.patbuf[2], tmpbuf,
48384260Sobrien			    EL_BUFSIZ - 3);
48484260Sobrien			el->el_search.patlen++;
48584260Sobrien			el->el_search.patbuf[el->el_search.patlen++] = '.';
48684260Sobrien			el->el_search.patbuf[el->el_search.patlen++] = '*';
48784260Sobrien			el->el_search.patbuf[el->el_search.patlen] = '\0';
48884260Sobrien		}
4891573Srgrimes#endif
49084260Sobrien	} else {
4911573Srgrimes#ifdef ANCHOR
49284260Sobrien		tmpbuf[tmplen++] = '.';
49384260Sobrien		tmpbuf[tmplen++] = '*';
4941573Srgrimes#endif
49584260Sobrien		tmpbuf[tmplen] = '\0';
49684260Sobrien		(void) strncpy(el->el_search.patbuf, tmpbuf, EL_BUFSIZ - 1);
49784260Sobrien		el->el_search.patlen = tmplen;
4981573Srgrimes	}
49984260Sobrien	el->el_state.lastcmd = (el_action_t) dir;	/* avoid c_setpat */
50084260Sobrien	el->el_line.cursor = el->el_line.lastchar = el->el_line.buffer;
50184260Sobrien	if ((dir == ED_SEARCH_PREV_HISTORY ? ed_search_prev_history(el, 0) :
502148834Sstefanf	    ed_search_next_history(el, 0)) == CC_ERROR) {
50384260Sobrien		re_refresh(el);
50484260Sobrien		return (CC_ERROR);
50584260Sobrien	}
506148834Sstefanf	if (ch == 0033) {
507148834Sstefanf		re_refresh(el);
508148834Sstefanf		return ed_newline(el, 0);
509148834Sstefanf	}
510148834Sstefanf	return (CC_REFRESH);
5111573Srgrimes}
5121573Srgrimes
5131573Srgrimes
5141573Srgrimes/* ce_search_line():
5151573Srgrimes *	Look for a pattern inside a line
5161573Srgrimes */
5171573Srgrimesprotected el_action_t
518148834Sstefanfce_search_line(EditLine *el, int dir)
5191573Srgrimes{
520148834Sstefanf	char *cp = el->el_line.cursor;
521148834Sstefanf	char *pattern = el->el_search.patbuf;
522148834Sstefanf	char oc, *ocp;
523148834Sstefanf#ifdef ANCHOR
524148834Sstefanf	ocp = &pattern[1];
525148834Sstefanf	oc = *ocp;
526148834Sstefanf	*ocp = '^';
527148834Sstefanf#else
528148834Sstefanf	ocp = pattern;
529148834Sstefanf	oc = *ocp;
530148834Sstefanf#endif
5311573Srgrimes
53284260Sobrien	if (dir == ED_SEARCH_PREV_HISTORY) {
533148834Sstefanf		for (; cp >= el->el_line.buffer; cp--) {
534148834Sstefanf			if (el_match(cp, ocp)) {
535148834Sstefanf				*ocp = oc;
53684260Sobrien				el->el_line.cursor = cp;
53784260Sobrien				return (CC_NORM);
53884260Sobrien			}
539148834Sstefanf		}
540148834Sstefanf		*ocp = oc;
54184260Sobrien		return (CC_ERROR);
54284260Sobrien	} else {
543148834Sstefanf		for (; *cp != '\0' && cp < el->el_line.limit; cp++) {
544148834Sstefanf			if (el_match(cp, ocp)) {
545148834Sstefanf				*ocp = oc;
54684260Sobrien				el->el_line.cursor = cp;
54784260Sobrien				return (CC_NORM);
54884260Sobrien			}
549148834Sstefanf		}
550148834Sstefanf		*ocp = oc;
55184260Sobrien		return (CC_ERROR);
55284260Sobrien	}
5531573Srgrimes}
5541573Srgrimes
5551573Srgrimes
5561573Srgrimes/* cv_repeat_srch():
5571573Srgrimes *	Vi repeat search
5581573Srgrimes */
5591573Srgrimesprotected el_action_t
56084260Sobriencv_repeat_srch(EditLine *el, int c)
5611573Srgrimes{
56284260Sobrien
5631573Srgrimes#ifdef SDEBUG
56484260Sobrien	(void) fprintf(el->el_errfile, "dir %d patlen %d patbuf %s\n",
56584260Sobrien	    c, el->el_search.patlen, el->el_search.patbuf);
5661573Srgrimes#endif
5671573Srgrimes
56884260Sobrien	el->el_state.lastcmd = (el_action_t) c;	/* Hack to stop c_setpat */
56984260Sobrien	el->el_line.lastchar = el->el_line.buffer;
5701573Srgrimes
57184260Sobrien	switch (c) {
57284260Sobrien	case ED_SEARCH_NEXT_HISTORY:
57384260Sobrien		return (ed_search_next_history(el, 0));
57484260Sobrien	case ED_SEARCH_PREV_HISTORY:
57584260Sobrien		return (ed_search_prev_history(el, 0));
57684260Sobrien	default:
57784260Sobrien		return (CC_ERROR);
57884260Sobrien	}
5791573Srgrimes}
5801573Srgrimes
5811573Srgrimes
582148834Sstefanf/* cv_csearch():
583148834Sstefanf *	Vi character search
5841573Srgrimes */
5851573Srgrimesprotected el_action_t
586148834Sstefanfcv_csearch(EditLine *el, int direction, int ch, int count, int tflag)
5871573Srgrimes{
58884260Sobrien	char *cp;
5891573Srgrimes
590148834Sstefanf	if (ch == 0)
591148834Sstefanf		return CC_ERROR;
5921573Srgrimes
593148834Sstefanf	if (ch == -1) {
594148834Sstefanf		char c;
595148834Sstefanf		if (el_getc(el, &c) != 1)
596148834Sstefanf			return ed_end_of_file(el, 0);
597148834Sstefanf		ch = c;
59884260Sobrien	}
5991573Srgrimes
600148834Sstefanf	/* Save for ';' and ',' commands */
601148834Sstefanf	el->el_search.chacha = ch;
602148834Sstefanf	el->el_search.chadir = direction;
603148834Sstefanf	el->el_search.chatflg = tflag;
6041573Srgrimes
60584260Sobrien	cp = el->el_line.cursor;
60684260Sobrien	while (count--) {
60784260Sobrien		if (*cp == ch)
608148834Sstefanf			cp += direction;
609148834Sstefanf		for (;;cp += direction) {
610148834Sstefanf			if (cp >= el->el_line.lastchar)
611148834Sstefanf				return CC_ERROR;
612148834Sstefanf			if (cp < el->el_line.buffer)
613148834Sstefanf				return CC_ERROR;
614148834Sstefanf			if (*cp == ch)
615148834Sstefanf				break;
616148834Sstefanf		}
61784260Sobrien	}
6181573Srgrimes
619148834Sstefanf	if (tflag)
620148834Sstefanf		cp -= direction;
6211573Srgrimes
62284260Sobrien	el->el_line.cursor = cp;
6231573Srgrimes
624148834Sstefanf	if (el->el_chared.c_vcmd.action != NOP) {
625148834Sstefanf		if (direction > 0)
626148834Sstefanf			el->el_line.cursor++;
62784260Sobrien		cv_delfini(el);
628148834Sstefanf		return CC_REFRESH;
62984260Sobrien	}
630148834Sstefanf	return CC_CURSOR;
6311573Srgrimes}
632