1*f9a159daSBaptiste Daroussin /* $NetBSD: search.c,v 1.51 2020/03/30 06:56:38 ryo Exp $ */
2d0ef721eSBaptiste Daroussin
3d0ef721eSBaptiste Daroussin /*-
4d0ef721eSBaptiste Daroussin * Copyright (c) 1992, 1993
5d0ef721eSBaptiste Daroussin * The Regents of the University of California. All rights reserved.
6d0ef721eSBaptiste Daroussin *
7d0ef721eSBaptiste Daroussin * This code is derived from software contributed to Berkeley by
8d0ef721eSBaptiste Daroussin * Christos Zoulas of Cornell University.
9d0ef721eSBaptiste Daroussin *
10d0ef721eSBaptiste Daroussin * Redistribution and use in source and binary forms, with or without
11d0ef721eSBaptiste Daroussin * modification, are permitted provided that the following conditions
12d0ef721eSBaptiste Daroussin * are met:
13d0ef721eSBaptiste Daroussin * 1. Redistributions of source code must retain the above copyright
14d0ef721eSBaptiste Daroussin * notice, this list of conditions and the following disclaimer.
15d0ef721eSBaptiste Daroussin * 2. Redistributions in binary form must reproduce the above copyright
16d0ef721eSBaptiste Daroussin * notice, this list of conditions and the following disclaimer in the
17d0ef721eSBaptiste Daroussin * documentation and/or other materials provided with the distribution.
18d0ef721eSBaptiste Daroussin * 3. Neither the name of the University nor the names of its contributors
19d0ef721eSBaptiste Daroussin * may be used to endorse or promote products derived from this software
20d0ef721eSBaptiste Daroussin * without specific prior written permission.
21d0ef721eSBaptiste Daroussin *
22d0ef721eSBaptiste Daroussin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23d0ef721eSBaptiste Daroussin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24d0ef721eSBaptiste Daroussin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25d0ef721eSBaptiste Daroussin * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26d0ef721eSBaptiste Daroussin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27d0ef721eSBaptiste Daroussin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28d0ef721eSBaptiste Daroussin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29d0ef721eSBaptiste Daroussin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30d0ef721eSBaptiste Daroussin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31d0ef721eSBaptiste Daroussin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32d0ef721eSBaptiste Daroussin * SUCH DAMAGE.
33d0ef721eSBaptiste Daroussin */
34d0ef721eSBaptiste Daroussin
35d0ef721eSBaptiste Daroussin #include "config.h"
36d0ef721eSBaptiste Daroussin #if !defined(lint) && !defined(SCCSID)
37d0ef721eSBaptiste Daroussin #if 0
38d0ef721eSBaptiste Daroussin static char sccsid[] = "@(#)search.c 8.1 (Berkeley) 6/4/93";
39d0ef721eSBaptiste Daroussin #else
40*f9a159daSBaptiste Daroussin __RCSID("$NetBSD: search.c,v 1.51 2020/03/30 06:56:38 ryo Exp $");
41d0ef721eSBaptiste Daroussin #endif
42d0ef721eSBaptiste Daroussin #endif /* not lint && not SCCSID */
43d0ef721eSBaptiste Daroussin
44d0ef721eSBaptiste Daroussin /*
45d0ef721eSBaptiste Daroussin * search.c: History and character search functions
46d0ef721eSBaptiste Daroussin */
47d0ef721eSBaptiste Daroussin #include <stdlib.h>
48d0ef721eSBaptiste Daroussin #include <string.h>
49d0ef721eSBaptiste Daroussin #if defined(REGEX)
50d0ef721eSBaptiste Daroussin #include <regex.h>
51d0ef721eSBaptiste Daroussin #elif defined(REGEXP)
52d0ef721eSBaptiste Daroussin #include <regexp.h>
53d0ef721eSBaptiste Daroussin #endif
54d0ef721eSBaptiste Daroussin
55d0ef721eSBaptiste Daroussin #include "el.h"
56d0ef721eSBaptiste Daroussin #include "common.h"
57d0ef721eSBaptiste Daroussin #include "fcns.h"
58d0ef721eSBaptiste Daroussin
59d0ef721eSBaptiste Daroussin /*
60d0ef721eSBaptiste Daroussin * Adjust cursor in vi mode to include the character under it
61d0ef721eSBaptiste Daroussin */
62d0ef721eSBaptiste Daroussin #define EL_CURSOR(el) \
63d0ef721eSBaptiste Daroussin ((el)->el_line.cursor + (((el)->el_map.type == MAP_VI) && \
64d0ef721eSBaptiste Daroussin ((el)->el_map.current == (el)->el_map.alt)))
65d0ef721eSBaptiste Daroussin
66d0ef721eSBaptiste Daroussin /* search_init():
67d0ef721eSBaptiste Daroussin * Initialize the search stuff
68d0ef721eSBaptiste Daroussin */
69d0ef721eSBaptiste Daroussin libedit_private int
search_init(EditLine * el)70d0ef721eSBaptiste Daroussin search_init(EditLine *el)
71d0ef721eSBaptiste Daroussin {
72d0ef721eSBaptiste Daroussin
73d0ef721eSBaptiste Daroussin el->el_search.patbuf = el_calloc(EL_BUFSIZ,
74d0ef721eSBaptiste Daroussin sizeof(*el->el_search.patbuf));
75d0ef721eSBaptiste Daroussin if (el->el_search.patbuf == NULL)
76d0ef721eSBaptiste Daroussin return -1;
77d0ef721eSBaptiste Daroussin el->el_search.patbuf[0] = L'\0';
78d0ef721eSBaptiste Daroussin el->el_search.patlen = 0;
79d0ef721eSBaptiste Daroussin el->el_search.patdir = -1;
80d0ef721eSBaptiste Daroussin el->el_search.chacha = L'\0';
81d0ef721eSBaptiste Daroussin el->el_search.chadir = CHAR_FWD;
82d0ef721eSBaptiste Daroussin el->el_search.chatflg = 0;
83d0ef721eSBaptiste Daroussin return 0;
84d0ef721eSBaptiste Daroussin }
85d0ef721eSBaptiste Daroussin
86d0ef721eSBaptiste Daroussin
87d0ef721eSBaptiste Daroussin /* search_end():
88d0ef721eSBaptiste Daroussin * Initialize the search stuff
89d0ef721eSBaptiste Daroussin */
90d0ef721eSBaptiste Daroussin libedit_private void
search_end(EditLine * el)91d0ef721eSBaptiste Daroussin search_end(EditLine *el)
92d0ef721eSBaptiste Daroussin {
93d0ef721eSBaptiste Daroussin
94d0ef721eSBaptiste Daroussin el_free(el->el_search.patbuf);
95d0ef721eSBaptiste Daroussin el->el_search.patbuf = NULL;
96d0ef721eSBaptiste Daroussin }
97d0ef721eSBaptiste Daroussin
98d0ef721eSBaptiste Daroussin
99d0ef721eSBaptiste Daroussin #ifdef REGEXP
100d0ef721eSBaptiste Daroussin /* regerror():
101d0ef721eSBaptiste Daroussin * Handle regular expression errors
102d0ef721eSBaptiste Daroussin */
103d0ef721eSBaptiste Daroussin void
104d0ef721eSBaptiste Daroussin /*ARGSUSED*/
regerror(const char * msg)105d0ef721eSBaptiste Daroussin regerror(const char *msg)
106d0ef721eSBaptiste Daroussin {
107d0ef721eSBaptiste Daroussin }
108d0ef721eSBaptiste Daroussin #endif
109d0ef721eSBaptiste Daroussin
110d0ef721eSBaptiste Daroussin
111d0ef721eSBaptiste Daroussin /* el_match():
112d0ef721eSBaptiste Daroussin * Return if string matches pattern
113d0ef721eSBaptiste Daroussin */
114d0ef721eSBaptiste Daroussin libedit_private int
el_match(const wchar_t * str,const wchar_t * pat)115d0ef721eSBaptiste Daroussin el_match(const wchar_t *str, const wchar_t *pat)
116d0ef721eSBaptiste Daroussin {
117d0ef721eSBaptiste Daroussin static ct_buffer_t conv;
118d0ef721eSBaptiste Daroussin #if defined (REGEX)
119d0ef721eSBaptiste Daroussin regex_t re;
120d0ef721eSBaptiste Daroussin int rv;
121d0ef721eSBaptiste Daroussin #elif defined (REGEXP)
122d0ef721eSBaptiste Daroussin regexp *rp;
123d0ef721eSBaptiste Daroussin int rv;
124d0ef721eSBaptiste Daroussin #else
125d0ef721eSBaptiste Daroussin extern char *re_comp(const char *);
126d0ef721eSBaptiste Daroussin extern int re_exec(const char *);
127d0ef721eSBaptiste Daroussin #endif
128d0ef721eSBaptiste Daroussin
129d0ef721eSBaptiste Daroussin if (wcsstr(str, pat) != 0)
130d0ef721eSBaptiste Daroussin return 1;
131d0ef721eSBaptiste Daroussin
132d0ef721eSBaptiste Daroussin #if defined(REGEX)
133d0ef721eSBaptiste Daroussin if (regcomp(&re, ct_encode_string(pat, &conv), 0) == 0) {
134d0ef721eSBaptiste Daroussin rv = regexec(&re, ct_encode_string(str, &conv), (size_t)0, NULL,
135d0ef721eSBaptiste Daroussin 0) == 0;
136d0ef721eSBaptiste Daroussin regfree(&re);
137d0ef721eSBaptiste Daroussin } else {
138d0ef721eSBaptiste Daroussin rv = 0;
139d0ef721eSBaptiste Daroussin }
140d0ef721eSBaptiste Daroussin return rv;
141d0ef721eSBaptiste Daroussin #elif defined(REGEXP)
142d0ef721eSBaptiste Daroussin if ((re = regcomp(ct_encode_string(pat, &conv))) != NULL) {
143d0ef721eSBaptiste Daroussin rv = regexec(re, ct_encode_string(str, &conv));
144d0ef721eSBaptiste Daroussin el_free(re);
145d0ef721eSBaptiste Daroussin } else {
146d0ef721eSBaptiste Daroussin rv = 0;
147d0ef721eSBaptiste Daroussin }
148d0ef721eSBaptiste Daroussin return rv;
149d0ef721eSBaptiste Daroussin #else
150d0ef721eSBaptiste Daroussin if (re_comp(ct_encode_string(pat, &conv)) != NULL)
151d0ef721eSBaptiste Daroussin return 0;
152d0ef721eSBaptiste Daroussin else
153d0ef721eSBaptiste Daroussin return re_exec(ct_encode_string(str, &conv)) == 1;
154d0ef721eSBaptiste Daroussin #endif
155d0ef721eSBaptiste Daroussin }
156d0ef721eSBaptiste Daroussin
157d0ef721eSBaptiste Daroussin
158d0ef721eSBaptiste Daroussin /* c_hmatch():
159d0ef721eSBaptiste Daroussin * return True if the pattern matches the prefix
160d0ef721eSBaptiste Daroussin */
161d0ef721eSBaptiste Daroussin libedit_private int
c_hmatch(EditLine * el,const wchar_t * str)162d0ef721eSBaptiste Daroussin c_hmatch(EditLine *el, const wchar_t *str)
163d0ef721eSBaptiste Daroussin {
164d0ef721eSBaptiste Daroussin #ifdef SDEBUG
165*f9a159daSBaptiste Daroussin (void) fprintf(el->el_errfile, "match `%ls' with `%ls'\n",
166d0ef721eSBaptiste Daroussin el->el_search.patbuf, str);
167d0ef721eSBaptiste Daroussin #endif /* SDEBUG */
168d0ef721eSBaptiste Daroussin
169d0ef721eSBaptiste Daroussin return el_match(str, el->el_search.patbuf);
170d0ef721eSBaptiste Daroussin }
171d0ef721eSBaptiste Daroussin
172d0ef721eSBaptiste Daroussin
173d0ef721eSBaptiste Daroussin /* c_setpat():
174d0ef721eSBaptiste Daroussin * Set the history seatch pattern
175d0ef721eSBaptiste Daroussin */
176d0ef721eSBaptiste Daroussin libedit_private void
c_setpat(EditLine * el)177d0ef721eSBaptiste Daroussin c_setpat(EditLine *el)
178d0ef721eSBaptiste Daroussin {
179d0ef721eSBaptiste Daroussin if (el->el_state.lastcmd != ED_SEARCH_PREV_HISTORY &&
180d0ef721eSBaptiste Daroussin el->el_state.lastcmd != ED_SEARCH_NEXT_HISTORY) {
181d0ef721eSBaptiste Daroussin el->el_search.patlen =
182d0ef721eSBaptiste Daroussin (size_t)(EL_CURSOR(el) - el->el_line.buffer);
183d0ef721eSBaptiste Daroussin if (el->el_search.patlen >= EL_BUFSIZ)
184d0ef721eSBaptiste Daroussin el->el_search.patlen = EL_BUFSIZ - 1;
185d0ef721eSBaptiste Daroussin (void) wcsncpy(el->el_search.patbuf, el->el_line.buffer,
186d0ef721eSBaptiste Daroussin el->el_search.patlen);
187d0ef721eSBaptiste Daroussin el->el_search.patbuf[el->el_search.patlen] = '\0';
188d0ef721eSBaptiste Daroussin }
189d0ef721eSBaptiste Daroussin #ifdef SDEBUG
190d0ef721eSBaptiste Daroussin (void) fprintf(el->el_errfile, "\neventno = %d\n",
191d0ef721eSBaptiste Daroussin el->el_history.eventno);
192*f9a159daSBaptiste Daroussin (void) fprintf(el->el_errfile, "patlen = %ld\n", el->el_search.patlen);
193*f9a159daSBaptiste Daroussin (void) fprintf(el->el_errfile, "patbuf = \"%ls\"\n",
194d0ef721eSBaptiste Daroussin el->el_search.patbuf);
195*f9a159daSBaptiste Daroussin (void) fprintf(el->el_errfile, "cursor %ld lastchar %ld\n",
196d0ef721eSBaptiste Daroussin EL_CURSOR(el) - el->el_line.buffer,
197d0ef721eSBaptiste Daroussin el->el_line.lastchar - el->el_line.buffer);
198d0ef721eSBaptiste Daroussin #endif
199d0ef721eSBaptiste Daroussin }
200d0ef721eSBaptiste Daroussin
201d0ef721eSBaptiste Daroussin
202d0ef721eSBaptiste Daroussin /* ce_inc_search():
203d0ef721eSBaptiste Daroussin * Emacs incremental search
204d0ef721eSBaptiste Daroussin */
205d0ef721eSBaptiste Daroussin libedit_private el_action_t
ce_inc_search(EditLine * el,int dir)206d0ef721eSBaptiste Daroussin ce_inc_search(EditLine *el, int dir)
207d0ef721eSBaptiste Daroussin {
208d0ef721eSBaptiste Daroussin static const wchar_t STRfwd[] = L"fwd", STRbck[] = L"bck";
209d0ef721eSBaptiste Daroussin static wchar_t pchar = L':'; /* ':' = normal, '?' = failed */
210d0ef721eSBaptiste Daroussin static wchar_t endcmd[2] = {'\0', '\0'};
211d0ef721eSBaptiste Daroussin wchar_t *ocursor = el->el_line.cursor, oldpchar = pchar, ch;
212d0ef721eSBaptiste Daroussin const wchar_t *cp;
213d0ef721eSBaptiste Daroussin
214d0ef721eSBaptiste Daroussin el_action_t ret = CC_NORM;
215d0ef721eSBaptiste Daroussin
216d0ef721eSBaptiste Daroussin int ohisteventno = el->el_history.eventno;
217d0ef721eSBaptiste Daroussin size_t oldpatlen = el->el_search.patlen;
218d0ef721eSBaptiste Daroussin int newdir = dir;
219d0ef721eSBaptiste Daroussin int done, redo;
220d0ef721eSBaptiste Daroussin
221d0ef721eSBaptiste Daroussin if (el->el_line.lastchar + sizeof(STRfwd) /
222d0ef721eSBaptiste Daroussin sizeof(*el->el_line.lastchar) + 2 +
223d0ef721eSBaptiste Daroussin el->el_search.patlen >= el->el_line.limit)
224d0ef721eSBaptiste Daroussin return CC_ERROR;
225d0ef721eSBaptiste Daroussin
226d0ef721eSBaptiste Daroussin for (;;) {
227d0ef721eSBaptiste Daroussin
228d0ef721eSBaptiste Daroussin if (el->el_search.patlen == 0) { /* first round */
229d0ef721eSBaptiste Daroussin pchar = ':';
230d0ef721eSBaptiste Daroussin #ifdef ANCHOR
231d0ef721eSBaptiste Daroussin #define LEN 2
232d0ef721eSBaptiste Daroussin el->el_search.patbuf[el->el_search.patlen++] = '.';
233d0ef721eSBaptiste Daroussin el->el_search.patbuf[el->el_search.patlen++] = '*';
234d0ef721eSBaptiste Daroussin #else
235d0ef721eSBaptiste Daroussin #define LEN 0
236d0ef721eSBaptiste Daroussin #endif
237d0ef721eSBaptiste Daroussin }
238d0ef721eSBaptiste Daroussin done = redo = 0;
239d0ef721eSBaptiste Daroussin *el->el_line.lastchar++ = '\n';
240d0ef721eSBaptiste Daroussin for (cp = (newdir == ED_SEARCH_PREV_HISTORY) ? STRbck : STRfwd;
241d0ef721eSBaptiste Daroussin *cp; *el->el_line.lastchar++ = *cp++)
242d0ef721eSBaptiste Daroussin continue;
243d0ef721eSBaptiste Daroussin *el->el_line.lastchar++ = pchar;
244d0ef721eSBaptiste Daroussin for (cp = &el->el_search.patbuf[LEN];
245d0ef721eSBaptiste Daroussin cp < &el->el_search.patbuf[el->el_search.patlen];
246d0ef721eSBaptiste Daroussin *el->el_line.lastchar++ = *cp++)
247d0ef721eSBaptiste Daroussin continue;
248d0ef721eSBaptiste Daroussin *el->el_line.lastchar = '\0';
249d0ef721eSBaptiste Daroussin re_refresh(el);
250d0ef721eSBaptiste Daroussin
251d0ef721eSBaptiste Daroussin if (el_wgetc(el, &ch) != 1)
252d0ef721eSBaptiste Daroussin return ed_end_of_file(el, 0);
253d0ef721eSBaptiste Daroussin
254d0ef721eSBaptiste Daroussin switch (el->el_map.current[(unsigned char) ch]) {
255d0ef721eSBaptiste Daroussin case ED_INSERT:
256d0ef721eSBaptiste Daroussin case ED_DIGIT:
257d0ef721eSBaptiste Daroussin if (el->el_search.patlen >= EL_BUFSIZ - LEN)
258d0ef721eSBaptiste Daroussin terminal_beep(el);
259d0ef721eSBaptiste Daroussin else {
260d0ef721eSBaptiste Daroussin el->el_search.patbuf[el->el_search.patlen++] =
261d0ef721eSBaptiste Daroussin ch;
262d0ef721eSBaptiste Daroussin *el->el_line.lastchar++ = ch;
263d0ef721eSBaptiste Daroussin *el->el_line.lastchar = '\0';
264d0ef721eSBaptiste Daroussin re_refresh(el);
265d0ef721eSBaptiste Daroussin }
266d0ef721eSBaptiste Daroussin break;
267d0ef721eSBaptiste Daroussin
268d0ef721eSBaptiste Daroussin case EM_INC_SEARCH_NEXT:
269d0ef721eSBaptiste Daroussin newdir = ED_SEARCH_NEXT_HISTORY;
270d0ef721eSBaptiste Daroussin redo++;
271d0ef721eSBaptiste Daroussin break;
272d0ef721eSBaptiste Daroussin
273d0ef721eSBaptiste Daroussin case EM_INC_SEARCH_PREV:
274d0ef721eSBaptiste Daroussin newdir = ED_SEARCH_PREV_HISTORY;
275d0ef721eSBaptiste Daroussin redo++;
276d0ef721eSBaptiste Daroussin break;
277d0ef721eSBaptiste Daroussin
278d0ef721eSBaptiste Daroussin case EM_DELETE_PREV_CHAR:
279d0ef721eSBaptiste Daroussin case ED_DELETE_PREV_CHAR:
280d0ef721eSBaptiste Daroussin if (el->el_search.patlen > LEN)
281d0ef721eSBaptiste Daroussin done++;
282d0ef721eSBaptiste Daroussin else
283d0ef721eSBaptiste Daroussin terminal_beep(el);
284d0ef721eSBaptiste Daroussin break;
285d0ef721eSBaptiste Daroussin
286d0ef721eSBaptiste Daroussin default:
287d0ef721eSBaptiste Daroussin switch (ch) {
288d0ef721eSBaptiste Daroussin case 0007: /* ^G: Abort */
289d0ef721eSBaptiste Daroussin ret = CC_ERROR;
290d0ef721eSBaptiste Daroussin done++;
291d0ef721eSBaptiste Daroussin break;
292d0ef721eSBaptiste Daroussin
293d0ef721eSBaptiste Daroussin case 0027: /* ^W: Append word */
294d0ef721eSBaptiste Daroussin /* No can do if globbing characters in pattern */
295d0ef721eSBaptiste Daroussin for (cp = &el->el_search.patbuf[LEN];; cp++)
296d0ef721eSBaptiste Daroussin if (cp >= &el->el_search.patbuf[
297d0ef721eSBaptiste Daroussin el->el_search.patlen]) {
298d0ef721eSBaptiste Daroussin el->el_line.cursor +=
299d0ef721eSBaptiste Daroussin el->el_search.patlen - LEN - 1;
300d0ef721eSBaptiste Daroussin cp = c__next_word(el->el_line.cursor,
301d0ef721eSBaptiste Daroussin el->el_line.lastchar, 1,
302d0ef721eSBaptiste Daroussin ce__isword);
303d0ef721eSBaptiste Daroussin while (el->el_line.cursor < cp &&
304d0ef721eSBaptiste Daroussin *el->el_line.cursor != '\n') {
305d0ef721eSBaptiste Daroussin if (el->el_search.patlen >=
306d0ef721eSBaptiste Daroussin EL_BUFSIZ - LEN) {
307d0ef721eSBaptiste Daroussin terminal_beep(el);
308d0ef721eSBaptiste Daroussin break;
309d0ef721eSBaptiste Daroussin }
310d0ef721eSBaptiste Daroussin el->el_search.patbuf[el->el_search.patlen++] =
311d0ef721eSBaptiste Daroussin *el->el_line.cursor;
312d0ef721eSBaptiste Daroussin *el->el_line.lastchar++ =
313d0ef721eSBaptiste Daroussin *el->el_line.cursor++;
314d0ef721eSBaptiste Daroussin }
315d0ef721eSBaptiste Daroussin el->el_line.cursor = ocursor;
316d0ef721eSBaptiste Daroussin *el->el_line.lastchar = '\0';
317d0ef721eSBaptiste Daroussin re_refresh(el);
318d0ef721eSBaptiste Daroussin break;
319d0ef721eSBaptiste Daroussin } else if (isglob(*cp)) {
320d0ef721eSBaptiste Daroussin terminal_beep(el);
321d0ef721eSBaptiste Daroussin break;
322d0ef721eSBaptiste Daroussin }
323d0ef721eSBaptiste Daroussin break;
324d0ef721eSBaptiste Daroussin
325d0ef721eSBaptiste Daroussin default: /* Terminate and execute cmd */
326d0ef721eSBaptiste Daroussin endcmd[0] = ch;
327d0ef721eSBaptiste Daroussin el_wpush(el, endcmd);
328d0ef721eSBaptiste Daroussin /* FALLTHROUGH */
329d0ef721eSBaptiste Daroussin
330d0ef721eSBaptiste Daroussin case 0033: /* ESC: Terminate */
331d0ef721eSBaptiste Daroussin ret = CC_REFRESH;
332d0ef721eSBaptiste Daroussin done++;
333d0ef721eSBaptiste Daroussin break;
334d0ef721eSBaptiste Daroussin }
335d0ef721eSBaptiste Daroussin break;
336d0ef721eSBaptiste Daroussin }
337d0ef721eSBaptiste Daroussin
338d0ef721eSBaptiste Daroussin while (el->el_line.lastchar > el->el_line.buffer &&
339d0ef721eSBaptiste Daroussin *el->el_line.lastchar != '\n')
340d0ef721eSBaptiste Daroussin *el->el_line.lastchar-- = '\0';
341d0ef721eSBaptiste Daroussin *el->el_line.lastchar = '\0';
342d0ef721eSBaptiste Daroussin
343d0ef721eSBaptiste Daroussin if (!done) {
344d0ef721eSBaptiste Daroussin
345d0ef721eSBaptiste Daroussin /* Can't search if unmatched '[' */
346d0ef721eSBaptiste Daroussin for (cp = &el->el_search.patbuf[el->el_search.patlen-1],
347d0ef721eSBaptiste Daroussin ch = L']';
348d0ef721eSBaptiste Daroussin cp >= &el->el_search.patbuf[LEN];
349d0ef721eSBaptiste Daroussin cp--)
350d0ef721eSBaptiste Daroussin if (*cp == '[' || *cp == ']') {
351d0ef721eSBaptiste Daroussin ch = *cp;
352d0ef721eSBaptiste Daroussin break;
353d0ef721eSBaptiste Daroussin }
354d0ef721eSBaptiste Daroussin if (el->el_search.patlen > LEN && ch != L'[') {
355d0ef721eSBaptiste Daroussin if (redo && newdir == dir) {
356d0ef721eSBaptiste Daroussin if (pchar == '?') { /* wrap around */
357d0ef721eSBaptiste Daroussin el->el_history.eventno =
358d0ef721eSBaptiste Daroussin newdir == ED_SEARCH_PREV_HISTORY ? 0 : 0x7fffffff;
359d0ef721eSBaptiste Daroussin if (hist_get(el) == CC_ERROR)
360d0ef721eSBaptiste Daroussin /* el->el_history.event
361d0ef721eSBaptiste Daroussin * no was fixed by
362d0ef721eSBaptiste Daroussin * first call */
363d0ef721eSBaptiste Daroussin (void) hist_get(el);
364d0ef721eSBaptiste Daroussin el->el_line.cursor = newdir ==
365d0ef721eSBaptiste Daroussin ED_SEARCH_PREV_HISTORY ?
366d0ef721eSBaptiste Daroussin el->el_line.lastchar :
367d0ef721eSBaptiste Daroussin el->el_line.buffer;
368d0ef721eSBaptiste Daroussin } else
369d0ef721eSBaptiste Daroussin el->el_line.cursor +=
370d0ef721eSBaptiste Daroussin newdir ==
371d0ef721eSBaptiste Daroussin ED_SEARCH_PREV_HISTORY ?
372d0ef721eSBaptiste Daroussin -1 : 1;
373d0ef721eSBaptiste Daroussin }
374d0ef721eSBaptiste Daroussin #ifdef ANCHOR
375d0ef721eSBaptiste Daroussin el->el_search.patbuf[el->el_search.patlen++] =
376d0ef721eSBaptiste Daroussin '.';
377d0ef721eSBaptiste Daroussin el->el_search.patbuf[el->el_search.patlen++] =
378d0ef721eSBaptiste Daroussin '*';
379d0ef721eSBaptiste Daroussin #endif
380d0ef721eSBaptiste Daroussin el->el_search.patbuf[el->el_search.patlen] =
381d0ef721eSBaptiste Daroussin '\0';
382d0ef721eSBaptiste Daroussin if (el->el_line.cursor < el->el_line.buffer ||
383d0ef721eSBaptiste Daroussin el->el_line.cursor > el->el_line.lastchar ||
384d0ef721eSBaptiste Daroussin (ret = ce_search_line(el, newdir))
385d0ef721eSBaptiste Daroussin == CC_ERROR) {
386d0ef721eSBaptiste Daroussin /* avoid c_setpat */
387d0ef721eSBaptiste Daroussin el->el_state.lastcmd =
388d0ef721eSBaptiste Daroussin (el_action_t) newdir;
389d0ef721eSBaptiste Daroussin ret = (el_action_t)
390d0ef721eSBaptiste Daroussin (newdir == ED_SEARCH_PREV_HISTORY ?
391d0ef721eSBaptiste Daroussin ed_search_prev_history(el, 0) :
392d0ef721eSBaptiste Daroussin ed_search_next_history(el, 0));
393d0ef721eSBaptiste Daroussin if (ret != CC_ERROR) {
394d0ef721eSBaptiste Daroussin el->el_line.cursor = newdir ==
395d0ef721eSBaptiste Daroussin ED_SEARCH_PREV_HISTORY ?
396d0ef721eSBaptiste Daroussin el->el_line.lastchar :
397d0ef721eSBaptiste Daroussin el->el_line.buffer;
398d0ef721eSBaptiste Daroussin (void) ce_search_line(el,
399d0ef721eSBaptiste Daroussin newdir);
400d0ef721eSBaptiste Daroussin }
401d0ef721eSBaptiste Daroussin }
402d0ef721eSBaptiste Daroussin el->el_search.patlen -= LEN;
403d0ef721eSBaptiste Daroussin el->el_search.patbuf[el->el_search.patlen] =
404d0ef721eSBaptiste Daroussin '\0';
405d0ef721eSBaptiste Daroussin if (ret == CC_ERROR) {
406d0ef721eSBaptiste Daroussin terminal_beep(el);
407d0ef721eSBaptiste Daroussin if (el->el_history.eventno !=
408d0ef721eSBaptiste Daroussin ohisteventno) {
409d0ef721eSBaptiste Daroussin el->el_history.eventno =
410d0ef721eSBaptiste Daroussin ohisteventno;
411d0ef721eSBaptiste Daroussin if (hist_get(el) == CC_ERROR)
412d0ef721eSBaptiste Daroussin return CC_ERROR;
413d0ef721eSBaptiste Daroussin }
414d0ef721eSBaptiste Daroussin el->el_line.cursor = ocursor;
415d0ef721eSBaptiste Daroussin pchar = '?';
416d0ef721eSBaptiste Daroussin } else {
417d0ef721eSBaptiste Daroussin pchar = ':';
418d0ef721eSBaptiste Daroussin }
419d0ef721eSBaptiste Daroussin }
420d0ef721eSBaptiste Daroussin ret = ce_inc_search(el, newdir);
421d0ef721eSBaptiste Daroussin
422d0ef721eSBaptiste Daroussin if (ret == CC_ERROR && pchar == '?' && oldpchar == ':')
423d0ef721eSBaptiste Daroussin /*
424d0ef721eSBaptiste Daroussin * break abort of failed search at last
425d0ef721eSBaptiste Daroussin * non-failed
426d0ef721eSBaptiste Daroussin */
427d0ef721eSBaptiste Daroussin ret = CC_NORM;
428d0ef721eSBaptiste Daroussin
429d0ef721eSBaptiste Daroussin }
430d0ef721eSBaptiste Daroussin if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) {
431d0ef721eSBaptiste Daroussin /* restore on normal return or error exit */
432d0ef721eSBaptiste Daroussin pchar = oldpchar;
433d0ef721eSBaptiste Daroussin el->el_search.patlen = oldpatlen;
434d0ef721eSBaptiste Daroussin if (el->el_history.eventno != ohisteventno) {
435d0ef721eSBaptiste Daroussin el->el_history.eventno = ohisteventno;
436d0ef721eSBaptiste Daroussin if (hist_get(el) == CC_ERROR)
437d0ef721eSBaptiste Daroussin return CC_ERROR;
438d0ef721eSBaptiste Daroussin }
439d0ef721eSBaptiste Daroussin el->el_line.cursor = ocursor;
440d0ef721eSBaptiste Daroussin if (ret == CC_ERROR)
441d0ef721eSBaptiste Daroussin re_refresh(el);
442d0ef721eSBaptiste Daroussin }
443d0ef721eSBaptiste Daroussin if (done || ret != CC_NORM)
444d0ef721eSBaptiste Daroussin return ret;
445d0ef721eSBaptiste Daroussin }
446d0ef721eSBaptiste Daroussin }
447d0ef721eSBaptiste Daroussin
448d0ef721eSBaptiste Daroussin
449d0ef721eSBaptiste Daroussin /* cv_search():
450d0ef721eSBaptiste Daroussin * Vi search.
451d0ef721eSBaptiste Daroussin */
452d0ef721eSBaptiste Daroussin libedit_private el_action_t
cv_search(EditLine * el,int dir)453d0ef721eSBaptiste Daroussin cv_search(EditLine *el, int dir)
454d0ef721eSBaptiste Daroussin {
455d0ef721eSBaptiste Daroussin wchar_t ch;
456d0ef721eSBaptiste Daroussin wchar_t tmpbuf[EL_BUFSIZ];
457d0ef721eSBaptiste Daroussin ssize_t tmplen;
458d0ef721eSBaptiste Daroussin
459d0ef721eSBaptiste Daroussin #ifdef ANCHOR
460d0ef721eSBaptiste Daroussin tmpbuf[0] = '.';
461d0ef721eSBaptiste Daroussin tmpbuf[1] = '*';
462d0ef721eSBaptiste Daroussin #endif
463d0ef721eSBaptiste Daroussin tmplen = LEN;
464d0ef721eSBaptiste Daroussin
465d0ef721eSBaptiste Daroussin el->el_search.patdir = dir;
466d0ef721eSBaptiste Daroussin
467d0ef721eSBaptiste Daroussin tmplen = c_gets(el, &tmpbuf[LEN],
468d0ef721eSBaptiste Daroussin dir == ED_SEARCH_PREV_HISTORY ? L"\n/" : L"\n?" );
469d0ef721eSBaptiste Daroussin if (tmplen == -1)
470d0ef721eSBaptiste Daroussin return CC_REFRESH;
471d0ef721eSBaptiste Daroussin
472d0ef721eSBaptiste Daroussin tmplen += LEN;
473d0ef721eSBaptiste Daroussin ch = tmpbuf[tmplen];
474d0ef721eSBaptiste Daroussin tmpbuf[tmplen] = '\0';
475d0ef721eSBaptiste Daroussin
476d0ef721eSBaptiste Daroussin if (tmplen == LEN) {
477d0ef721eSBaptiste Daroussin /*
478d0ef721eSBaptiste Daroussin * Use the old pattern, but wild-card it.
479d0ef721eSBaptiste Daroussin */
480d0ef721eSBaptiste Daroussin if (el->el_search.patlen == 0) {
481d0ef721eSBaptiste Daroussin re_refresh(el);
482d0ef721eSBaptiste Daroussin return CC_ERROR;
483d0ef721eSBaptiste Daroussin }
484d0ef721eSBaptiste Daroussin #ifdef ANCHOR
485d0ef721eSBaptiste Daroussin if (el->el_search.patbuf[0] != '.' &&
486d0ef721eSBaptiste Daroussin el->el_search.patbuf[0] != '*') {
487d0ef721eSBaptiste Daroussin (void) wcsncpy(tmpbuf, el->el_search.patbuf,
488d0ef721eSBaptiste Daroussin sizeof(tmpbuf) / sizeof(*tmpbuf) - 1);
489d0ef721eSBaptiste Daroussin el->el_search.patbuf[0] = '.';
490d0ef721eSBaptiste Daroussin el->el_search.patbuf[1] = '*';
491d0ef721eSBaptiste Daroussin (void) wcsncpy(&el->el_search.patbuf[2], tmpbuf,
492d0ef721eSBaptiste Daroussin EL_BUFSIZ - 3);
493d0ef721eSBaptiste Daroussin el->el_search.patlen++;
494d0ef721eSBaptiste Daroussin el->el_search.patbuf[el->el_search.patlen++] = '.';
495d0ef721eSBaptiste Daroussin el->el_search.patbuf[el->el_search.patlen++] = '*';
496d0ef721eSBaptiste Daroussin el->el_search.patbuf[el->el_search.patlen] = '\0';
497d0ef721eSBaptiste Daroussin }
498d0ef721eSBaptiste Daroussin #endif
499d0ef721eSBaptiste Daroussin } else {
500d0ef721eSBaptiste Daroussin #ifdef ANCHOR
501d0ef721eSBaptiste Daroussin tmpbuf[tmplen++] = '.';
502d0ef721eSBaptiste Daroussin tmpbuf[tmplen++] = '*';
503d0ef721eSBaptiste Daroussin #endif
504d0ef721eSBaptiste Daroussin tmpbuf[tmplen] = '\0';
505d0ef721eSBaptiste Daroussin (void) wcsncpy(el->el_search.patbuf, tmpbuf, EL_BUFSIZ - 1);
506d0ef721eSBaptiste Daroussin el->el_search.patlen = (size_t)tmplen;
507d0ef721eSBaptiste Daroussin }
508d0ef721eSBaptiste Daroussin el->el_state.lastcmd = (el_action_t) dir; /* avoid c_setpat */
509d0ef721eSBaptiste Daroussin el->el_line.cursor = el->el_line.lastchar = el->el_line.buffer;
510d0ef721eSBaptiste Daroussin if ((dir == ED_SEARCH_PREV_HISTORY ? ed_search_prev_history(el, 0) :
511d0ef721eSBaptiste Daroussin ed_search_next_history(el, 0)) == CC_ERROR) {
512d0ef721eSBaptiste Daroussin re_refresh(el);
513d0ef721eSBaptiste Daroussin return CC_ERROR;
514d0ef721eSBaptiste Daroussin }
515d0ef721eSBaptiste Daroussin if (ch == 0033) {
516d0ef721eSBaptiste Daroussin re_refresh(el);
517d0ef721eSBaptiste Daroussin return ed_newline(el, 0);
518d0ef721eSBaptiste Daroussin }
519d0ef721eSBaptiste Daroussin return CC_REFRESH;
520d0ef721eSBaptiste Daroussin }
521d0ef721eSBaptiste Daroussin
522d0ef721eSBaptiste Daroussin
523d0ef721eSBaptiste Daroussin /* ce_search_line():
524d0ef721eSBaptiste Daroussin * Look for a pattern inside a line
525d0ef721eSBaptiste Daroussin */
526d0ef721eSBaptiste Daroussin libedit_private el_action_t
ce_search_line(EditLine * el,int dir)527d0ef721eSBaptiste Daroussin ce_search_line(EditLine *el, int dir)
528d0ef721eSBaptiste Daroussin {
529d0ef721eSBaptiste Daroussin wchar_t *cp = el->el_line.cursor;
530d0ef721eSBaptiste Daroussin wchar_t *pattern = el->el_search.patbuf;
531d0ef721eSBaptiste Daroussin wchar_t oc, *ocp;
532d0ef721eSBaptiste Daroussin #ifdef ANCHOR
533d0ef721eSBaptiste Daroussin ocp = &pattern[1];
534d0ef721eSBaptiste Daroussin oc = *ocp;
535d0ef721eSBaptiste Daroussin *ocp = '^';
536d0ef721eSBaptiste Daroussin #else
537d0ef721eSBaptiste Daroussin ocp = pattern;
538d0ef721eSBaptiste Daroussin oc = *ocp;
539d0ef721eSBaptiste Daroussin #endif
540d0ef721eSBaptiste Daroussin
541d0ef721eSBaptiste Daroussin if (dir == ED_SEARCH_PREV_HISTORY) {
542d0ef721eSBaptiste Daroussin for (; cp >= el->el_line.buffer; cp--) {
543d0ef721eSBaptiste Daroussin if (el_match(cp, ocp)) {
544d0ef721eSBaptiste Daroussin *ocp = oc;
545d0ef721eSBaptiste Daroussin el->el_line.cursor = cp;
546d0ef721eSBaptiste Daroussin return CC_NORM;
547d0ef721eSBaptiste Daroussin }
548d0ef721eSBaptiste Daroussin }
549d0ef721eSBaptiste Daroussin *ocp = oc;
550d0ef721eSBaptiste Daroussin return CC_ERROR;
551d0ef721eSBaptiste Daroussin } else {
552d0ef721eSBaptiste Daroussin for (; *cp != '\0' && cp < el->el_line.limit; cp++) {
553d0ef721eSBaptiste Daroussin if (el_match(cp, ocp)) {
554d0ef721eSBaptiste Daroussin *ocp = oc;
555d0ef721eSBaptiste Daroussin el->el_line.cursor = cp;
556d0ef721eSBaptiste Daroussin return CC_NORM;
557d0ef721eSBaptiste Daroussin }
558d0ef721eSBaptiste Daroussin }
559d0ef721eSBaptiste Daroussin *ocp = oc;
560d0ef721eSBaptiste Daroussin return CC_ERROR;
561d0ef721eSBaptiste Daroussin }
562d0ef721eSBaptiste Daroussin }
563d0ef721eSBaptiste Daroussin
564d0ef721eSBaptiste Daroussin
565d0ef721eSBaptiste Daroussin /* cv_repeat_srch():
566d0ef721eSBaptiste Daroussin * Vi repeat search
567d0ef721eSBaptiste Daroussin */
568d0ef721eSBaptiste Daroussin libedit_private el_action_t
cv_repeat_srch(EditLine * el,wint_t c)569d0ef721eSBaptiste Daroussin cv_repeat_srch(EditLine *el, wint_t c)
570d0ef721eSBaptiste Daroussin {
571d0ef721eSBaptiste Daroussin
572d0ef721eSBaptiste Daroussin #ifdef SDEBUG
573*f9a159daSBaptiste Daroussin static ct_buffer_t conv;
574*f9a159daSBaptiste Daroussin (void) fprintf(el->el_errfile, "dir %d patlen %ld patbuf %s\n",
575*f9a159daSBaptiste Daroussin c, el->el_search.patlen, ct_encode_string(el->el_search.patbuf, &conv));
576d0ef721eSBaptiste Daroussin #endif
577d0ef721eSBaptiste Daroussin
578d0ef721eSBaptiste Daroussin el->el_state.lastcmd = (el_action_t) c; /* Hack to stop c_setpat */
579d0ef721eSBaptiste Daroussin el->el_line.lastchar = el->el_line.buffer;
580d0ef721eSBaptiste Daroussin
581d0ef721eSBaptiste Daroussin switch (c) {
582d0ef721eSBaptiste Daroussin case ED_SEARCH_NEXT_HISTORY:
583d0ef721eSBaptiste Daroussin return ed_search_next_history(el, 0);
584d0ef721eSBaptiste Daroussin case ED_SEARCH_PREV_HISTORY:
585d0ef721eSBaptiste Daroussin return ed_search_prev_history(el, 0);
586d0ef721eSBaptiste Daroussin default:
587d0ef721eSBaptiste Daroussin return CC_ERROR;
588d0ef721eSBaptiste Daroussin }
589d0ef721eSBaptiste Daroussin }
590d0ef721eSBaptiste Daroussin
591d0ef721eSBaptiste Daroussin
592d0ef721eSBaptiste Daroussin /* cv_csearch():
593d0ef721eSBaptiste Daroussin * Vi character search
594d0ef721eSBaptiste Daroussin */
595d0ef721eSBaptiste Daroussin libedit_private el_action_t
cv_csearch(EditLine * el,int direction,wint_t ch,int count,int tflag)596d0ef721eSBaptiste Daroussin cv_csearch(EditLine *el, int direction, wint_t ch, int count, int tflag)
597d0ef721eSBaptiste Daroussin {
598d0ef721eSBaptiste Daroussin wchar_t *cp;
599d0ef721eSBaptiste Daroussin
600d0ef721eSBaptiste Daroussin if (ch == 0)
601d0ef721eSBaptiste Daroussin return CC_ERROR;
602d0ef721eSBaptiste Daroussin
603d0ef721eSBaptiste Daroussin if (ch == (wint_t)-1) {
604d0ef721eSBaptiste Daroussin wchar_t c;
605d0ef721eSBaptiste Daroussin if (el_wgetc(el, &c) != 1)
606d0ef721eSBaptiste Daroussin return ed_end_of_file(el, 0);
607d0ef721eSBaptiste Daroussin ch = c;
608d0ef721eSBaptiste Daroussin }
609d0ef721eSBaptiste Daroussin
610d0ef721eSBaptiste Daroussin /* Save for ';' and ',' commands */
611d0ef721eSBaptiste Daroussin el->el_search.chacha = ch;
612d0ef721eSBaptiste Daroussin el->el_search.chadir = direction;
613d0ef721eSBaptiste Daroussin el->el_search.chatflg = (char)tflag;
614d0ef721eSBaptiste Daroussin
615d0ef721eSBaptiste Daroussin cp = el->el_line.cursor;
616d0ef721eSBaptiste Daroussin while (count--) {
617d0ef721eSBaptiste Daroussin if ((wint_t)*cp == ch)
618d0ef721eSBaptiste Daroussin cp += direction;
619d0ef721eSBaptiste Daroussin for (;;cp += direction) {
620d0ef721eSBaptiste Daroussin if (cp >= el->el_line.lastchar)
621d0ef721eSBaptiste Daroussin return CC_ERROR;
622d0ef721eSBaptiste Daroussin if (cp < el->el_line.buffer)
623d0ef721eSBaptiste Daroussin return CC_ERROR;
624d0ef721eSBaptiste Daroussin if ((wint_t)*cp == ch)
625d0ef721eSBaptiste Daroussin break;
626d0ef721eSBaptiste Daroussin }
627d0ef721eSBaptiste Daroussin }
628d0ef721eSBaptiste Daroussin
629d0ef721eSBaptiste Daroussin if (tflag)
630d0ef721eSBaptiste Daroussin cp -= direction;
631d0ef721eSBaptiste Daroussin
632d0ef721eSBaptiste Daroussin el->el_line.cursor = cp;
633d0ef721eSBaptiste Daroussin
634d0ef721eSBaptiste Daroussin if (el->el_chared.c_vcmd.action != NOP) {
635d0ef721eSBaptiste Daroussin if (direction > 0)
636d0ef721eSBaptiste Daroussin el->el_line.cursor++;
637d0ef721eSBaptiste Daroussin cv_delfini(el);
638d0ef721eSBaptiste Daroussin return CC_REFRESH;
639d0ef721eSBaptiste Daroussin }
640d0ef721eSBaptiste Daroussin return CC_CURSOR;
641d0ef721eSBaptiste Daroussin }
642