xref: /third_party/mksh/edit.c (revision c84f3f3c)
1c84f3f3cSopenharmony_ci/*	$OpenBSD: edit.c,v 1.41 2015/09/01 13:12:31 tedu Exp $	*/
2c84f3f3cSopenharmony_ci/*	$OpenBSD: edit.h,v 1.9 2011/05/30 17:14:35 martynas Exp $	*/
3c84f3f3cSopenharmony_ci/*	$OpenBSD: emacs.c,v 1.52 2015/09/10 22:48:58 nicm Exp $	*/
4c84f3f3cSopenharmony_ci/*	$OpenBSD: vi.c,v 1.30 2015/09/10 22:48:58 nicm Exp $	*/
5c84f3f3cSopenharmony_ci
6c84f3f3cSopenharmony_ci/*-
7c84f3f3cSopenharmony_ci * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
8c84f3f3cSopenharmony_ci *		 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018,
9c84f3f3cSopenharmony_ci *		 2019, 2020
10c84f3f3cSopenharmony_ci *	mirabilos <m@mirbsd.org>
11c84f3f3cSopenharmony_ci *
12c84f3f3cSopenharmony_ci * Provided that these terms and disclaimer and all copyright notices
13c84f3f3cSopenharmony_ci * are retained or reproduced in an accompanying document, permission
14c84f3f3cSopenharmony_ci * is granted to deal in this work without restriction, including un-
15c84f3f3cSopenharmony_ci * limited rights to use, publicly perform, distribute, sell, modify,
16c84f3f3cSopenharmony_ci * merge, give away, or sublicence.
17c84f3f3cSopenharmony_ci *
18c84f3f3cSopenharmony_ci * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
19c84f3f3cSopenharmony_ci * the utmost extent permitted by applicable law, neither express nor
20c84f3f3cSopenharmony_ci * implied; without malicious intent or gross negligence. In no event
21c84f3f3cSopenharmony_ci * may a licensor, author or contributor be held liable for indirect,
22c84f3f3cSopenharmony_ci * direct, other damage, loss, or other issues arising in any way out
23c84f3f3cSopenharmony_ci * of dealing in the work, even if advised of the possibility of such
24c84f3f3cSopenharmony_ci * damage or existence of a defect, except proven that it results out
25c84f3f3cSopenharmony_ci * of said person's immediate fault when using the work as intended.
26c84f3f3cSopenharmony_ci */
27c84f3f3cSopenharmony_ci
28c84f3f3cSopenharmony_ci#include "sh.h"
29c84f3f3cSopenharmony_ci
30c84f3f3cSopenharmony_ci#ifndef MKSH_NO_CMDLINE_EDITING
31c84f3f3cSopenharmony_ci
32c84f3f3cSopenharmony_ci__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.357 2020/10/31 05:02:17 tg Exp $");
33c84f3f3cSopenharmony_ci
34c84f3f3cSopenharmony_ci/*
35c84f3f3cSopenharmony_ci * in later versions we might use libtermcap for this, but since external
36c84f3f3cSopenharmony_ci * dependencies are problematic, this has not yet been decided on; another
37c84f3f3cSopenharmony_ci * good string is KSH_ESC_STRING "c" except on hardware terminals like the
38c84f3f3cSopenharmony_ci * DEC VT420 which do a full power cycle then...
39c84f3f3cSopenharmony_ci */
40c84f3f3cSopenharmony_ci#ifndef MKSH_CLS_STRING
41c84f3f3cSopenharmony_ci#define MKSH_CLS_STRING		KSH_ESC_STRING "[;H" KSH_ESC_STRING "[J"
42c84f3f3cSopenharmony_ci#endif
43c84f3f3cSopenharmony_ci
44c84f3f3cSopenharmony_ci#if !defined(MKSH_SMALL) || !MKSH_S_NOVI
45c84f3f3cSopenharmony_cistatic const char ctrl_x_e[] = "fc -e \"${VISUAL:-${EDITOR:-vi}}\" --";
46c84f3f3cSopenharmony_ci#endif
47c84f3f3cSopenharmony_ci
48c84f3f3cSopenharmony_ci/* tty driver characters we are interested in */
49c84f3f3cSopenharmony_ci#define EDCHAR_DISABLED	0xFFFFU
50c84f3f3cSopenharmony_ci#define EDCHAR_INITIAL	0xFFFEU
51c84f3f3cSopenharmony_cistatic struct {
52c84f3f3cSopenharmony_ci	unsigned short erase;
53c84f3f3cSopenharmony_ci	unsigned short kill;
54c84f3f3cSopenharmony_ci	unsigned short werase;
55c84f3f3cSopenharmony_ci	unsigned short intr;
56c84f3f3cSopenharmony_ci	unsigned short quit;
57c84f3f3cSopenharmony_ci	unsigned short eof;
58c84f3f3cSopenharmony_ci} edchars;
59c84f3f3cSopenharmony_ci
60c84f3f3cSopenharmony_ci#define isched(x,e) ((unsigned short)(unsigned char)(x) == (e))
61c84f3f3cSopenharmony_ci#define isedchar(x) (!((x) & ~0xFF))
62c84f3f3cSopenharmony_ci#ifndef _POSIX_VDISABLE
63c84f3f3cSopenharmony_ci#define toedchar(x) ((unsigned short)(unsigned char)(x))
64c84f3f3cSopenharmony_ci#else
65c84f3f3cSopenharmony_ci#define toedchar(x) (((_POSIX_VDISABLE != -1) && ((x) == _POSIX_VDISABLE)) ? \
66c84f3f3cSopenharmony_ci			((unsigned short)EDCHAR_DISABLED) : \
67c84f3f3cSopenharmony_ci			((unsigned short)(unsigned char)(x)))
68c84f3f3cSopenharmony_ci#endif
69c84f3f3cSopenharmony_ci
70c84f3f3cSopenharmony_ci/* x_cf_glob() flags */
71c84f3f3cSopenharmony_ci#define XCF_COMMAND	BIT(0)	/* Do command completion */
72c84f3f3cSopenharmony_ci#define XCF_FILE	BIT(1)	/* Do file completion */
73c84f3f3cSopenharmony_ci#define XCF_FULLPATH	BIT(2)	/* command completion: store full path */
74c84f3f3cSopenharmony_ci#define XCF_COMMAND_FILE (XCF_COMMAND | XCF_FILE)
75c84f3f3cSopenharmony_ci#define XCF_IS_COMMAND	BIT(3)	/* return flag: is command */
76c84f3f3cSopenharmony_ci#define XCF_IS_NOSPACE	BIT(4)	/* return flag: do not append a space */
77c84f3f3cSopenharmony_ci
78c84f3f3cSopenharmony_cistatic char editmode;
79c84f3f3cSopenharmony_cistatic int xx_cols;			/* for Emacs mode */
80c84f3f3cSopenharmony_cistatic int modified;			/* buffer has been "modified" */
81c84f3f3cSopenharmony_cistatic char *holdbufp;			/* place to hold last edit buffer */
82c84f3f3cSopenharmony_ci
83c84f3f3cSopenharmony_ci/* 0=dumb 1=tmux (for now) */
84c84f3f3cSopenharmony_cistatic uint8_t x_term_mode;
85c84f3f3cSopenharmony_ci
86c84f3f3cSopenharmony_cistatic void x_adjust(void);
87c84f3f3cSopenharmony_cistatic int x_getc(void);
88c84f3f3cSopenharmony_cistatic void x_putcf(int);
89c84f3f3cSopenharmony_cistatic void x_modified(void);
90c84f3f3cSopenharmony_cistatic void x_mode(bool);
91c84f3f3cSopenharmony_cistatic int x_do_comment(char *, ssize_t, ssize_t *);
92c84f3f3cSopenharmony_cistatic void x_print_expansions(int, char * const *, bool);
93c84f3f3cSopenharmony_cistatic int x_cf_glob(int *, const char *, int, int, int *, int *, char ***);
94c84f3f3cSopenharmony_cistatic size_t x_longest_prefix(int, char * const *);
95c84f3f3cSopenharmony_cistatic void x_glob_hlp_add_qchar(char *);
96c84f3f3cSopenharmony_cistatic char *x_glob_hlp_tilde_and_rem_qchar(char *, bool);
97c84f3f3cSopenharmony_cistatic size_t x_basename(const char *, const char *);
98c84f3f3cSopenharmony_cistatic void x_free_words(int, char **);
99c84f3f3cSopenharmony_cistatic int x_escape(const char *, size_t, int (*)(const char *, size_t));
100c84f3f3cSopenharmony_cistatic int x_emacs(char *);
101c84f3f3cSopenharmony_cistatic void x_init_prompt(bool);
102c84f3f3cSopenharmony_ci#if !MKSH_S_NOVI
103c84f3f3cSopenharmony_cistatic int x_vi(char *);
104c84f3f3cSopenharmony_ci#endif
105c84f3f3cSopenharmony_cistatic void x_intr(int, int) MKSH_A_NORETURN;
106c84f3f3cSopenharmony_ci
107c84f3f3cSopenharmony_ci#define x_flush()	shf_flush(shl_out)
108c84f3f3cSopenharmony_ci#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
109c84f3f3cSopenharmony_ci#define x_putc(c)	x_putcf(c)
110c84f3f3cSopenharmony_ci#else
111c84f3f3cSopenharmony_ci#define x_putc(c)	shf_putc((c), shl_out)
112c84f3f3cSopenharmony_ci#endif
113c84f3f3cSopenharmony_ci
114c84f3f3cSopenharmony_cistatic int path_order_cmp(const void *, const void *);
115c84f3f3cSopenharmony_cistatic void glob_table(const char *, XPtrV *, struct table *);
116c84f3f3cSopenharmony_cistatic void glob_path(int, const char *, XPtrV *, const char *);
117c84f3f3cSopenharmony_cistatic int x_file_glob(int *, char *, char ***);
118c84f3f3cSopenharmony_cistatic int x_command_glob(int, char *, char ***);
119c84f3f3cSopenharmony_cistatic int x_locate_word(const char *, int, int, int *, bool *);
120c84f3f3cSopenharmony_ci
121c84f3f3cSopenharmony_cistatic int x_e_getmbc(char *);
122c84f3f3cSopenharmony_ci
123c84f3f3cSopenharmony_ci/* +++ generic editing functions +++ */
124c84f3f3cSopenharmony_ci
125c84f3f3cSopenharmony_ci/*
126c84f3f3cSopenharmony_ci * read an edited command line
127c84f3f3cSopenharmony_ci */
128c84f3f3cSopenharmony_ciint
129c84f3f3cSopenharmony_cix_read(char *buf)
130c84f3f3cSopenharmony_ci{
131c84f3f3cSopenharmony_ci	int i;
132c84f3f3cSopenharmony_ci
133c84f3f3cSopenharmony_ci	x_mode(true);
134c84f3f3cSopenharmony_ci	modified = 1;
135c84f3f3cSopenharmony_ci	if (Flag(FEMACS) || Flag(FGMACS))
136c84f3f3cSopenharmony_ci		i = x_emacs(buf);
137c84f3f3cSopenharmony_ci#if !MKSH_S_NOVI
138c84f3f3cSopenharmony_ci	else if (Flag(FVI))
139c84f3f3cSopenharmony_ci		i = x_vi(buf);
140c84f3f3cSopenharmony_ci#endif
141c84f3f3cSopenharmony_ci	else
142c84f3f3cSopenharmony_ci		/* internal error */
143c84f3f3cSopenharmony_ci		i = -1;
144c84f3f3cSopenharmony_ci	editmode = 0;
145c84f3f3cSopenharmony_ci	x_mode(false);
146c84f3f3cSopenharmony_ci	return (i);
147c84f3f3cSopenharmony_ci}
148c84f3f3cSopenharmony_ci
149c84f3f3cSopenharmony_ci/* tty I/O */
150c84f3f3cSopenharmony_ci
151c84f3f3cSopenharmony_cistatic int
152c84f3f3cSopenharmony_cix_getc(void)
153c84f3f3cSopenharmony_ci{
154c84f3f3cSopenharmony_ci#ifdef __OS2__
155c84f3f3cSopenharmony_ci	return (_read_kbd(0, 1, 0));
156c84f3f3cSopenharmony_ci#else
157c84f3f3cSopenharmony_ci	char c;
158c84f3f3cSopenharmony_ci	ssize_t n;
159c84f3f3cSopenharmony_ci
160c84f3f3cSopenharmony_ci	while ((n = blocking_read(0, &c, 1)) < 0 && errno == EINTR)
161c84f3f3cSopenharmony_ci		if (trap) {
162c84f3f3cSopenharmony_ci			x_mode(false);
163c84f3f3cSopenharmony_ci			runtraps(0);
164c84f3f3cSopenharmony_ci#ifdef SIGWINCH
165c84f3f3cSopenharmony_ci			if (got_winch) {
166c84f3f3cSopenharmony_ci				change_winsz();
167c84f3f3cSopenharmony_ci				if (x_cols != xx_cols && editmode == 1) {
168c84f3f3cSopenharmony_ci					/* redraw line in Emacs mode */
169c84f3f3cSopenharmony_ci					xx_cols = x_cols;
170c84f3f3cSopenharmony_ci					x_init_prompt(false);
171c84f3f3cSopenharmony_ci					x_adjust();
172c84f3f3cSopenharmony_ci				}
173c84f3f3cSopenharmony_ci			}
174c84f3f3cSopenharmony_ci#endif
175c84f3f3cSopenharmony_ci			x_mode(true);
176c84f3f3cSopenharmony_ci		}
177c84f3f3cSopenharmony_ci	return ((n == 1) ? (int)(unsigned char)c : -1);
178c84f3f3cSopenharmony_ci#endif
179c84f3f3cSopenharmony_ci}
180c84f3f3cSopenharmony_ci
181c84f3f3cSopenharmony_cistatic void
182c84f3f3cSopenharmony_cix_putcf(int c)
183c84f3f3cSopenharmony_ci{
184c84f3f3cSopenharmony_ci	shf_putc_i(c, shl_out);
185c84f3f3cSopenharmony_ci}
186c84f3f3cSopenharmony_ci
187c84f3f3cSopenharmony_ci/*********************************
188c84f3f3cSopenharmony_ci * Misc common code for vi/emacs *
189c84f3f3cSopenharmony_ci *********************************/
190c84f3f3cSopenharmony_ci
191c84f3f3cSopenharmony_ci/*-
192c84f3f3cSopenharmony_ci * Handle the commenting/uncommenting of a line.
193c84f3f3cSopenharmony_ci * Returns:
194c84f3f3cSopenharmony_ci *	1 if a carriage return is indicated (comment added)
195c84f3f3cSopenharmony_ci *	0 if no return (comment removed)
196c84f3f3cSopenharmony_ci *	-1 if there is an error (not enough room for comment chars)
197c84f3f3cSopenharmony_ci * If successful, *lenp contains the new length. Note: cursor should be
198c84f3f3cSopenharmony_ci * moved to the start of the line after (un)commenting.
199c84f3f3cSopenharmony_ci */
200c84f3f3cSopenharmony_cistatic int
201c84f3f3cSopenharmony_cix_do_comment(char *buf, ssize_t bsize, ssize_t *lenp)
202c84f3f3cSopenharmony_ci{
203c84f3f3cSopenharmony_ci	ssize_t i, j, len = *lenp;
204c84f3f3cSopenharmony_ci
205c84f3f3cSopenharmony_ci	if (len == 0)
206c84f3f3cSopenharmony_ci		/* somewhat arbitrary - it's what AT&T ksh does */
207c84f3f3cSopenharmony_ci		return (1);
208c84f3f3cSopenharmony_ci
209c84f3f3cSopenharmony_ci	/* Already commented? */
210c84f3f3cSopenharmony_ci	if (buf[0] == '#') {
211c84f3f3cSopenharmony_ci		bool saw_nl = false;
212c84f3f3cSopenharmony_ci
213c84f3f3cSopenharmony_ci		for (j = 0, i = 1; i < len; i++) {
214c84f3f3cSopenharmony_ci			if (!saw_nl || buf[i] != '#')
215c84f3f3cSopenharmony_ci				buf[j++] = buf[i];
216c84f3f3cSopenharmony_ci			saw_nl = buf[i] == '\n';
217c84f3f3cSopenharmony_ci		}
218c84f3f3cSopenharmony_ci		*lenp = j;
219c84f3f3cSopenharmony_ci		return (0);
220c84f3f3cSopenharmony_ci	} else {
221c84f3f3cSopenharmony_ci		int n = 1;
222c84f3f3cSopenharmony_ci
223c84f3f3cSopenharmony_ci		/* See if there's room for the #s - 1 per \n */
224c84f3f3cSopenharmony_ci		for (i = 0; i < len; i++)
225c84f3f3cSopenharmony_ci			if (buf[i] == '\n')
226c84f3f3cSopenharmony_ci				n++;
227c84f3f3cSopenharmony_ci		if (len + n >= bsize)
228c84f3f3cSopenharmony_ci			return (-1);
229c84f3f3cSopenharmony_ci		/* Now add them... */
230c84f3f3cSopenharmony_ci		for (i = len, j = len + n; --i >= 0; ) {
231c84f3f3cSopenharmony_ci			if (buf[i] == '\n')
232c84f3f3cSopenharmony_ci				buf[--j] = '#';
233c84f3f3cSopenharmony_ci			buf[--j] = buf[i];
234c84f3f3cSopenharmony_ci		}
235c84f3f3cSopenharmony_ci		buf[0] = '#';
236c84f3f3cSopenharmony_ci		*lenp += n;
237c84f3f3cSopenharmony_ci		return (1);
238c84f3f3cSopenharmony_ci	}
239c84f3f3cSopenharmony_ci}
240c84f3f3cSopenharmony_ci
241c84f3f3cSopenharmony_ci/****************************************************
242c84f3f3cSopenharmony_ci * Common file/command completion code for vi/emacs *
243c84f3f3cSopenharmony_ci ****************************************************/
244c84f3f3cSopenharmony_ci
245c84f3f3cSopenharmony_cistatic void
246c84f3f3cSopenharmony_cix_print_expansions(int nwords, char * const *words, bool is_command)
247c84f3f3cSopenharmony_ci{
248c84f3f3cSopenharmony_ci	bool use_copy = false;
249c84f3f3cSopenharmony_ci	size_t prefix_len;
250c84f3f3cSopenharmony_ci	XPtrV l = { NULL, 0, 0 };
251c84f3f3cSopenharmony_ci	struct columnise_opts co;
252c84f3f3cSopenharmony_ci
253c84f3f3cSopenharmony_ci	/*
254c84f3f3cSopenharmony_ci	 * Check if all matches are in the same directory (in this
255c84f3f3cSopenharmony_ci	 * case, we want to omit the directory name)
256c84f3f3cSopenharmony_ci	 */
257c84f3f3cSopenharmony_ci	if (!is_command &&
258c84f3f3cSopenharmony_ci	    (prefix_len = x_longest_prefix(nwords, words)) > 0) {
259c84f3f3cSopenharmony_ci		int i;
260c84f3f3cSopenharmony_ci
261c84f3f3cSopenharmony_ci		/* Special case for 1 match (prefix is whole word) */
262c84f3f3cSopenharmony_ci		if (nwords == 1)
263c84f3f3cSopenharmony_ci			prefix_len = x_basename(words[0], NULL);
264c84f3f3cSopenharmony_ci		/* Any (non-trailing) slashes in non-common word suffixes? */
265c84f3f3cSopenharmony_ci		for (i = 0; i < nwords; i++)
266c84f3f3cSopenharmony_ci			if (x_basename(words[i] + prefix_len, NULL) >
267c84f3f3cSopenharmony_ci			    prefix_len)
268c84f3f3cSopenharmony_ci				break;
269c84f3f3cSopenharmony_ci		/* All in same directory? */
270c84f3f3cSopenharmony_ci		if (i == nwords) {
271c84f3f3cSopenharmony_ci			while (prefix_len > 0 &&
272c84f3f3cSopenharmony_ci			    !mksh_cdirsep(words[0][prefix_len - 1]))
273c84f3f3cSopenharmony_ci				prefix_len--;
274c84f3f3cSopenharmony_ci			use_copy = true;
275c84f3f3cSopenharmony_ci			XPinit(l, nwords + 1);
276c84f3f3cSopenharmony_ci			for (i = 0; i < nwords; i++)
277c84f3f3cSopenharmony_ci				XPput(l, words[i] + prefix_len);
278c84f3f3cSopenharmony_ci			XPput(l, NULL);
279c84f3f3cSopenharmony_ci		}
280c84f3f3cSopenharmony_ci	}
281c84f3f3cSopenharmony_ci	/*
282c84f3f3cSopenharmony_ci	 * Enumerate expansions
283c84f3f3cSopenharmony_ci	 */
284c84f3f3cSopenharmony_ci	x_putc('\r');
285c84f3f3cSopenharmony_ci	x_putc('\n');
286c84f3f3cSopenharmony_ci	co.shf = shl_out;
287c84f3f3cSopenharmony_ci	co.linesep = '\n';
288c84f3f3cSopenharmony_ci	co.do_last = true;
289c84f3f3cSopenharmony_ci	co.prefcol = false;
290c84f3f3cSopenharmony_ci	pr_list(&co, use_copy ? (char **)XPptrv(l) : words);
291c84f3f3cSopenharmony_ci
292c84f3f3cSopenharmony_ci	if (use_copy)
293c84f3f3cSopenharmony_ci		/* not x_free_words() */
294c84f3f3cSopenharmony_ci		XPfree(l);
295c84f3f3cSopenharmony_ci}
296c84f3f3cSopenharmony_ci
297c84f3f3cSopenharmony_ci/*
298c84f3f3cSopenharmony_ci * Convert backslash-escaped string to QCHAR-escaped
299c84f3f3cSopenharmony_ci * string useful for globbing; loses QCHAR unless it
300c84f3f3cSopenharmony_ci * can squeeze in, eg. by previous loss of backslash
301c84f3f3cSopenharmony_ci */
302c84f3f3cSopenharmony_cistatic void
303c84f3f3cSopenharmony_cix_glob_hlp_add_qchar(char *cp)
304c84f3f3cSopenharmony_ci{
305c84f3f3cSopenharmony_ci	char ch, *dp = cp;
306c84f3f3cSopenharmony_ci	bool escaping = false;
307c84f3f3cSopenharmony_ci
308c84f3f3cSopenharmony_ci	while ((ch = *cp++)) {
309c84f3f3cSopenharmony_ci		if (ch == '\\' && !escaping) {
310c84f3f3cSopenharmony_ci			escaping = true;
311c84f3f3cSopenharmony_ci			continue;
312c84f3f3cSopenharmony_ci		}
313c84f3f3cSopenharmony_ci		if (escaping || (ch == QCHAR && (cp - dp) > 1)) {
314c84f3f3cSopenharmony_ci			/*
315c84f3f3cSopenharmony_ci			 * empirically made list of chars to escape
316c84f3f3cSopenharmony_ci			 * for globbing as well as QCHAR itself
317c84f3f3cSopenharmony_ci			 */
318c84f3f3cSopenharmony_ci			switch (ord(ch)) {
319c84f3f3cSopenharmony_ci			case QCHAR:
320c84f3f3cSopenharmony_ci			case ORD('$'):
321c84f3f3cSopenharmony_ci			case ORD('*'):
322c84f3f3cSopenharmony_ci			case ORD('?'):
323c84f3f3cSopenharmony_ci			case ORD('['):
324c84f3f3cSopenharmony_ci			case ORD('\\'):
325c84f3f3cSopenharmony_ci			case ORD('`'):
326c84f3f3cSopenharmony_ci				*dp++ = QCHAR;
327c84f3f3cSopenharmony_ci				break;
328c84f3f3cSopenharmony_ci			}
329c84f3f3cSopenharmony_ci			escaping = false;
330c84f3f3cSopenharmony_ci		}
331c84f3f3cSopenharmony_ci		*dp++ = ch;
332c84f3f3cSopenharmony_ci	}
333c84f3f3cSopenharmony_ci	*dp = '\0';
334c84f3f3cSopenharmony_ci}
335c84f3f3cSopenharmony_ci
336c84f3f3cSopenharmony_ci/*
337c84f3f3cSopenharmony_ci * Run tilde expansion on argument string, return the result
338c84f3f3cSopenharmony_ci * after unescaping; if the flag is set, the original string
339c84f3f3cSopenharmony_ci * is freed if changed and assumed backslash-escaped, if not
340c84f3f3cSopenharmony_ci * it is assumed QCHAR-escaped
341c84f3f3cSopenharmony_ci */
342c84f3f3cSopenharmony_cistatic char *
343c84f3f3cSopenharmony_cix_glob_hlp_tilde_and_rem_qchar(char *s, bool magic_flag)
344c84f3f3cSopenharmony_ci{
345c84f3f3cSopenharmony_ci	char ch, *cp, *dp;
346c84f3f3cSopenharmony_ci
347c84f3f3cSopenharmony_ci	/*
348c84f3f3cSopenharmony_ci	 * On the string, check whether we have a tilde expansion,
349c84f3f3cSopenharmony_ci	 * and if so, discern "~foo/bar" and "~/baz" from "~blah";
350c84f3f3cSopenharmony_ci	 * if we have a directory part (the former), try to expand
351c84f3f3cSopenharmony_ci	 */
352c84f3f3cSopenharmony_ci	if (*s == '~' && (cp = /* not sdirsep */ strchr(s, '/')) != NULL) {
353c84f3f3cSopenharmony_ci		/* ok, so split into "~foo"/"bar" or "~"/"baz" */
354c84f3f3cSopenharmony_ci		*cp++ = 0;
355c84f3f3cSopenharmony_ci		/* try to expand the tilde */
356c84f3f3cSopenharmony_ci		if (!(dp = do_tilde(s + 1))) {
357c84f3f3cSopenharmony_ci			/* nope, revert damage */
358c84f3f3cSopenharmony_ci			*--cp = '/';
359c84f3f3cSopenharmony_ci		} else {
360c84f3f3cSopenharmony_ci			/* ok, expand and replace */
361c84f3f3cSopenharmony_ci			strpathx(cp, dp, cp, 1);
362c84f3f3cSopenharmony_ci			if (magic_flag)
363c84f3f3cSopenharmony_ci				afree(s, ATEMP);
364c84f3f3cSopenharmony_ci			s = cp;
365c84f3f3cSopenharmony_ci		}
366c84f3f3cSopenharmony_ci	}
367c84f3f3cSopenharmony_ci
368c84f3f3cSopenharmony_ci	/* ... convert it from backslash-escaped via QCHAR-escaped... */
369c84f3f3cSopenharmony_ci	if (magic_flag)
370c84f3f3cSopenharmony_ci		x_glob_hlp_add_qchar(s);
371c84f3f3cSopenharmony_ci	/* ... to unescaped, for comparison with the matches */
372c84f3f3cSopenharmony_ci	cp = dp = s;
373c84f3f3cSopenharmony_ci
374c84f3f3cSopenharmony_ci	while ((ch = *cp++)) {
375c84f3f3cSopenharmony_ci		if (ch == QCHAR && !(ch = *cp++))
376c84f3f3cSopenharmony_ci			break;
377c84f3f3cSopenharmony_ci		*dp++ = ch;
378c84f3f3cSopenharmony_ci	}
379c84f3f3cSopenharmony_ci	*dp = '\0';
380c84f3f3cSopenharmony_ci
381c84f3f3cSopenharmony_ci	return (s);
382c84f3f3cSopenharmony_ci}
383c84f3f3cSopenharmony_ci
384c84f3f3cSopenharmony_ci/**
385c84f3f3cSopenharmony_ci * Do file globbing:
386c84f3f3cSopenharmony_ci *	- does expansion, checks for no match, etc.
387c84f3f3cSopenharmony_ci *	- sets *wordsp to array of matching strings
388c84f3f3cSopenharmony_ci *	- returns number of matching strings
389c84f3f3cSopenharmony_ci */
390c84f3f3cSopenharmony_cistatic int
391c84f3f3cSopenharmony_cix_file_glob(int *flagsp, char *toglob, char ***wordsp)
392c84f3f3cSopenharmony_ci{
393c84f3f3cSopenharmony_ci	char **words, *cp;
394c84f3f3cSopenharmony_ci	int nwords;
395c84f3f3cSopenharmony_ci	XPtrV w;
396c84f3f3cSopenharmony_ci	struct source *s, *sold;
397c84f3f3cSopenharmony_ci
398c84f3f3cSopenharmony_ci	/* remove all escaping backward slashes */
399c84f3f3cSopenharmony_ci	x_glob_hlp_add_qchar(toglob);
400c84f3f3cSopenharmony_ci
401c84f3f3cSopenharmony_ci	/*
402c84f3f3cSopenharmony_ci	 * Convert "foo*" (toglob) to an array of strings (words)
403c84f3f3cSopenharmony_ci	 */
404c84f3f3cSopenharmony_ci	sold = source;
405c84f3f3cSopenharmony_ci	s = pushs(SWSTR, ATEMP);
406c84f3f3cSopenharmony_ci	s->start = s->str = toglob;
407c84f3f3cSopenharmony_ci	source = s;
408c84f3f3cSopenharmony_ci	if (yylex(ONEWORD | LQCHAR) != LWORD) {
409c84f3f3cSopenharmony_ci		source = sold;
410c84f3f3cSopenharmony_ci		internal_warningf(Tfg_badsubst);
411c84f3f3cSopenharmony_ci		return (0);
412c84f3f3cSopenharmony_ci	}
413c84f3f3cSopenharmony_ci	source = sold;
414c84f3f3cSopenharmony_ci	afree(s, ATEMP);
415c84f3f3cSopenharmony_ci	XPinit(w, 32);
416c84f3f3cSopenharmony_ci	cp = yylval.cp;
417c84f3f3cSopenharmony_ci	while (*cp == CHAR || *cp == QCHAR)
418c84f3f3cSopenharmony_ci		cp += 2;
419c84f3f3cSopenharmony_ci	nwords = DOGLOB | DOTILDE | DOMARKDIRS;
420c84f3f3cSopenharmony_ci	if (*cp != EOS) {
421c84f3f3cSopenharmony_ci		/* probably a $FOO expansion */
422c84f3f3cSopenharmony_ci		*flagsp |= XCF_IS_NOSPACE;
423c84f3f3cSopenharmony_ci		/* this always results in at most one match */
424c84f3f3cSopenharmony_ci		nwords = 0;
425c84f3f3cSopenharmony_ci	}
426c84f3f3cSopenharmony_ci	expand(yylval.cp, &w, nwords);
427c84f3f3cSopenharmony_ci	XPput(w, NULL);
428c84f3f3cSopenharmony_ci	words = (char **)XPclose(w);
429c84f3f3cSopenharmony_ci
430c84f3f3cSopenharmony_ci	for (nwords = 0; words[nwords]; nwords++)
431c84f3f3cSopenharmony_ci		;
432c84f3f3cSopenharmony_ci	if (nwords == 1) {
433c84f3f3cSopenharmony_ci		struct stat statb;
434c84f3f3cSopenharmony_ci
435c84f3f3cSopenharmony_ci		/* Expand any tilde and drop all QCHAR for comparison */
436c84f3f3cSopenharmony_ci		toglob = x_glob_hlp_tilde_and_rem_qchar(toglob, false);
437c84f3f3cSopenharmony_ci
438c84f3f3cSopenharmony_ci		/*
439c84f3f3cSopenharmony_ci		 * Check if globbing failed (returned glob pattern),
440c84f3f3cSopenharmony_ci		 * but be careful (e.g. toglob == "ab*" when the file
441c84f3f3cSopenharmony_ci		 * "ab*" exists is not an error).
442c84f3f3cSopenharmony_ci		 * Also, check for empty result - happens if we tried
443c84f3f3cSopenharmony_ci		 * to glob something which evaluated to an empty
444c84f3f3cSopenharmony_ci		 * string (e.g., "$FOO" when there is no FOO, etc).
445c84f3f3cSopenharmony_ci		 */
446c84f3f3cSopenharmony_ci		if ((strcmp(words[0], toglob) == 0 &&
447c84f3f3cSopenharmony_ci		    stat(words[0], &statb) < 0) ||
448c84f3f3cSopenharmony_ci		    words[0][0] == '\0') {
449c84f3f3cSopenharmony_ci			x_free_words(nwords, words);
450c84f3f3cSopenharmony_ci			words = NULL;
451c84f3f3cSopenharmony_ci			nwords = 0;
452c84f3f3cSopenharmony_ci		}
453c84f3f3cSopenharmony_ci	}
454c84f3f3cSopenharmony_ci
455c84f3f3cSopenharmony_ci	if ((*wordsp = nwords ? words : NULL) == NULL && words != NULL)
456c84f3f3cSopenharmony_ci		x_free_words(nwords, words);
457c84f3f3cSopenharmony_ci
458c84f3f3cSopenharmony_ci	return (nwords);
459c84f3f3cSopenharmony_ci}
460c84f3f3cSopenharmony_ci
461c84f3f3cSopenharmony_ci/* Data structure used in x_command_glob() */
462c84f3f3cSopenharmony_cistruct path_order_info {
463c84f3f3cSopenharmony_ci	char *word;
464c84f3f3cSopenharmony_ci	size_t base;
465c84f3f3cSopenharmony_ci	size_t path_order;
466c84f3f3cSopenharmony_ci};
467c84f3f3cSopenharmony_ci
468c84f3f3cSopenharmony_ci/* Compare routine used in x_command_glob() */
469c84f3f3cSopenharmony_cistatic int
470c84f3f3cSopenharmony_cipath_order_cmp(const void *aa, const void *bb)
471c84f3f3cSopenharmony_ci{
472c84f3f3cSopenharmony_ci	const struct path_order_info *a = (const struct path_order_info *)aa;
473c84f3f3cSopenharmony_ci	const struct path_order_info *b = (const struct path_order_info *)bb;
474c84f3f3cSopenharmony_ci	int t;
475c84f3f3cSopenharmony_ci
476c84f3f3cSopenharmony_ci	if ((t = ascstrcmp(a->word + a->base, b->word + b->base)))
477c84f3f3cSopenharmony_ci		return (t);
478c84f3f3cSopenharmony_ci	if (a->path_order > b->path_order)
479c84f3f3cSopenharmony_ci		return (1);
480c84f3f3cSopenharmony_ci	if (a->path_order < b->path_order)
481c84f3f3cSopenharmony_ci		return (-1);
482c84f3f3cSopenharmony_ci	return (0);
483c84f3f3cSopenharmony_ci}
484c84f3f3cSopenharmony_ci
485c84f3f3cSopenharmony_cistatic int
486c84f3f3cSopenharmony_cix_command_glob(int flags, char *toglob, char ***wordsp)
487c84f3f3cSopenharmony_ci{
488c84f3f3cSopenharmony_ci	char *pat, *fpath;
489c84f3f3cSopenharmony_ci	size_t nwords;
490c84f3f3cSopenharmony_ci	XPtrV w;
491c84f3f3cSopenharmony_ci	struct block *l;
492c84f3f3cSopenharmony_ci
493c84f3f3cSopenharmony_ci	/* Convert "foo*" (toglob) to a pattern for future use */
494c84f3f3cSopenharmony_ci	pat = evalstr(toglob, DOPAT | DOTILDE);
495c84f3f3cSopenharmony_ci
496c84f3f3cSopenharmony_ci	XPinit(w, 32);
497c84f3f3cSopenharmony_ci
498c84f3f3cSopenharmony_ci	glob_table(pat, &w, &keywords);
499c84f3f3cSopenharmony_ci	glob_table(pat, &w, &aliases);
500c84f3f3cSopenharmony_ci	glob_table(pat, &w, &builtins);
501c84f3f3cSopenharmony_ci	for (l = e->loc; l; l = l->next)
502c84f3f3cSopenharmony_ci		glob_table(pat, &w, &l->funs);
503c84f3f3cSopenharmony_ci
504c84f3f3cSopenharmony_ci	glob_path(flags, pat, &w, path);
505c84f3f3cSopenharmony_ci	if ((fpath = str_val(global(TFPATH))) != null)
506c84f3f3cSopenharmony_ci		glob_path(flags, pat, &w, fpath);
507c84f3f3cSopenharmony_ci
508c84f3f3cSopenharmony_ci	nwords = XPsize(w);
509c84f3f3cSopenharmony_ci
510c84f3f3cSopenharmony_ci	if (!nwords) {
511c84f3f3cSopenharmony_ci		*wordsp = NULL;
512c84f3f3cSopenharmony_ci		XPfree(w);
513c84f3f3cSopenharmony_ci		return (0);
514c84f3f3cSopenharmony_ci	}
515c84f3f3cSopenharmony_ci	/* Sort entries */
516c84f3f3cSopenharmony_ci	if (flags & XCF_FULLPATH) {
517c84f3f3cSopenharmony_ci		/* Sort by basename, then path order */
518c84f3f3cSopenharmony_ci		struct path_order_info *info, *last_info = NULL;
519c84f3f3cSopenharmony_ci		char **words = (char **)XPptrv(w);
520c84f3f3cSopenharmony_ci		size_t i, path_order = 0;
521c84f3f3cSopenharmony_ci
522c84f3f3cSopenharmony_ci		info = (struct path_order_info *)
523c84f3f3cSopenharmony_ci		    alloc2(nwords, sizeof(struct path_order_info), ATEMP);
524c84f3f3cSopenharmony_ci		for (i = 0; i < nwords; i++) {
525c84f3f3cSopenharmony_ci			info[i].word = words[i];
526c84f3f3cSopenharmony_ci			info[i].base = x_basename(words[i], NULL);
527c84f3f3cSopenharmony_ci			if (!last_info || info[i].base != last_info->base ||
528c84f3f3cSopenharmony_ci			    strncmp(words[i], last_info->word, info[i].base) != 0) {
529c84f3f3cSopenharmony_ci				last_info = &info[i];
530c84f3f3cSopenharmony_ci				path_order++;
531c84f3f3cSopenharmony_ci			}
532c84f3f3cSopenharmony_ci			info[i].path_order = path_order;
533c84f3f3cSopenharmony_ci		}
534c84f3f3cSopenharmony_ci		qsort(info, nwords, sizeof(struct path_order_info),
535c84f3f3cSopenharmony_ci		    path_order_cmp);
536c84f3f3cSopenharmony_ci		for (i = 0; i < nwords; i++)
537c84f3f3cSopenharmony_ci			words[i] = info[i].word;
538c84f3f3cSopenharmony_ci		afree(info, ATEMP);
539c84f3f3cSopenharmony_ci	} else {
540c84f3f3cSopenharmony_ci		/* Sort and remove duplicate entries */
541c84f3f3cSopenharmony_ci		char **words = (char **)XPptrv(w);
542c84f3f3cSopenharmony_ci		size_t i, j;
543c84f3f3cSopenharmony_ci
544c84f3f3cSopenharmony_ci		qsort(words, nwords, sizeof(void *), ascpstrcmp);
545c84f3f3cSopenharmony_ci		for (i = j = 0; i < nwords - 1; i++) {
546c84f3f3cSopenharmony_ci			if (strcmp(words[i], words[i + 1]))
547c84f3f3cSopenharmony_ci				words[j++] = words[i];
548c84f3f3cSopenharmony_ci			else
549c84f3f3cSopenharmony_ci				afree(words[i], ATEMP);
550c84f3f3cSopenharmony_ci		}
551c84f3f3cSopenharmony_ci		words[j++] = words[i];
552c84f3f3cSopenharmony_ci		w.len = nwords = j;
553c84f3f3cSopenharmony_ci	}
554c84f3f3cSopenharmony_ci
555c84f3f3cSopenharmony_ci	XPput(w, NULL);
556c84f3f3cSopenharmony_ci	*wordsp = (char **)XPclose(w);
557c84f3f3cSopenharmony_ci
558c84f3f3cSopenharmony_ci	return (nwords);
559c84f3f3cSopenharmony_ci}
560c84f3f3cSopenharmony_ci
561c84f3f3cSopenharmony_ci#define IS_WORDC(c)	(!ctype(c, C_EDNWC))
562c84f3f3cSopenharmony_ci
563c84f3f3cSopenharmony_cistatic int
564c84f3f3cSopenharmony_cix_locate_word(const char *buf, int buflen, int pos, int *startp,
565c84f3f3cSopenharmony_ci    bool *is_commandp)
566c84f3f3cSopenharmony_ci{
567c84f3f3cSopenharmony_ci	int start, end;
568c84f3f3cSopenharmony_ci
569c84f3f3cSopenharmony_ci	/* Bad call? Probably should report error */
570c84f3f3cSopenharmony_ci	if (pos < 0 || pos > buflen) {
571c84f3f3cSopenharmony_ci		*startp = pos;
572c84f3f3cSopenharmony_ci		*is_commandp = false;
573c84f3f3cSopenharmony_ci		return (0);
574c84f3f3cSopenharmony_ci	}
575c84f3f3cSopenharmony_ci	/* The case where pos == buflen happens to take care of itself... */
576c84f3f3cSopenharmony_ci
577c84f3f3cSopenharmony_ci	start = pos;
578c84f3f3cSopenharmony_ci	/*
579c84f3f3cSopenharmony_ci	 * Keep going backwards to start of word (has effect of allowing
580c84f3f3cSopenharmony_ci	 * one blank after the end of a word)
581c84f3f3cSopenharmony_ci	 */
582c84f3f3cSopenharmony_ci	for (; (start > 0 && IS_WORDC(buf[start - 1])) ||
583c84f3f3cSopenharmony_ci	    (start > 1 && buf[start - 2] == '\\'); start--)
584c84f3f3cSopenharmony_ci		;
585c84f3f3cSopenharmony_ci	/* Go forwards to end of word */
586c84f3f3cSopenharmony_ci	for (end = start; end < buflen && IS_WORDC(buf[end]); end++) {
587c84f3f3cSopenharmony_ci		if (buf[end] == '\\' && (end + 1) < buflen)
588c84f3f3cSopenharmony_ci			end++;
589c84f3f3cSopenharmony_ci	}
590c84f3f3cSopenharmony_ci
591c84f3f3cSopenharmony_ci	if (is_commandp) {
592c84f3f3cSopenharmony_ci		bool iscmd;
593c84f3f3cSopenharmony_ci		int p = start - 1;
594c84f3f3cSopenharmony_ci
595c84f3f3cSopenharmony_ci		/* Figure out if this is a command */
596c84f3f3cSopenharmony_ci		while (p >= 0 && ctype(buf[p], C_SPACE))
597c84f3f3cSopenharmony_ci			p--;
598c84f3f3cSopenharmony_ci		iscmd = p < 0 || ctype(buf[p], C_EDCMD);
599c84f3f3cSopenharmony_ci		if (iscmd) {
600c84f3f3cSopenharmony_ci			/*
601c84f3f3cSopenharmony_ci			 * If command has a /, path, etc. is not searched;
602c84f3f3cSopenharmony_ci			 * only current directory is searched which is just
603c84f3f3cSopenharmony_ci			 * like file globbing.
604c84f3f3cSopenharmony_ci			 */
605c84f3f3cSopenharmony_ci			for (p = start; p < end; p++)
606c84f3f3cSopenharmony_ci				if (mksh_cdirsep(buf[p]))
607c84f3f3cSopenharmony_ci					break;
608c84f3f3cSopenharmony_ci			iscmd = p == end;
609c84f3f3cSopenharmony_ci		}
610c84f3f3cSopenharmony_ci		*is_commandp = iscmd;
611c84f3f3cSopenharmony_ci	}
612c84f3f3cSopenharmony_ci	*startp = start;
613c84f3f3cSopenharmony_ci
614c84f3f3cSopenharmony_ci	return (end - start);
615c84f3f3cSopenharmony_ci}
616c84f3f3cSopenharmony_ci
617c84f3f3cSopenharmony_cistatic int
618c84f3f3cSopenharmony_cix_cf_glob(int *flagsp, const char *buf, int buflen, int pos, int *startp,
619c84f3f3cSopenharmony_ci    int *endp, char ***wordsp)
620c84f3f3cSopenharmony_ci{
621c84f3f3cSopenharmony_ci	int len, nwords = 0;
622c84f3f3cSopenharmony_ci	char **words = NULL;
623c84f3f3cSopenharmony_ci	bool is_command;
624c84f3f3cSopenharmony_ci
625c84f3f3cSopenharmony_ci	len = x_locate_word(buf, buflen, pos, startp, &is_command);
626c84f3f3cSopenharmony_ci	if (!((*flagsp) & XCF_COMMAND))
627c84f3f3cSopenharmony_ci		is_command = false;
628c84f3f3cSopenharmony_ci	/*
629c84f3f3cSopenharmony_ci	 * Don't do command globing on zero length strings - it takes too
630c84f3f3cSopenharmony_ci	 * long and isn't very useful. File globs are more likely to be
631c84f3f3cSopenharmony_ci	 * useful, so allow these.
632c84f3f3cSopenharmony_ci	 */
633c84f3f3cSopenharmony_ci	if (len == 0 && is_command)
634c84f3f3cSopenharmony_ci		return (0);
635c84f3f3cSopenharmony_ci
636c84f3f3cSopenharmony_ci	if (len >= 0) {
637c84f3f3cSopenharmony_ci		char *toglob, *s;
638c84f3f3cSopenharmony_ci
639c84f3f3cSopenharmony_ci		/*
640c84f3f3cSopenharmony_ci		 * Given a string, copy it and possibly add a '*' to the end.
641c84f3f3cSopenharmony_ci		 */
642c84f3f3cSopenharmony_ci
643c84f3f3cSopenharmony_ci		strndupx(toglob, buf + *startp, len + /* the '*' */ 1, ATEMP);
644c84f3f3cSopenharmony_ci		toglob[len] = '\0';
645c84f3f3cSopenharmony_ci
646c84f3f3cSopenharmony_ci		/*
647c84f3f3cSopenharmony_ci		 * If the pathname contains a wildcard (an unquoted '*',
648c84f3f3cSopenharmony_ci		 * '?', or '[') or an extglob, then it is globbed based
649c84f3f3cSopenharmony_ci		 * on that value (i.e., without the appended '*'). Same
650c84f3f3cSopenharmony_ci		 * for parameter substitutions (as in “cat $HOME/.ss↹”)
651c84f3f3cSopenharmony_ci		 * without appending a trailing space (LP: #710539), as
652c84f3f3cSopenharmony_ci		 * well as for “~foo” (but not “~foo/”).
653c84f3f3cSopenharmony_ci		 */
654c84f3f3cSopenharmony_ci		for (s = toglob; *s; s++) {
655c84f3f3cSopenharmony_ci			if (*s == '\\' && s[1])
656c84f3f3cSopenharmony_ci				s++;
657c84f3f3cSopenharmony_ci			else if (ctype(*s, C_QUEST | C_DOLAR) ||
658c84f3f3cSopenharmony_ci			    ord(*s) == ORD('*') || ord(*s) == ORD('[') ||
659c84f3f3cSopenharmony_ci			    /* ?() *() +() @() !() but two already checked */
660c84f3f3cSopenharmony_ci			    (ord(s[1]) == ORD('(' /*)*/) &&
661c84f3f3cSopenharmony_ci			    (ord(*s) == ORD('+') || ord(*s) == ORD('@') ||
662c84f3f3cSopenharmony_ci			    ord(*s) == ORD('!')))) {
663c84f3f3cSopenharmony_ci				/*
664c84f3f3cSopenharmony_ci				 * just expand based on the extglob
665c84f3f3cSopenharmony_ci				 * or parameter
666c84f3f3cSopenharmony_ci				 */
667c84f3f3cSopenharmony_ci				goto dont_add_glob;
668c84f3f3cSopenharmony_ci			}
669c84f3f3cSopenharmony_ci		}
670c84f3f3cSopenharmony_ci
671c84f3f3cSopenharmony_ci		if (*toglob == '~' && /* not vdirsep */ !vstrchr(toglob, '/')) {
672c84f3f3cSopenharmony_ci			/* neither for '~foo' (but '~foo/bar') */
673c84f3f3cSopenharmony_ci			*flagsp |= XCF_IS_NOSPACE;
674c84f3f3cSopenharmony_ci			goto dont_add_glob;
675c84f3f3cSopenharmony_ci		}
676c84f3f3cSopenharmony_ci
677c84f3f3cSopenharmony_ci		/* append a glob */
678c84f3f3cSopenharmony_ci		toglob[len] = '*';
679c84f3f3cSopenharmony_ci		toglob[len + 1] = '\0';
680c84f3f3cSopenharmony_ci dont_add_glob:
681c84f3f3cSopenharmony_ci		/*
682c84f3f3cSopenharmony_ci		 * Expand (glob) it now.
683c84f3f3cSopenharmony_ci		 */
684c84f3f3cSopenharmony_ci
685c84f3f3cSopenharmony_ci		nwords = is_command ?
686c84f3f3cSopenharmony_ci		    x_command_glob(*flagsp, toglob, &words) :
687c84f3f3cSopenharmony_ci		    x_file_glob(flagsp, toglob, &words);
688c84f3f3cSopenharmony_ci		afree(toglob, ATEMP);
689c84f3f3cSopenharmony_ci	}
690c84f3f3cSopenharmony_ci	if (nwords == 0) {
691c84f3f3cSopenharmony_ci		*wordsp = NULL;
692c84f3f3cSopenharmony_ci		return (0);
693c84f3f3cSopenharmony_ci	}
694c84f3f3cSopenharmony_ci	if (is_command)
695c84f3f3cSopenharmony_ci		*flagsp |= XCF_IS_COMMAND;
696c84f3f3cSopenharmony_ci	*wordsp = words;
697c84f3f3cSopenharmony_ci	*endp = *startp + len;
698c84f3f3cSopenharmony_ci
699c84f3f3cSopenharmony_ci	return (nwords);
700c84f3f3cSopenharmony_ci}
701c84f3f3cSopenharmony_ci
702c84f3f3cSopenharmony_ci/*
703c84f3f3cSopenharmony_ci * Find longest common prefix
704c84f3f3cSopenharmony_ci */
705c84f3f3cSopenharmony_cistatic size_t
706c84f3f3cSopenharmony_cix_longest_prefix(int nwords, char * const * words)
707c84f3f3cSopenharmony_ci{
708c84f3f3cSopenharmony_ci	int i;
709c84f3f3cSopenharmony_ci	size_t j, prefix_len;
710c84f3f3cSopenharmony_ci	char *p;
711c84f3f3cSopenharmony_ci
712c84f3f3cSopenharmony_ci	if (nwords <= 0)
713c84f3f3cSopenharmony_ci		return (0);
714c84f3f3cSopenharmony_ci
715c84f3f3cSopenharmony_ci	prefix_len = strlen(words[0]);
716c84f3f3cSopenharmony_ci	for (i = 1; i < nwords; i++)
717c84f3f3cSopenharmony_ci		for (j = 0, p = words[i]; j < prefix_len; j++)
718c84f3f3cSopenharmony_ci			if (p[j] != words[0][j]) {
719c84f3f3cSopenharmony_ci				prefix_len = j;
720c84f3f3cSopenharmony_ci				break;
721c84f3f3cSopenharmony_ci			}
722c84f3f3cSopenharmony_ci	/* false for nwords==1 as 0 = words[0][prefix_len] then */
723c84f3f3cSopenharmony_ci	if (UTFMODE && prefix_len && (rtt2asc(words[0][prefix_len]) & 0xC0) == 0x80)
724c84f3f3cSopenharmony_ci		while (prefix_len && (rtt2asc(words[0][prefix_len]) & 0xC0) != 0xC0)
725c84f3f3cSopenharmony_ci			--prefix_len;
726c84f3f3cSopenharmony_ci	return (prefix_len);
727c84f3f3cSopenharmony_ci}
728c84f3f3cSopenharmony_ci
729c84f3f3cSopenharmony_cistatic void
730c84f3f3cSopenharmony_cix_free_words(int nwords, char **words)
731c84f3f3cSopenharmony_ci{
732c84f3f3cSopenharmony_ci	while (nwords)
733c84f3f3cSopenharmony_ci		afree(words[--nwords], ATEMP);
734c84f3f3cSopenharmony_ci	afree(words, ATEMP);
735c84f3f3cSopenharmony_ci}
736c84f3f3cSopenharmony_ci
737c84f3f3cSopenharmony_ci/*-
738c84f3f3cSopenharmony_ci * Return the offset of the basename of string s (which ends at se - need not
739c84f3f3cSopenharmony_ci * be null terminated). Trailing slashes are ignored. If s is just a slash,
740c84f3f3cSopenharmony_ci * then the offset is 0 (actually, length - 1).
741c84f3f3cSopenharmony_ci *	s		Return
742c84f3f3cSopenharmony_ci *	/etc		1
743c84f3f3cSopenharmony_ci *	/etc/		1
744c84f3f3cSopenharmony_ci *	/etc//		1
745c84f3f3cSopenharmony_ci *	/etc/fo		5
746c84f3f3cSopenharmony_ci *	foo		0
747c84f3f3cSopenharmony_ci *	///		2
748c84f3f3cSopenharmony_ci *			0
749c84f3f3cSopenharmony_ci */
750c84f3f3cSopenharmony_cistatic size_t
751c84f3f3cSopenharmony_cix_basename(const char *s, const char *se)
752c84f3f3cSopenharmony_ci{
753c84f3f3cSopenharmony_ci	const char *p;
754c84f3f3cSopenharmony_ci
755c84f3f3cSopenharmony_ci	if (se == NULL)
756c84f3f3cSopenharmony_ci		se = strnul(s);
757c84f3f3cSopenharmony_ci	if (s == se)
758c84f3f3cSopenharmony_ci		return (0);
759c84f3f3cSopenharmony_ci
760c84f3f3cSopenharmony_ci	/* skip trailing directory separators */
761c84f3f3cSopenharmony_ci	p = se - 1;
762c84f3f3cSopenharmony_ci	while (p > s && mksh_cdirsep(*p))
763c84f3f3cSopenharmony_ci		--p;
764c84f3f3cSopenharmony_ci	/* drop last component */
765c84f3f3cSopenharmony_ci	while (p > s && !mksh_cdirsep(*p))
766c84f3f3cSopenharmony_ci		--p;
767c84f3f3cSopenharmony_ci	if (mksh_cdirsep(*p) && p + 1 < se)
768c84f3f3cSopenharmony_ci		++p;
769c84f3f3cSopenharmony_ci
770c84f3f3cSopenharmony_ci	return (p - s);
771c84f3f3cSopenharmony_ci}
772c84f3f3cSopenharmony_ci
773c84f3f3cSopenharmony_ci/*
774c84f3f3cSopenharmony_ci * Apply pattern matching to a table: all table entries that match a pattern
775c84f3f3cSopenharmony_ci * are added to wp.
776c84f3f3cSopenharmony_ci */
777c84f3f3cSopenharmony_cistatic void
778c84f3f3cSopenharmony_ciglob_table(const char *pat, XPtrV *wp, struct table *tp)
779c84f3f3cSopenharmony_ci{
780c84f3f3cSopenharmony_ci	struct tstate ts;
781c84f3f3cSopenharmony_ci	struct tbl *te;
782c84f3f3cSopenharmony_ci
783c84f3f3cSopenharmony_ci	ktwalk(&ts, tp);
784c84f3f3cSopenharmony_ci	while ((te = ktnext(&ts)))
785c84f3f3cSopenharmony_ci		if (gmatchx(te->name, pat, false)) {
786c84f3f3cSopenharmony_ci			char *cp;
787c84f3f3cSopenharmony_ci
788c84f3f3cSopenharmony_ci			strdupx(cp, te->name, ATEMP);
789c84f3f3cSopenharmony_ci			XPput(*wp, cp);
790c84f3f3cSopenharmony_ci		}
791c84f3f3cSopenharmony_ci}
792c84f3f3cSopenharmony_ci
793c84f3f3cSopenharmony_cistatic void
794c84f3f3cSopenharmony_ciglob_path(int flags, const char *pat, XPtrV *wp, const char *lpath)
795c84f3f3cSopenharmony_ci{
796c84f3f3cSopenharmony_ci	const char *sp = lpath, *p;
797c84f3f3cSopenharmony_ci	char *xp, **words;
798c84f3f3cSopenharmony_ci	size_t pathlen, patlen, oldsize, newsize, i, j;
799c84f3f3cSopenharmony_ci	XString xs;
800c84f3f3cSopenharmony_ci
801c84f3f3cSopenharmony_ci	patlen = strlen(pat);
802c84f3f3cSopenharmony_ci	checkoktoadd(patlen, 129 + X_EXTRA);
803c84f3f3cSopenharmony_ci	++patlen;
804c84f3f3cSopenharmony_ci	Xinit(xs, xp, patlen + 128, ATEMP);
805c84f3f3cSopenharmony_ci	while (sp) {
806c84f3f3cSopenharmony_ci		xp = Xstring(xs, xp);
807c84f3f3cSopenharmony_ci		if (!(p = cstrchr(sp, MKSH_PATHSEPC)))
808c84f3f3cSopenharmony_ci			p = strnul(sp);
809c84f3f3cSopenharmony_ci		pathlen = p - sp;
810c84f3f3cSopenharmony_ci		if (pathlen) {
811c84f3f3cSopenharmony_ci			/*
812c84f3f3cSopenharmony_ci			 * Copy sp into xp, stuffing any MAGIC characters
813c84f3f3cSopenharmony_ci			 * on the way
814c84f3f3cSopenharmony_ci			 */
815c84f3f3cSopenharmony_ci			const char *s = sp;
816c84f3f3cSopenharmony_ci
817c84f3f3cSopenharmony_ci			XcheckN(xs, xp, pathlen * 2);
818c84f3f3cSopenharmony_ci			while (s < p) {
819c84f3f3cSopenharmony_ci				if (ISMAGIC(*s))
820c84f3f3cSopenharmony_ci					*xp++ = MAGIC;
821c84f3f3cSopenharmony_ci				*xp++ = *s++;
822c84f3f3cSopenharmony_ci			}
823c84f3f3cSopenharmony_ci			*xp++ = '/';
824c84f3f3cSopenharmony_ci			pathlen++;
825c84f3f3cSopenharmony_ci		}
826c84f3f3cSopenharmony_ci		sp = p;
827c84f3f3cSopenharmony_ci		XcheckN(xs, xp, patlen);
828c84f3f3cSopenharmony_ci		memcpy(xp, pat, patlen);
829c84f3f3cSopenharmony_ci
830c84f3f3cSopenharmony_ci		oldsize = XPsize(*wp);
831c84f3f3cSopenharmony_ci		/* mark dirs */
832c84f3f3cSopenharmony_ci		glob_str(Xstring(xs, xp), wp, true);
833c84f3f3cSopenharmony_ci		newsize = XPsize(*wp);
834c84f3f3cSopenharmony_ci
835c84f3f3cSopenharmony_ci		/* Check that each match is executable... */
836c84f3f3cSopenharmony_ci		words = (char **)XPptrv(*wp);
837c84f3f3cSopenharmony_ci		for (i = j = oldsize; i < newsize; i++) {
838c84f3f3cSopenharmony_ci			if (ksh_access(words[i], X_OK) == 0) {
839c84f3f3cSopenharmony_ci				words[j] = words[i];
840c84f3f3cSopenharmony_ci				if (!(flags & XCF_FULLPATH))
841c84f3f3cSopenharmony_ci					memmove(words[j], words[j] + pathlen,
842c84f3f3cSopenharmony_ci					    strlen(words[j] + pathlen) + 1);
843c84f3f3cSopenharmony_ci				j++;
844c84f3f3cSopenharmony_ci			} else
845c84f3f3cSopenharmony_ci				afree(words[i], ATEMP);
846c84f3f3cSopenharmony_ci		}
847c84f3f3cSopenharmony_ci		wp->len = j;
848c84f3f3cSopenharmony_ci
849c84f3f3cSopenharmony_ci		if (!*sp++)
850c84f3f3cSopenharmony_ci			break;
851c84f3f3cSopenharmony_ci	}
852c84f3f3cSopenharmony_ci	Xfree(xs, xp);
853c84f3f3cSopenharmony_ci}
854c84f3f3cSopenharmony_ci
855c84f3f3cSopenharmony_ci/*
856c84f3f3cSopenharmony_ci * if argument string contains any special characters, they will
857c84f3f3cSopenharmony_ci * be escaped and the result will be put into edit buffer by
858c84f3f3cSopenharmony_ci * keybinding-specific function
859c84f3f3cSopenharmony_ci */
860c84f3f3cSopenharmony_cistatic int
861c84f3f3cSopenharmony_cix_escape(const char *s, size_t len, int (*putbuf_func)(const char *, size_t))
862c84f3f3cSopenharmony_ci{
863c84f3f3cSopenharmony_ci	size_t add = 0, wlen = len;
864c84f3f3cSopenharmony_ci	int rval = 0;
865c84f3f3cSopenharmony_ci
866c84f3f3cSopenharmony_ci	while (wlen - add > 0)
867c84f3f3cSopenharmony_ci		if (ctype(s[add], C_IFS | C_EDQ)) {
868c84f3f3cSopenharmony_ci			if (putbuf_func(s, add) != 0) {
869c84f3f3cSopenharmony_ci				rval = -1;
870c84f3f3cSopenharmony_ci				break;
871c84f3f3cSopenharmony_ci			}
872c84f3f3cSopenharmony_ci			putbuf_func(s[add] == '\n' ? "'" : "\\", 1);
873c84f3f3cSopenharmony_ci			putbuf_func(&s[add], 1);
874c84f3f3cSopenharmony_ci			if (s[add] == '\n')
875c84f3f3cSopenharmony_ci				putbuf_func("'", 1);
876c84f3f3cSopenharmony_ci
877c84f3f3cSopenharmony_ci			add++;
878c84f3f3cSopenharmony_ci			wlen -= add;
879c84f3f3cSopenharmony_ci			s += add;
880c84f3f3cSopenharmony_ci			add = 0;
881c84f3f3cSopenharmony_ci		} else
882c84f3f3cSopenharmony_ci			++add;
883c84f3f3cSopenharmony_ci	if (wlen > 0 && rval == 0)
884c84f3f3cSopenharmony_ci		rval = putbuf_func(s, wlen);
885c84f3f3cSopenharmony_ci
886c84f3f3cSopenharmony_ci	return (rval);
887c84f3f3cSopenharmony_ci}
888c84f3f3cSopenharmony_ci
889c84f3f3cSopenharmony_ci
890c84f3f3cSopenharmony_ci/* +++ emacs editing mode +++ */
891c84f3f3cSopenharmony_ci
892c84f3f3cSopenharmony_cistatic	Area	aedit;
893c84f3f3cSopenharmony_ci#define	AEDIT	&aedit		/* area for kill ring and macro defns */
894c84f3f3cSopenharmony_ci
895c84f3f3cSopenharmony_ci/* values returned by keyboard functions */
896c84f3f3cSopenharmony_ci#define	KSTD	0
897c84f3f3cSopenharmony_ci#define	KEOL	1		/* ^M, ^J */
898c84f3f3cSopenharmony_ci#define	KINTR	2		/* ^G, ^C */
899c84f3f3cSopenharmony_ci
900c84f3f3cSopenharmony_cistruct x_ftab {
901c84f3f3cSopenharmony_ci	int (*xf_func)(int c);
902c84f3f3cSopenharmony_ci	const char *xf_name;
903c84f3f3cSopenharmony_ci	short xf_flags;
904c84f3f3cSopenharmony_ci};
905c84f3f3cSopenharmony_ci
906c84f3f3cSopenharmony_cistruct x_defbindings {
907c84f3f3cSopenharmony_ci	unsigned char xdb_func;	/* XFUNC_* */
908c84f3f3cSopenharmony_ci	unsigned char xdb_tab;
909c84f3f3cSopenharmony_ci	unsigned char xdb_char;
910c84f3f3cSopenharmony_ci};
911c84f3f3cSopenharmony_ci
912c84f3f3cSopenharmony_ci#define XF_ARG		1	/* command takes number prefix */
913c84f3f3cSopenharmony_ci#define	XF_NOBIND	2	/* not allowed to bind to function */
914c84f3f3cSopenharmony_ci#define	XF_PREFIX	4	/* function sets prefix */
915c84f3f3cSopenharmony_ci
916c84f3f3cSopenharmony_ci#define X_NTABS		4			/* normal, meta1, meta2, pc */
917c84f3f3cSopenharmony_ci#define X_TABSZ		256			/* size of keydef tables etc */
918c84f3f3cSopenharmony_ci
919c84f3f3cSopenharmony_ci/*-
920c84f3f3cSopenharmony_ci * Arguments for do_complete()
921c84f3f3cSopenharmony_ci * 0 = enumerate	M-=	complete as much as possible and then list
922c84f3f3cSopenharmony_ci * 1 = complete		M-Esc
923c84f3f3cSopenharmony_ci * 2 = list		M-?
924c84f3f3cSopenharmony_ci */
925c84f3f3cSopenharmony_citypedef enum {
926c84f3f3cSopenharmony_ci	CT_LIST,	/* list the possible completions */
927c84f3f3cSopenharmony_ci	CT_COMPLETE,	/* complete to longest prefix */
928c84f3f3cSopenharmony_ci	CT_COMPLIST	/* complete and then list (if non-exact) */
929c84f3f3cSopenharmony_ci} Comp_type;
930c84f3f3cSopenharmony_ci
931c84f3f3cSopenharmony_ci/*
932c84f3f3cSopenharmony_ci * The following are used for my horizontal scrolling stuff
933c84f3f3cSopenharmony_ci */
934c84f3f3cSopenharmony_cistatic char *xbuf;		/* beg input buffer */
935c84f3f3cSopenharmony_cistatic char *xend;		/* end input buffer */
936c84f3f3cSopenharmony_cistatic char *xcp;		/* current position */
937c84f3f3cSopenharmony_cistatic char *xep;		/* current end */
938c84f3f3cSopenharmony_cistatic char *xbp;		/* start of visible portion of input buffer */
939c84f3f3cSopenharmony_cistatic char *xlp;		/* last char visible on screen */
940c84f3f3cSopenharmony_cistatic bool x_adj_ok;
941c84f3f3cSopenharmony_ci/*
942c84f3f3cSopenharmony_ci * we use x_adj_done so that functions can tell
943c84f3f3cSopenharmony_ci * whether x_adjust() has been called while they are active.
944c84f3f3cSopenharmony_ci */
945c84f3f3cSopenharmony_cistatic int x_adj_done;		/* is incremented by x_adjust() */
946c84f3f3cSopenharmony_ci
947c84f3f3cSopenharmony_cistatic int x_displen;
948c84f3f3cSopenharmony_cistatic int x_arg;		/* general purpose arg */
949c84f3f3cSopenharmony_cistatic bool x_arg_defaulted;	/* x_arg not explicitly set; defaulted to 1 */
950c84f3f3cSopenharmony_ci
951c84f3f3cSopenharmony_cistatic bool xlp_valid;		/* lastvis pointer was recalculated */
952c84f3f3cSopenharmony_ci
953c84f3f3cSopenharmony_cistatic char **x_histp;		/* history position */
954c84f3f3cSopenharmony_cistatic int x_nextcmd;		/* for newline-and-next */
955c84f3f3cSopenharmony_cistatic char **x_histncp;	/* saved x_histp for " */
956c84f3f3cSopenharmony_cistatic char **x_histmcp;	/* saved x_histp for " */
957c84f3f3cSopenharmony_cistatic char *xmp;		/* mark pointer */
958c84f3f3cSopenharmony_cistatic unsigned char x_last_command;
959c84f3f3cSopenharmony_cistatic unsigned char (*x_tab)[X_TABSZ];	/* key definition */
960c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
961c84f3f3cSopenharmony_cistatic char *(*x_atab)[X_TABSZ];	/* macro definitions */
962c84f3f3cSopenharmony_ci#endif
963c84f3f3cSopenharmony_cistatic unsigned char x_bound[(X_TABSZ * X_NTABS + 7) / 8];
964c84f3f3cSopenharmony_ci#define KILLSIZE	20
965c84f3f3cSopenharmony_cistatic char *killstack[KILLSIZE];
966c84f3f3cSopenharmony_cistatic int killsp, killtp;
967c84f3f3cSopenharmony_cistatic int x_curprefix;
968c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
969c84f3f3cSopenharmony_cistatic char *macroptr;		/* bind key macro active? */
970c84f3f3cSopenharmony_ci#endif
971c84f3f3cSopenharmony_ci#if !MKSH_S_NOVI
972c84f3f3cSopenharmony_cistatic int winwidth;		/* width of window */
973c84f3f3cSopenharmony_cistatic char *wbuf[2];		/* window buffers */
974c84f3f3cSopenharmony_cistatic int wbuf_len;		/* length of window buffers (x_cols - 3) */
975c84f3f3cSopenharmony_cistatic int win;			/* window buffer in use */
976c84f3f3cSopenharmony_cistatic char morec;		/* more character at right of window */
977c84f3f3cSopenharmony_cistatic int holdlen;		/* length of holdbuf */
978c84f3f3cSopenharmony_ci#endif
979c84f3f3cSopenharmony_cistatic int pwidth;		/* width of prompt */
980c84f3f3cSopenharmony_cistatic int prompt_trunc;	/* how much of prompt to truncate or -1 */
981c84f3f3cSopenharmony_cistatic int x_col;		/* current column on line */
982c84f3f3cSopenharmony_ci
983c84f3f3cSopenharmony_cistatic int x_ins(const char *);
984c84f3f3cSopenharmony_cistatic void x_delete(size_t, bool);
985c84f3f3cSopenharmony_cistatic size_t x_bword(void);
986c84f3f3cSopenharmony_cistatic size_t x_fword(bool);
987c84f3f3cSopenharmony_cistatic void x_goto(char *);
988c84f3f3cSopenharmony_cistatic char *x_bs0(char *, char *) MKSH_A_PURE;
989c84f3f3cSopenharmony_cistatic void x_bs3(char **);
990c84f3f3cSopenharmony_cistatic int x_size2(char *, char **);
991c84f3f3cSopenharmony_cistatic void x_zots(char *);
992c84f3f3cSopenharmony_cistatic void x_zotc3(char **);
993c84f3f3cSopenharmony_cistatic void x_vi_zotc(int);
994c84f3f3cSopenharmony_cistatic void x_load_hist(char **);
995c84f3f3cSopenharmony_cistatic int x_search(const char *, int, int);
996c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
997c84f3f3cSopenharmony_cistatic int x_search_dir(int);
998c84f3f3cSopenharmony_ci#endif
999c84f3f3cSopenharmony_cistatic int x_match(const char *, const char *);
1000c84f3f3cSopenharmony_cistatic void x_redraw(int);
1001c84f3f3cSopenharmony_cistatic void x_push(size_t);
1002c84f3f3cSopenharmony_cistatic void x_bind_showone(int, int);
1003c84f3f3cSopenharmony_cistatic void x_e_ungetc(int);
1004c84f3f3cSopenharmony_cistatic int x_e_getc(void);
1005c84f3f3cSopenharmony_cistatic void x_e_putc2(int);
1006c84f3f3cSopenharmony_cistatic void x_e_putc3(const char **);
1007c84f3f3cSopenharmony_cistatic void x_e_puts(const char *);
1008c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
1009c84f3f3cSopenharmony_cistatic int x_fold_case(int);
1010c84f3f3cSopenharmony_ci#endif
1011c84f3f3cSopenharmony_cistatic char *x_lastcp(void);
1012c84f3f3cSopenharmony_cistatic void x_lastpos(void);
1013c84f3f3cSopenharmony_cistatic void do_complete(int, Comp_type);
1014c84f3f3cSopenharmony_cistatic size_t x_nb2nc(size_t) MKSH_A_PURE;
1015c84f3f3cSopenharmony_ci
1016c84f3f3cSopenharmony_cistatic int unget_char = -1;
1017c84f3f3cSopenharmony_ci
1018c84f3f3cSopenharmony_cistatic int x_do_ins(const char *, size_t);
1019c84f3f3cSopenharmony_cistatic void bind_if_not_bound(int, int, int);
1020c84f3f3cSopenharmony_ci
1021c84f3f3cSopenharmony_cienum emacs_funcs {
1022c84f3f3cSopenharmony_ci#define EMACSFN_ENUMS
1023c84f3f3cSopenharmony_ci#include "emacsfn.h"
1024c84f3f3cSopenharmony_ci	XFUNC_MAX
1025c84f3f3cSopenharmony_ci};
1026c84f3f3cSopenharmony_ci
1027c84f3f3cSopenharmony_ci#define EMACSFN_DEFNS
1028c84f3f3cSopenharmony_ci#include "emacsfn.h"
1029c84f3f3cSopenharmony_ci
1030c84f3f3cSopenharmony_cistatic const struct x_ftab x_ftab[] = {
1031c84f3f3cSopenharmony_ci#define EMACSFN_ITEMS
1032c84f3f3cSopenharmony_ci#include "emacsfn.h"
1033c84f3f3cSopenharmony_ci};
1034c84f3f3cSopenharmony_ci
1035c84f3f3cSopenharmony_ci#ifndef MKSH_LESS_CMDLINE_EDITING
1036c84f3f3cSopenharmony_cistatic struct x_defbindings const x_defbindings[] = {
1037c84f3f3cSopenharmony_ci	{ XFUNC_del_back,		0,  CTRL_QM	},
1038c84f3f3cSopenharmony_ci	{ XFUNC_del_bword,		1,  CTRL_QM	},
1039c84f3f3cSopenharmony_ci	{ XFUNC_eot_del,		0,  CTRL_D	},
1040c84f3f3cSopenharmony_ci	{ XFUNC_del_back,		0,  CTRL_H	},
1041c84f3f3cSopenharmony_ci	{ XFUNC_del_bword,		1,  CTRL_H	},
1042c84f3f3cSopenharmony_ci	{ XFUNC_del_bword,		1,	'h'	},
1043c84f3f3cSopenharmony_ci	{ XFUNC_mv_bword,		1,	'b'	},
1044c84f3f3cSopenharmony_ci	{ XFUNC_mv_fword,		1,	'f'	},
1045c84f3f3cSopenharmony_ci	{ XFUNC_del_fword,		1,	'd'	},
1046c84f3f3cSopenharmony_ci	{ XFUNC_mv_back,		0,  CTRL_B	},
1047c84f3f3cSopenharmony_ci	{ XFUNC_mv_forw,		0,  CTRL_F	},
1048c84f3f3cSopenharmony_ci	{ XFUNC_search_char_forw,	0,  CTRL_BC	},
1049c84f3f3cSopenharmony_ci	{ XFUNC_search_char_back,	1,  CTRL_BC	},
1050c84f3f3cSopenharmony_ci	{ XFUNC_newline,		0,  CTRL_M	},
1051c84f3f3cSopenharmony_ci	{ XFUNC_newline,		0,  CTRL_J	},
1052c84f3f3cSopenharmony_ci	{ XFUNC_end_of_text,		0,  CTRL_US	},
1053c84f3f3cSopenharmony_ci	{ XFUNC_abort,			0,  CTRL_G	},
1054c84f3f3cSopenharmony_ci	{ XFUNC_prev_com,		0,  CTRL_P	},
1055c84f3f3cSopenharmony_ci	{ XFUNC_next_com,		0,  CTRL_N	},
1056c84f3f3cSopenharmony_ci	{ XFUNC_nl_next_com,		0,  CTRL_O	},
1057c84f3f3cSopenharmony_ci	{ XFUNC_search_hist,		0,  CTRL_R	},
1058c84f3f3cSopenharmony_ci	{ XFUNC_beg_hist,		1,	'<'	},
1059c84f3f3cSopenharmony_ci	{ XFUNC_end_hist,		1,	'>'	},
1060c84f3f3cSopenharmony_ci	{ XFUNC_goto_hist,		1,	'g'	},
1061c84f3f3cSopenharmony_ci	{ XFUNC_mv_end,			0,  CTRL_E	},
1062c84f3f3cSopenharmony_ci	{ XFUNC_mv_beg,			0,  CTRL_A	},
1063c84f3f3cSopenharmony_ci	{ XFUNC_draw_line,		0,  CTRL_L	},
1064c84f3f3cSopenharmony_ci	{ XFUNC_cls,			1,  CTRL_L	},
1065c84f3f3cSopenharmony_ci	{ XFUNC_meta1,			0,  CTRL_BO	},
1066c84f3f3cSopenharmony_ci	{ XFUNC_meta2,			0,  CTRL_X	},
1067c84f3f3cSopenharmony_ci	{ XFUNC_kill,			0,  CTRL_K	},
1068c84f3f3cSopenharmony_ci	{ XFUNC_yank,			0,  CTRL_Y	},
1069c84f3f3cSopenharmony_ci	{ XFUNC_meta_yank,		1,	'y'	},
1070c84f3f3cSopenharmony_ci	{ XFUNC_literal,		0,  CTRL_CA	},
1071c84f3f3cSopenharmony_ci	{ XFUNC_comment,		1,	'#'	},
1072c84f3f3cSopenharmony_ci	{ XFUNC_transpose,		0,  CTRL_T	},
1073c84f3f3cSopenharmony_ci	{ XFUNC_complete,		1,  CTRL_BO	},
1074c84f3f3cSopenharmony_ci	{ XFUNC_comp_list,		0,  CTRL_I	},
1075c84f3f3cSopenharmony_ci	{ XFUNC_comp_list,		1,	'='	},
1076c84f3f3cSopenharmony_ci	{ XFUNC_enumerate,		1,	'?'	},
1077c84f3f3cSopenharmony_ci	{ XFUNC_expand,			1,	'*'	},
1078c84f3f3cSopenharmony_ci	{ XFUNC_comp_file,		1,  CTRL_X	},
1079c84f3f3cSopenharmony_ci	{ XFUNC_comp_comm,		2,  CTRL_BO	},
1080c84f3f3cSopenharmony_ci	{ XFUNC_list_comm,		2,	'?'	},
1081c84f3f3cSopenharmony_ci	{ XFUNC_list_file,		2,  CTRL_Y	},
1082c84f3f3cSopenharmony_ci	{ XFUNC_set_mark,		1,	' '	},
1083c84f3f3cSopenharmony_ci	{ XFUNC_kill_region,		0,  CTRL_W	},
1084c84f3f3cSopenharmony_ci	{ XFUNC_xchg_point_mark,	2,  CTRL_X	},
1085c84f3f3cSopenharmony_ci	{ XFUNC_literal,		0,  CTRL_V	},
1086c84f3f3cSopenharmony_ci	{ XFUNC_version,		1,  CTRL_V	},
1087c84f3f3cSopenharmony_ci	{ XFUNC_prev_histword,		1,	'.'	},
1088c84f3f3cSopenharmony_ci	{ XFUNC_prev_histword,		1,	'_'	},
1089c84f3f3cSopenharmony_ci	{ XFUNC_set_arg,		1,	'0'	},
1090c84f3f3cSopenharmony_ci	{ XFUNC_set_arg,		1,	'1'	},
1091c84f3f3cSopenharmony_ci	{ XFUNC_set_arg,		1,	'2'	},
1092c84f3f3cSopenharmony_ci	{ XFUNC_set_arg,		1,	'3'	},
1093c84f3f3cSopenharmony_ci	{ XFUNC_set_arg,		1,	'4'	},
1094c84f3f3cSopenharmony_ci	{ XFUNC_set_arg,		1,	'5'	},
1095c84f3f3cSopenharmony_ci	{ XFUNC_set_arg,		1,	'6'	},
1096c84f3f3cSopenharmony_ci	{ XFUNC_set_arg,		1,	'7'	},
1097c84f3f3cSopenharmony_ci	{ XFUNC_set_arg,		1,	'8'	},
1098c84f3f3cSopenharmony_ci	{ XFUNC_set_arg,		1,	'9'	},
1099c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
1100c84f3f3cSopenharmony_ci	{ XFUNC_fold_upper,		1,	'U'	},
1101c84f3f3cSopenharmony_ci	{ XFUNC_fold_upper,		1,	'u'	},
1102c84f3f3cSopenharmony_ci	{ XFUNC_fold_lower,		1,	'L'	},
1103c84f3f3cSopenharmony_ci	{ XFUNC_fold_lower,		1,	'l'	},
1104c84f3f3cSopenharmony_ci	{ XFUNC_fold_capitalise,	1,	'C'	},
1105c84f3f3cSopenharmony_ci	{ XFUNC_fold_capitalise,	1,	'c'	},
1106c84f3f3cSopenharmony_ci#endif
1107c84f3f3cSopenharmony_ci	/*
1108c84f3f3cSopenharmony_ci	 * These for ANSI arrow keys: arguablely shouldn't be here by
1109c84f3f3cSopenharmony_ci	 * default, but its simpler/faster/smaller than using termcap
1110c84f3f3cSopenharmony_ci	 * entries.
1111c84f3f3cSopenharmony_ci	 */
1112c84f3f3cSopenharmony_ci	{ XFUNC_meta2,			1,	'['	},
1113c84f3f3cSopenharmony_ci	{ XFUNC_meta2,			1,	'O'	},
1114c84f3f3cSopenharmony_ci	{ XFUNC_prev_com,		2,	'A'	},
1115c84f3f3cSopenharmony_ci	{ XFUNC_next_com,		2,	'B'	},
1116c84f3f3cSopenharmony_ci	{ XFUNC_mv_forw,		2,	'C'	},
1117c84f3f3cSopenharmony_ci	{ XFUNC_mv_back,		2,	'D'	},
1118c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
1119c84f3f3cSopenharmony_ci	{ XFUNC_vt_hack,		2,	'1'	},
1120c84f3f3cSopenharmony_ci	{ XFUNC_mv_beg | 0x80,		2,	'7'	},
1121c84f3f3cSopenharmony_ci	{ XFUNC_mv_beg,			2,	'H'	},
1122c84f3f3cSopenharmony_ci	{ XFUNC_mv_end | 0x80,		2,	'4'	},
1123c84f3f3cSopenharmony_ci	{ XFUNC_mv_end | 0x80,		2,	'8'	},
1124c84f3f3cSopenharmony_ci	{ XFUNC_mv_end,			2,	'F'	},
1125c84f3f3cSopenharmony_ci	{ XFUNC_del_char | 0x80,	2,	'3'	},
1126c84f3f3cSopenharmony_ci	{ XFUNC_del_char,		2,	'P'	},
1127c84f3f3cSopenharmony_ci	{ XFUNC_search_hist_up | 0x80,	2,	'5'	},
1128c84f3f3cSopenharmony_ci	{ XFUNC_search_hist_dn | 0x80,	2,	'6'	},
1129c84f3f3cSopenharmony_ci#endif
1130c84f3f3cSopenharmony_ci	/* PC scancodes */
1131c84f3f3cSopenharmony_ci#if !defined(MKSH_SMALL) || defined(__OS2__)
1132c84f3f3cSopenharmony_ci	{ XFUNC_meta3,			0,	0	},
1133c84f3f3cSopenharmony_ci	{ XFUNC_mv_beg,			3,	71	},
1134c84f3f3cSopenharmony_ci	{ XFUNC_prev_com,		3,	72	},
1135c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
1136c84f3f3cSopenharmony_ci	{ XFUNC_search_hist_up,		3,	73	},
1137c84f3f3cSopenharmony_ci#endif
1138c84f3f3cSopenharmony_ci	{ XFUNC_mv_back,		3,	75	},
1139c84f3f3cSopenharmony_ci	{ XFUNC_mv_forw,		3,	77	},
1140c84f3f3cSopenharmony_ci	{ XFUNC_mv_end,			3,	79	},
1141c84f3f3cSopenharmony_ci	{ XFUNC_next_com,		3,	80	},
1142c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
1143c84f3f3cSopenharmony_ci	{ XFUNC_search_hist_dn,		3,	81	},
1144c84f3f3cSopenharmony_ci#endif
1145c84f3f3cSopenharmony_ci	{ XFUNC_del_char,		3,	83	},
1146c84f3f3cSopenharmony_ci#endif
1147c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
1148c84f3f3cSopenharmony_ci	/* more non-standard ones */
1149c84f3f3cSopenharmony_ci	{ XFUNC_eval_region,		1,  CTRL_E	},
1150c84f3f3cSopenharmony_ci	{ XFUNC_quote_region,		1,	'Q'	},
1151c84f3f3cSopenharmony_ci	{ XFUNC_edit_line,		2,	'e'	}
1152c84f3f3cSopenharmony_ci#endif
1153c84f3f3cSopenharmony_ci};
1154c84f3f3cSopenharmony_ci#else // MKSH_LESS_CMDLINE_EDITING
1155c84f3f3cSopenharmony_cistatic struct x_defbindings const x_defbindings[] = {
1156c84f3f3cSopenharmony_ci	{ XFUNC_abort,			0,  CTRL_G	},
1157c84f3f3cSopenharmony_ci	{ XFUNC_newline,		0,  CTRL_M	},
1158c84f3f3cSopenharmony_ci	{ XFUNC_newline,		0,  CTRL_J	},
1159c84f3f3cSopenharmony_ci	{ XFUNC_meta1,			0,  CTRL_BO	},
1160c84f3f3cSopenharmony_ci	{ XFUNC_meta2,			0,  CTRL_X	},
1161c84f3f3cSopenharmony_ci	{ XFUNC_meta2,			1,	'['	},
1162c84f3f3cSopenharmony_ci	{ XFUNC_meta2,			1,	'O'	},
1163c84f3f3cSopenharmony_ci	{ XFUNC_prev_com,		0,  CTRL_P	},
1164c84f3f3cSopenharmony_ci	{ XFUNC_prev_com,		2,	'A'	},
1165c84f3f3cSopenharmony_ci	{ XFUNC_next_com,		0,  CTRL_N	},
1166c84f3f3cSopenharmony_ci	{ XFUNC_next_com,		2,	'B'	},
1167c84f3f3cSopenharmony_ci	{ XFUNC_complete,		1,  CTRL_BO	},
1168c84f3f3cSopenharmony_ci	{ XFUNC_comp_list,		0,  CTRL_I	},
1169c84f3f3cSopenharmony_ci	{ XFUNC_comp_list,		1,	'='	},
1170c84f3f3cSopenharmony_ci	{ XFUNC_del_char | 0x80,		2,	'3'	},
1171c84f3f3cSopenharmony_ci	{ XFUNC_del_back,		0,  CTRL_QM	},
1172c84f3f3cSopenharmony_ci	{ XFUNC_del_back,		0,  CTRL_H	},
1173c84f3f3cSopenharmony_ci	{ XFUNC_mv_back,		0,  CTRL_B	},
1174c84f3f3cSopenharmony_ci	{ XFUNC_mv_back,		2,	'D'	},
1175c84f3f3cSopenharmony_ci	{ XFUNC_mv_forw,		0,  CTRL_F	},
1176c84f3f3cSopenharmony_ci	{ XFUNC_mv_forw,		2,	'C'	},
1177c84f3f3cSopenharmony_ci	{ XFUNC_mv_forw,		3,	77	}
1178c84f3f3cSopenharmony_ci};
1179c84f3f3cSopenharmony_ci#endif // MKSH_LESS_CMDLINE_EDITING
1180c84f3f3cSopenharmony_ci
1181c84f3f3cSopenharmony_ci
1182c84f3f3cSopenharmony_cistatic size_t
1183c84f3f3cSopenharmony_cix_nb2nc(size_t nb)
1184c84f3f3cSopenharmony_ci{
1185c84f3f3cSopenharmony_ci	char *cp;
1186c84f3f3cSopenharmony_ci	size_t nc = 0;
1187c84f3f3cSopenharmony_ci
1188c84f3f3cSopenharmony_ci	for (cp = xcp; cp < (xcp + nb); ++nc)
1189c84f3f3cSopenharmony_ci		cp += utf_ptradj(cp);
1190c84f3f3cSopenharmony_ci	return (nc);
1191c84f3f3cSopenharmony_ci}
1192c84f3f3cSopenharmony_ci
1193c84f3f3cSopenharmony_cistatic void
1194c84f3f3cSopenharmony_cix_modified(void)
1195c84f3f3cSopenharmony_ci{
1196c84f3f3cSopenharmony_ci	if (!modified) {
1197c84f3f3cSopenharmony_ci		x_histmcp = x_histp;
1198c84f3f3cSopenharmony_ci		x_histp = histptr + 1;
1199c84f3f3cSopenharmony_ci		modified = 1;
1200c84f3f3cSopenharmony_ci	}
1201c84f3f3cSopenharmony_ci}
1202c84f3f3cSopenharmony_ci
1203c84f3f3cSopenharmony_ci#ifdef MKSH_SMALL
1204c84f3f3cSopenharmony_ci#define XFUNC_VALUE(f) (f)
1205c84f3f3cSopenharmony_ci#else
1206c84f3f3cSopenharmony_ci#define XFUNC_VALUE(f) (f & 0x7F)
1207c84f3f3cSopenharmony_ci#endif
1208c84f3f3cSopenharmony_ci
1209c84f3f3cSopenharmony_cistatic int
1210c84f3f3cSopenharmony_cix_e_getmbc(char *sbuf)
1211c84f3f3cSopenharmony_ci{
1212c84f3f3cSopenharmony_ci	int c, pos = 0;
1213c84f3f3cSopenharmony_ci	unsigned char *buf = (unsigned char *)sbuf;
1214c84f3f3cSopenharmony_ci
1215c84f3f3cSopenharmony_ci	memset(buf, 0, 4);
1216c84f3f3cSopenharmony_ci	buf[pos++] = c = x_e_getc();
1217c84f3f3cSopenharmony_ci	if (c == -1)
1218c84f3f3cSopenharmony_ci		return (-1);
1219c84f3f3cSopenharmony_ci	if (UTFMODE) {
1220c84f3f3cSopenharmony_ci		if ((rtt2asc(buf[0]) >= (unsigned char)0xC2) &&
1221c84f3f3cSopenharmony_ci		    (rtt2asc(buf[0]) < (unsigned char)0xF0)) {
1222c84f3f3cSopenharmony_ci			c = x_e_getc();
1223c84f3f3cSopenharmony_ci			if (c == -1)
1224c84f3f3cSopenharmony_ci				return (-1);
1225c84f3f3cSopenharmony_ci			if ((rtt2asc(c) & 0xC0) != 0x80) {
1226c84f3f3cSopenharmony_ci				x_e_ungetc(c);
1227c84f3f3cSopenharmony_ci				return (1);
1228c84f3f3cSopenharmony_ci			}
1229c84f3f3cSopenharmony_ci			buf[pos++] = c;
1230c84f3f3cSopenharmony_ci		}
1231c84f3f3cSopenharmony_ci		if ((rtt2asc(buf[0]) >= (unsigned char)0xE0) &&
1232c84f3f3cSopenharmony_ci		    (rtt2asc(buf[0]) < (unsigned char)0xF0)) {
1233c84f3f3cSopenharmony_ci			/* XXX x_e_ungetc is one-octet only */
1234c84f3f3cSopenharmony_ci			buf[pos++] = c = x_e_getc();
1235c84f3f3cSopenharmony_ci			if (c == -1)
1236c84f3f3cSopenharmony_ci				return (-1);
1237c84f3f3cSopenharmony_ci		}
1238c84f3f3cSopenharmony_ci	}
1239c84f3f3cSopenharmony_ci	return (pos);
1240c84f3f3cSopenharmony_ci}
1241c84f3f3cSopenharmony_ci
1242c84f3f3cSopenharmony_ci/*
1243c84f3f3cSopenharmony_ci * minimum required space to work with on a line - if the prompt
1244c84f3f3cSopenharmony_ci * leaves less space than this on a line, the prompt is truncated
1245c84f3f3cSopenharmony_ci */
1246c84f3f3cSopenharmony_ci#define MIN_EDIT_SPACE	7
1247c84f3f3cSopenharmony_ci
1248c84f3f3cSopenharmony_cistatic void
1249c84f3f3cSopenharmony_cix_init_prompt(bool doprint)
1250c84f3f3cSopenharmony_ci{
1251c84f3f3cSopenharmony_ci	prompt_trunc = pprompt(prompt, doprint ? 0 : -1);
1252c84f3f3cSopenharmony_ci	pwidth = prompt_trunc % x_cols;
1253c84f3f3cSopenharmony_ci	prompt_trunc -= pwidth;
1254c84f3f3cSopenharmony_ci	if ((mksh_uari_t)pwidth > ((mksh_uari_t)x_cols - 3 - MIN_EDIT_SPACE)) {
1255c84f3f3cSopenharmony_ci		/* force newline after prompt */
1256c84f3f3cSopenharmony_ci		prompt_trunc = -1;
1257c84f3f3cSopenharmony_ci		pwidth = 0;
1258c84f3f3cSopenharmony_ci		if (doprint)
1259c84f3f3cSopenharmony_ci			x_e_putc2('\n');
1260c84f3f3cSopenharmony_ci	}
1261c84f3f3cSopenharmony_ci}
1262c84f3f3cSopenharmony_ci
1263c84f3f3cSopenharmony_cistatic int
1264c84f3f3cSopenharmony_cix_emacs(char *buf)
1265c84f3f3cSopenharmony_ci{
1266c84f3f3cSopenharmony_ci	int c, i;
1267c84f3f3cSopenharmony_ci	unsigned char f;
1268c84f3f3cSopenharmony_ci
1269c84f3f3cSopenharmony_ci	xbp = xbuf = buf;
1270c84f3f3cSopenharmony_ci	xend = buf + LINE;
1271c84f3f3cSopenharmony_ci	xlp = xcp = xep = buf;
1272c84f3f3cSopenharmony_ci	*xcp = 0;
1273c84f3f3cSopenharmony_ci	xlp_valid = true;
1274c84f3f3cSopenharmony_ci	xmp = NULL;
1275c84f3f3cSopenharmony_ci	x_curprefix = 0;
1276c84f3f3cSopenharmony_ci	x_histmcp = x_histp = histptr + 1;
1277c84f3f3cSopenharmony_ci	x_last_command = XFUNC_error;
1278c84f3f3cSopenharmony_ci
1279c84f3f3cSopenharmony_ci	x_init_prompt(true);
1280c84f3f3cSopenharmony_ci	x_displen = (xx_cols = x_cols) - 2 - (x_col = pwidth);
1281c84f3f3cSopenharmony_ci	x_adj_done = 0;
1282c84f3f3cSopenharmony_ci	x_adj_ok = true;
1283c84f3f3cSopenharmony_ci
1284c84f3f3cSopenharmony_ci	x_histncp = NULL;
1285c84f3f3cSopenharmony_ci	if (x_nextcmd >= 0) {
1286c84f3f3cSopenharmony_ci		int off = source->line - x_nextcmd;
1287c84f3f3cSopenharmony_ci		if (histptr - history >= off) {
1288c84f3f3cSopenharmony_ci			x_load_hist(histptr - off);
1289c84f3f3cSopenharmony_ci			x_histncp = x_histp;
1290c84f3f3cSopenharmony_ci		}
1291c84f3f3cSopenharmony_ci		x_nextcmd = -1;
1292c84f3f3cSopenharmony_ci	}
1293c84f3f3cSopenharmony_ci	editmode = 1;
1294c84f3f3cSopenharmony_ci	while (/* CONSTCOND */ 1) {
1295c84f3f3cSopenharmony_ci		x_flush();
1296c84f3f3cSopenharmony_ci		if ((c = x_e_getc()) < 0)
1297c84f3f3cSopenharmony_ci			return (0);
1298c84f3f3cSopenharmony_ci
1299c84f3f3cSopenharmony_ci		f = x_curprefix == -1 ? XFUNC_insert :
1300c84f3f3cSopenharmony_ci		    x_tab[x_curprefix][c];
1301c84f3f3cSopenharmony_ci		if (f & 0x80) {
1302c84f3f3cSopenharmony_ci			f &= 0x7F;
1303c84f3f3cSopenharmony_ci			if ((i = x_e_getc()) != '~')
1304c84f3f3cSopenharmony_ci				x_e_ungetc(i);
1305c84f3f3cSopenharmony_ci		}
1306c84f3f3cSopenharmony_ci
1307c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
1308c84f3f3cSopenharmony_ci		if (f & 0x80) {
1309c84f3f3cSopenharmony_ci			f &= 0x7F;
1310c84f3f3cSopenharmony_ci			if ((i = x_e_getc()) != '~')
1311c84f3f3cSopenharmony_ci				x_e_ungetc(i);
1312c84f3f3cSopenharmony_ci		}
1313c84f3f3cSopenharmony_ci
1314c84f3f3cSopenharmony_ci		/* avoid bind key macro recursion */
1315c84f3f3cSopenharmony_ci		if (macroptr && f == XFUNC_ins_string)
1316c84f3f3cSopenharmony_ci			f = XFUNC_insert;
1317c84f3f3cSopenharmony_ci#endif
1318c84f3f3cSopenharmony_ci
1319c84f3f3cSopenharmony_ci		if (!(x_ftab[f].xf_flags & XF_PREFIX) &&
1320c84f3f3cSopenharmony_ci		    x_last_command != XFUNC_set_arg) {
1321c84f3f3cSopenharmony_ci			x_arg = 1;
1322c84f3f3cSopenharmony_ci			x_arg_defaulted = true;
1323c84f3f3cSopenharmony_ci		}
1324c84f3f3cSopenharmony_ci		i = c | (x_curprefix << 8);
1325c84f3f3cSopenharmony_ci		x_curprefix = 0;
1326c84f3f3cSopenharmony_ci		switch ((*x_ftab[f].xf_func)(i)) {
1327c84f3f3cSopenharmony_ci		case KSTD:
1328c84f3f3cSopenharmony_ci			if (!(x_ftab[f].xf_flags & XF_PREFIX))
1329c84f3f3cSopenharmony_ci				x_last_command = f;
1330c84f3f3cSopenharmony_ci			break;
1331c84f3f3cSopenharmony_ci		case KEOL:
1332c84f3f3cSopenharmony_ci			i = xep - xbuf;
1333c84f3f3cSopenharmony_ci			return (i);
1334c84f3f3cSopenharmony_ci		case KINTR:
1335c84f3f3cSopenharmony_ci			/* special case for interrupt */
1336c84f3f3cSopenharmony_ci			x_intr(SIGINT, c);
1337c84f3f3cSopenharmony_ci		}
1338c84f3f3cSopenharmony_ci		/* ad-hoc hack for fixing the cursor position */
1339c84f3f3cSopenharmony_ci		x_goto(xcp);
1340c84f3f3cSopenharmony_ci	}
1341c84f3f3cSopenharmony_ci}
1342c84f3f3cSopenharmony_ci
1343c84f3f3cSopenharmony_cistatic int
1344c84f3f3cSopenharmony_cix_insert(int c)
1345c84f3f3cSopenharmony_ci{
1346c84f3f3cSopenharmony_ci	static int left, pos, save_arg;
1347c84f3f3cSopenharmony_ci	static char str[4];
1348c84f3f3cSopenharmony_ci
1349c84f3f3cSopenharmony_ci	/*
1350c84f3f3cSopenharmony_ci	 * Should allow tab and control chars.
1351c84f3f3cSopenharmony_ci	 */
1352c84f3f3cSopenharmony_ci	if (c == 0) {
1353c84f3f3cSopenharmony_ci invmbs:
1354c84f3f3cSopenharmony_ci		left = 0;
1355c84f3f3cSopenharmony_ci		x_e_putc2(KSH_BEL);
1356c84f3f3cSopenharmony_ci		return (KSTD);
1357c84f3f3cSopenharmony_ci	}
1358c84f3f3cSopenharmony_ci	if (UTFMODE) {
1359c84f3f3cSopenharmony_ci		if (((rtt2asc(c) & 0xC0) == 0x80) && left) {
1360c84f3f3cSopenharmony_ci			str[pos++] = c;
1361c84f3f3cSopenharmony_ci			if (!--left) {
1362c84f3f3cSopenharmony_ci				str[pos] = '\0';
1363c84f3f3cSopenharmony_ci				x_arg = save_arg;
1364c84f3f3cSopenharmony_ci				while (x_arg--)
1365c84f3f3cSopenharmony_ci					x_ins(str);
1366c84f3f3cSopenharmony_ci			}
1367c84f3f3cSopenharmony_ci			return (KSTD);
1368c84f3f3cSopenharmony_ci		}
1369c84f3f3cSopenharmony_ci		if (left) {
1370c84f3f3cSopenharmony_ci			if (x_curprefix == -1) {
1371c84f3f3cSopenharmony_ci				/* flush invalid multibyte */
1372c84f3f3cSopenharmony_ci				str[pos] = '\0';
1373c84f3f3cSopenharmony_ci				while (save_arg--)
1374c84f3f3cSopenharmony_ci					x_ins(str);
1375c84f3f3cSopenharmony_ci			}
1376c84f3f3cSopenharmony_ci		}
1377c84f3f3cSopenharmony_ci		if ((c >= 0xC2) && (c < 0xE0))
1378c84f3f3cSopenharmony_ci			left = 1;
1379c84f3f3cSopenharmony_ci		else if ((c >= 0xE0) && (c < 0xF0))
1380c84f3f3cSopenharmony_ci			left = 2;
1381c84f3f3cSopenharmony_ci		else if (c > 0x7F)
1382c84f3f3cSopenharmony_ci			goto invmbs;
1383c84f3f3cSopenharmony_ci		else
1384c84f3f3cSopenharmony_ci			left = 0;
1385c84f3f3cSopenharmony_ci		if (left) {
1386c84f3f3cSopenharmony_ci			save_arg = x_arg;
1387c84f3f3cSopenharmony_ci			pos = 1;
1388c84f3f3cSopenharmony_ci			str[0] = c;
1389c84f3f3cSopenharmony_ci			return (KSTD);
1390c84f3f3cSopenharmony_ci		}
1391c84f3f3cSopenharmony_ci	}
1392c84f3f3cSopenharmony_ci	left = 0;
1393c84f3f3cSopenharmony_ci	str[0] = c;
1394c84f3f3cSopenharmony_ci	str[1] = '\0';
1395c84f3f3cSopenharmony_ci	while (x_arg--)
1396c84f3f3cSopenharmony_ci		x_ins(str);
1397c84f3f3cSopenharmony_ci	return (KSTD);
1398c84f3f3cSopenharmony_ci}
1399c84f3f3cSopenharmony_ci
1400c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
1401c84f3f3cSopenharmony_cistatic int
1402c84f3f3cSopenharmony_cix_ins_string(int c)
1403c84f3f3cSopenharmony_ci{
1404c84f3f3cSopenharmony_ci	macroptr = x_atab[c >> 8][c & 255];
1405c84f3f3cSopenharmony_ci	/*
1406c84f3f3cSopenharmony_ci	 * we no longer need to bother checking if macroptr is
1407c84f3f3cSopenharmony_ci	 * not NULL but first char is NUL; x_e_getc() does it
1408c84f3f3cSopenharmony_ci	 */
1409c84f3f3cSopenharmony_ci	return (KSTD);
1410c84f3f3cSopenharmony_ci}
1411c84f3f3cSopenharmony_ci#endif
1412c84f3f3cSopenharmony_ci
1413c84f3f3cSopenharmony_cistatic int
1414c84f3f3cSopenharmony_cix_do_ins(const char *cp, size_t len)
1415c84f3f3cSopenharmony_ci{
1416c84f3f3cSopenharmony_ci	if (xep + len >= xend) {
1417c84f3f3cSopenharmony_ci		x_e_putc2(KSH_BEL);
1418c84f3f3cSopenharmony_ci		return (-1);
1419c84f3f3cSopenharmony_ci	}
1420c84f3f3cSopenharmony_ci	memmove(xcp + len, xcp, xep - xcp + 1);
1421c84f3f3cSopenharmony_ci	memmove(xcp, cp, len);
1422c84f3f3cSopenharmony_ci	xcp += len;
1423c84f3f3cSopenharmony_ci	xep += len;
1424c84f3f3cSopenharmony_ci	x_modified();
1425c84f3f3cSopenharmony_ci	return (0);
1426c84f3f3cSopenharmony_ci}
1427c84f3f3cSopenharmony_ci
1428c84f3f3cSopenharmony_cistatic int
1429c84f3f3cSopenharmony_cix_ins(const char *s)
1430c84f3f3cSopenharmony_ci{
1431c84f3f3cSopenharmony_ci	char *cp = xcp;
1432c84f3f3cSopenharmony_ci	int adj = x_adj_done;
1433c84f3f3cSopenharmony_ci
1434c84f3f3cSopenharmony_ci	if (x_do_ins(s, strlen(s)) < 0)
1435c84f3f3cSopenharmony_ci		return (-1);
1436c84f3f3cSopenharmony_ci	/*
1437c84f3f3cSopenharmony_ci	 * x_zots() may result in a call to x_adjust()
1438c84f3f3cSopenharmony_ci	 * we want xcp to reflect the new position.
1439c84f3f3cSopenharmony_ci	 */
1440c84f3f3cSopenharmony_ci	xlp_valid = false;
1441c84f3f3cSopenharmony_ci	x_lastcp();
1442c84f3f3cSopenharmony_ci	x_adj_ok = tobool(xcp >= xlp);
1443c84f3f3cSopenharmony_ci	x_zots(cp);
1444c84f3f3cSopenharmony_ci	if (adj == x_adj_done)
1445c84f3f3cSopenharmony_ci		/* x_adjust() has not been called */
1446c84f3f3cSopenharmony_ci		x_lastpos();
1447c84f3f3cSopenharmony_ci	x_adj_ok = true;
1448c84f3f3cSopenharmony_ci	return (0);
1449c84f3f3cSopenharmony_ci}
1450c84f3f3cSopenharmony_ci
1451c84f3f3cSopenharmony_cistatic int
1452c84f3f3cSopenharmony_cix_del_back(int c MKSH_A_UNUSED)
1453c84f3f3cSopenharmony_ci{
1454c84f3f3cSopenharmony_ci	ssize_t i = 0;
1455c84f3f3cSopenharmony_ci
1456c84f3f3cSopenharmony_ci	if (xcp == xbuf) {
1457c84f3f3cSopenharmony_ci		x_e_putc2(KSH_BEL);
1458c84f3f3cSopenharmony_ci		return (KSTD);
1459c84f3f3cSopenharmony_ci	}
1460c84f3f3cSopenharmony_ci	do {
1461c84f3f3cSopenharmony_ci		x_goto(xcp - 1);
1462c84f3f3cSopenharmony_ci	} while ((++i < x_arg) && (xcp != xbuf));
1463c84f3f3cSopenharmony_ci	x_delete(i, false);
1464c84f3f3cSopenharmony_ci	return (KSTD);
1465c84f3f3cSopenharmony_ci}
1466c84f3f3cSopenharmony_ci
1467c84f3f3cSopenharmony_cistatic int
1468c84f3f3cSopenharmony_cix_del_char(int c MKSH_A_UNUSED)
1469c84f3f3cSopenharmony_ci{
1470c84f3f3cSopenharmony_ci	char *cp, *cp2;
1471c84f3f3cSopenharmony_ci	size_t i = 0;
1472c84f3f3cSopenharmony_ci
1473c84f3f3cSopenharmony_ci	cp = xcp;
1474c84f3f3cSopenharmony_ci	while (i < (size_t)x_arg) {
1475c84f3f3cSopenharmony_ci		utf_ptradjx(cp, cp2);
1476c84f3f3cSopenharmony_ci		if (cp2 > xep)
1477c84f3f3cSopenharmony_ci			break;
1478c84f3f3cSopenharmony_ci		cp = cp2;
1479c84f3f3cSopenharmony_ci		i++;
1480c84f3f3cSopenharmony_ci	}
1481c84f3f3cSopenharmony_ci
1482c84f3f3cSopenharmony_ci	if (!i) {
1483c84f3f3cSopenharmony_ci		x_e_putc2(KSH_BEL);
1484c84f3f3cSopenharmony_ci		return (KSTD);
1485c84f3f3cSopenharmony_ci	}
1486c84f3f3cSopenharmony_ci	x_delete(i, false);
1487c84f3f3cSopenharmony_ci	return (KSTD);
1488c84f3f3cSopenharmony_ci}
1489c84f3f3cSopenharmony_ci
1490c84f3f3cSopenharmony_ci/* Delete nc chars to the right of the cursor (including cursor position) */
1491c84f3f3cSopenharmony_cistatic void
1492c84f3f3cSopenharmony_cix_delete(size_t nc, bool push)
1493c84f3f3cSopenharmony_ci{
1494c84f3f3cSopenharmony_ci	size_t i, nb, nw;
1495c84f3f3cSopenharmony_ci	char *cp;
1496c84f3f3cSopenharmony_ci
1497c84f3f3cSopenharmony_ci	if (nc == 0)
1498c84f3f3cSopenharmony_ci		return;
1499c84f3f3cSopenharmony_ci
1500c84f3f3cSopenharmony_ci	nw = 0;
1501c84f3f3cSopenharmony_ci	cp = xcp;
1502c84f3f3cSopenharmony_ci	for (i = 0; i < nc; ++i) {
1503c84f3f3cSopenharmony_ci		char *cp2;
1504c84f3f3cSopenharmony_ci		int j;
1505c84f3f3cSopenharmony_ci
1506c84f3f3cSopenharmony_ci		j = x_size2(cp, &cp2);
1507c84f3f3cSopenharmony_ci		if (cp2 > xep)
1508c84f3f3cSopenharmony_ci			break;
1509c84f3f3cSopenharmony_ci		cp = cp2;
1510c84f3f3cSopenharmony_ci		nw += j;
1511c84f3f3cSopenharmony_ci	}
1512c84f3f3cSopenharmony_ci	nb = cp - xcp;
1513c84f3f3cSopenharmony_ci	/* nc = i; */
1514c84f3f3cSopenharmony_ci
1515c84f3f3cSopenharmony_ci	if (xmp != NULL && xmp > xcp) {
1516c84f3f3cSopenharmony_ci		if (xcp + nb > xmp)
1517c84f3f3cSopenharmony_ci			xmp = xcp;
1518c84f3f3cSopenharmony_ci		else
1519c84f3f3cSopenharmony_ci			xmp -= nb;
1520c84f3f3cSopenharmony_ci	}
1521c84f3f3cSopenharmony_ci	/*
1522c84f3f3cSopenharmony_ci	 * This lets us yank a word we have deleted.
1523c84f3f3cSopenharmony_ci	 */
1524c84f3f3cSopenharmony_ci	if (push)
1525c84f3f3cSopenharmony_ci		x_push(nb);
1526c84f3f3cSopenharmony_ci
1527c84f3f3cSopenharmony_ci	xep -= nb;
1528c84f3f3cSopenharmony_ci	/* Copies the NUL */
1529c84f3f3cSopenharmony_ci	memmove(xcp, xcp + nb, xep - xcp + 1);
1530c84f3f3cSopenharmony_ci	/* don't redraw */
1531c84f3f3cSopenharmony_ci	x_adj_ok = false;
1532c84f3f3cSopenharmony_ci	xlp_valid = false;
1533c84f3f3cSopenharmony_ci	x_zots(xcp);
1534c84f3f3cSopenharmony_ci	/*
1535c84f3f3cSopenharmony_ci	 * if we are already filling the line,
1536c84f3f3cSopenharmony_ci	 * there is no need to ' ', '\b'.
1537c84f3f3cSopenharmony_ci	 * But if we must, make sure we do the minimum.
1538c84f3f3cSopenharmony_ci	 */
1539c84f3f3cSopenharmony_ci	if ((i = xx_cols - 2 - x_col) > 0 || xep - xlp == 0) {
1540c84f3f3cSopenharmony_ci		nw = i = (nw < i) ? nw : i;
1541c84f3f3cSopenharmony_ci		while (i--)
1542c84f3f3cSopenharmony_ci			x_e_putc2(' ');
1543c84f3f3cSopenharmony_ci		if (x_col == xx_cols - 2) {
1544c84f3f3cSopenharmony_ci			x_e_putc2((xep > xlp) ? '>' : (xbp > xbuf) ? '<' : ' ');
1545c84f3f3cSopenharmony_ci			++nw;
1546c84f3f3cSopenharmony_ci		}
1547c84f3f3cSopenharmony_ci		while (nw--)
1548c84f3f3cSopenharmony_ci			x_e_putc2('\b');
1549c84f3f3cSopenharmony_ci	}
1550c84f3f3cSopenharmony_ci	/*x_goto(xcp);*/
1551c84f3f3cSopenharmony_ci	x_adj_ok = true;
1552c84f3f3cSopenharmony_ci	xlp_valid = false;
1553c84f3f3cSopenharmony_ci	x_lastpos();
1554c84f3f3cSopenharmony_ci	x_modified();
1555c84f3f3cSopenharmony_ci	return;
1556c84f3f3cSopenharmony_ci}
1557c84f3f3cSopenharmony_ci
1558c84f3f3cSopenharmony_cistatic int
1559c84f3f3cSopenharmony_cix_del_bword(int c MKSH_A_UNUSED)
1560c84f3f3cSopenharmony_ci{
1561c84f3f3cSopenharmony_ci	x_delete(x_bword(), true);
1562c84f3f3cSopenharmony_ci	return (KSTD);
1563c84f3f3cSopenharmony_ci}
1564c84f3f3cSopenharmony_ci
1565c84f3f3cSopenharmony_cistatic int
1566c84f3f3cSopenharmony_cix_mv_bword(int c MKSH_A_UNUSED)
1567c84f3f3cSopenharmony_ci{
1568c84f3f3cSopenharmony_ci	x_bword();
1569c84f3f3cSopenharmony_ci	return (KSTD);
1570c84f3f3cSopenharmony_ci}
1571c84f3f3cSopenharmony_ci
1572c84f3f3cSopenharmony_cistatic int
1573c84f3f3cSopenharmony_cix_mv_fword(int c MKSH_A_UNUSED)
1574c84f3f3cSopenharmony_ci{
1575c84f3f3cSopenharmony_ci	x_fword(true);
1576c84f3f3cSopenharmony_ci	return (KSTD);
1577c84f3f3cSopenharmony_ci}
1578c84f3f3cSopenharmony_ci
1579c84f3f3cSopenharmony_cistatic int
1580c84f3f3cSopenharmony_cix_del_fword(int c MKSH_A_UNUSED)
1581c84f3f3cSopenharmony_ci{
1582c84f3f3cSopenharmony_ci	x_delete(x_fword(false), true);
1583c84f3f3cSopenharmony_ci	return (KSTD);
1584c84f3f3cSopenharmony_ci}
1585c84f3f3cSopenharmony_ci
1586c84f3f3cSopenharmony_cistatic size_t
1587c84f3f3cSopenharmony_cix_bword(void)
1588c84f3f3cSopenharmony_ci{
1589c84f3f3cSopenharmony_ci	size_t nb = 0;
1590c84f3f3cSopenharmony_ci	char *cp = xcp;
1591c84f3f3cSopenharmony_ci
1592c84f3f3cSopenharmony_ci	if (cp == xbuf) {
1593c84f3f3cSopenharmony_ci		x_e_putc2(KSH_BEL);
1594c84f3f3cSopenharmony_ci		return (0);
1595c84f3f3cSopenharmony_ci	}
1596c84f3f3cSopenharmony_ci	while (x_arg--) {
1597c84f3f3cSopenharmony_ci		while (cp != xbuf && ctype(cp[-1], C_MFS)) {
1598c84f3f3cSopenharmony_ci			cp--;
1599c84f3f3cSopenharmony_ci			nb++;
1600c84f3f3cSopenharmony_ci		}
1601c84f3f3cSopenharmony_ci		while (cp != xbuf && !ctype(cp[-1], C_MFS)) {
1602c84f3f3cSopenharmony_ci			cp--;
1603c84f3f3cSopenharmony_ci			nb++;
1604c84f3f3cSopenharmony_ci		}
1605c84f3f3cSopenharmony_ci	}
1606c84f3f3cSopenharmony_ci	x_goto(cp);
1607c84f3f3cSopenharmony_ci	return (x_nb2nc(nb));
1608c84f3f3cSopenharmony_ci}
1609c84f3f3cSopenharmony_ci
1610c84f3f3cSopenharmony_cistatic size_t
1611c84f3f3cSopenharmony_cix_fword(bool move)
1612c84f3f3cSopenharmony_ci{
1613c84f3f3cSopenharmony_ci	size_t nc;
1614c84f3f3cSopenharmony_ci	char *cp = xcp;
1615c84f3f3cSopenharmony_ci
1616c84f3f3cSopenharmony_ci	if (cp == xep) {
1617c84f3f3cSopenharmony_ci		x_e_putc2(KSH_BEL);
1618c84f3f3cSopenharmony_ci		return (0);
1619c84f3f3cSopenharmony_ci	}
1620c84f3f3cSopenharmony_ci	while (x_arg--) {
1621c84f3f3cSopenharmony_ci		while (cp != xep && ctype(*cp, C_MFS))
1622c84f3f3cSopenharmony_ci			cp++;
1623c84f3f3cSopenharmony_ci		while (cp != xep && !ctype(*cp, C_MFS))
1624c84f3f3cSopenharmony_ci			cp++;
1625c84f3f3cSopenharmony_ci	}
1626c84f3f3cSopenharmony_ci	nc = x_nb2nc(cp - xcp);
1627c84f3f3cSopenharmony_ci	if (move)
1628c84f3f3cSopenharmony_ci		x_goto(cp);
1629c84f3f3cSopenharmony_ci	return (nc);
1630c84f3f3cSopenharmony_ci}
1631c84f3f3cSopenharmony_ci
1632c84f3f3cSopenharmony_cistatic void
1633c84f3f3cSopenharmony_cix_goto(char *cp)
1634c84f3f3cSopenharmony_ci{
1635c84f3f3cSopenharmony_ci	cp = cp >= xep ? xep : x_bs0(cp, xbuf);
1636c84f3f3cSopenharmony_ci	if (cp < xbp || cp >= utf_skipcols(xbp, x_displen, NULL)) {
1637c84f3f3cSopenharmony_ci		/* we are heading off screen */
1638c84f3f3cSopenharmony_ci		xcp = cp;
1639c84f3f3cSopenharmony_ci		x_adjust();
1640c84f3f3cSopenharmony_ci	} else if (cp < xcp) {
1641c84f3f3cSopenharmony_ci		/* move back */
1642c84f3f3cSopenharmony_ci		while (cp < xcp)
1643c84f3f3cSopenharmony_ci			x_bs3(&xcp);
1644c84f3f3cSopenharmony_ci	} else if (cp > xcp) {
1645c84f3f3cSopenharmony_ci		/* move forward */
1646c84f3f3cSopenharmony_ci		while (cp > xcp)
1647c84f3f3cSopenharmony_ci			x_zotc3(&xcp);
1648c84f3f3cSopenharmony_ci	}
1649c84f3f3cSopenharmony_ci}
1650c84f3f3cSopenharmony_ci
1651c84f3f3cSopenharmony_cistatic char *
1652c84f3f3cSopenharmony_cix_bs0(char *cp, char *lower_bound)
1653c84f3f3cSopenharmony_ci{
1654c84f3f3cSopenharmony_ci	if (UTFMODE)
1655c84f3f3cSopenharmony_ci		while ((!lower_bound || (cp > lower_bound)) &&
1656c84f3f3cSopenharmony_ci		    ((rtt2asc(*cp) & 0xC0) == 0x80))
1657c84f3f3cSopenharmony_ci			--cp;
1658c84f3f3cSopenharmony_ci	return (cp);
1659c84f3f3cSopenharmony_ci}
1660c84f3f3cSopenharmony_ci
1661c84f3f3cSopenharmony_cistatic void
1662c84f3f3cSopenharmony_cix_bs3(char **p)
1663c84f3f3cSopenharmony_ci{
1664c84f3f3cSopenharmony_ci	int i;
1665c84f3f3cSopenharmony_ci
1666c84f3f3cSopenharmony_ci	*p = x_bs0((*p) - 1, NULL);
1667c84f3f3cSopenharmony_ci	i = x_size2(*p, NULL);
1668c84f3f3cSopenharmony_ci	while (i--)
1669c84f3f3cSopenharmony_ci		x_e_putc2('\b');
1670c84f3f3cSopenharmony_ci}
1671c84f3f3cSopenharmony_ci
1672c84f3f3cSopenharmony_cistatic int
1673c84f3f3cSopenharmony_cix_size2(char *cp, char **dcp)
1674c84f3f3cSopenharmony_ci{
1675c84f3f3cSopenharmony_ci	uint8_t c = *(unsigned char *)cp;
1676c84f3f3cSopenharmony_ci
1677c84f3f3cSopenharmony_ci	if (UTFMODE && (rtt2asc(c) > 0x7F))
1678c84f3f3cSopenharmony_ci		return (utf_widthadj(cp, (const char **)dcp));
1679c84f3f3cSopenharmony_ci	if (dcp)
1680c84f3f3cSopenharmony_ci		*dcp = cp + 1;
1681c84f3f3cSopenharmony_ci	if (c == '\t')
1682c84f3f3cSopenharmony_ci		/* Kludge, tabs are always four spaces. */
1683c84f3f3cSopenharmony_ci		return (4);
1684c84f3f3cSopenharmony_ci	if (ksh_isctrl(c))
1685c84f3f3cSopenharmony_ci		/* control unsigned char */
1686c84f3f3cSopenharmony_ci		return (2);
1687c84f3f3cSopenharmony_ci	return (1);
1688c84f3f3cSopenharmony_ci}
1689c84f3f3cSopenharmony_ci
1690c84f3f3cSopenharmony_cistatic void
1691c84f3f3cSopenharmony_cix_zots(char *str)
1692c84f3f3cSopenharmony_ci{
1693c84f3f3cSopenharmony_ci	int adj = x_adj_done;
1694c84f3f3cSopenharmony_ci
1695c84f3f3cSopenharmony_ci	x_lastcp();
1696c84f3f3cSopenharmony_ci	while (*str && str < xlp && x_col < xx_cols && adj == x_adj_done)
1697c84f3f3cSopenharmony_ci		x_zotc3(&str);
1698c84f3f3cSopenharmony_ci}
1699c84f3f3cSopenharmony_ci
1700c84f3f3cSopenharmony_cistatic void
1701c84f3f3cSopenharmony_cix_zotc3(char **cp)
1702c84f3f3cSopenharmony_ci{
1703c84f3f3cSopenharmony_ci	unsigned char c = **(unsigned char **)cp;
1704c84f3f3cSopenharmony_ci
1705c84f3f3cSopenharmony_ci	if (c == '\t') {
1706c84f3f3cSopenharmony_ci		/* Kludge, tabs are always four spaces. */
1707c84f3f3cSopenharmony_ci		x_e_puts(T4spaces);
1708c84f3f3cSopenharmony_ci		(*cp)++;
1709c84f3f3cSopenharmony_ci	} else if (ksh_isctrl(c)) {
1710c84f3f3cSopenharmony_ci		x_e_putc2('^');
1711c84f3f3cSopenharmony_ci		x_e_putc2(ksh_unctrl(c));
1712c84f3f3cSopenharmony_ci		(*cp)++;
1713c84f3f3cSopenharmony_ci	} else
1714c84f3f3cSopenharmony_ci		x_e_putc3((const char **)cp);
1715c84f3f3cSopenharmony_ci}
1716c84f3f3cSopenharmony_ci
1717c84f3f3cSopenharmony_cistatic int
1718c84f3f3cSopenharmony_cix_mv_back(int c MKSH_A_UNUSED)
1719c84f3f3cSopenharmony_ci{
1720c84f3f3cSopenharmony_ci	if (xcp == xbuf) {
1721c84f3f3cSopenharmony_ci		x_e_putc2(KSH_BEL);
1722c84f3f3cSopenharmony_ci		return (KSTD);
1723c84f3f3cSopenharmony_ci	}
1724c84f3f3cSopenharmony_ci	while (x_arg--) {
1725c84f3f3cSopenharmony_ci		x_goto(xcp - 1);
1726c84f3f3cSopenharmony_ci		if (xcp == xbuf)
1727c84f3f3cSopenharmony_ci			break;
1728c84f3f3cSopenharmony_ci	}
1729c84f3f3cSopenharmony_ci	return (KSTD);
1730c84f3f3cSopenharmony_ci}
1731c84f3f3cSopenharmony_ci
1732c84f3f3cSopenharmony_cistatic int
1733c84f3f3cSopenharmony_cix_mv_forw(int c MKSH_A_UNUSED)
1734c84f3f3cSopenharmony_ci{
1735c84f3f3cSopenharmony_ci	char *cp = xcp, *cp2;
1736c84f3f3cSopenharmony_ci
1737c84f3f3cSopenharmony_ci	if (xcp == xep) {
1738c84f3f3cSopenharmony_ci		x_e_putc2(KSH_BEL);
1739c84f3f3cSopenharmony_ci		return (KSTD);
1740c84f3f3cSopenharmony_ci	}
1741c84f3f3cSopenharmony_ci	while (x_arg--) {
1742c84f3f3cSopenharmony_ci		utf_ptradjx(cp, cp2);
1743c84f3f3cSopenharmony_ci		if (cp2 > xep)
1744c84f3f3cSopenharmony_ci			break;
1745c84f3f3cSopenharmony_ci		cp = cp2;
1746c84f3f3cSopenharmony_ci	}
1747c84f3f3cSopenharmony_ci	x_goto(cp);
1748c84f3f3cSopenharmony_ci	return (KSTD);
1749c84f3f3cSopenharmony_ci}
1750c84f3f3cSopenharmony_ci
1751c84f3f3cSopenharmony_cistatic int
1752c84f3f3cSopenharmony_cix_search_char_forw(int c MKSH_A_UNUSED)
1753c84f3f3cSopenharmony_ci{
1754c84f3f3cSopenharmony_ci	char *cp = xcp;
1755c84f3f3cSopenharmony_ci	char tmp[4];
1756c84f3f3cSopenharmony_ci
1757c84f3f3cSopenharmony_ci	*xep = '\0';
1758c84f3f3cSopenharmony_ci	if (x_e_getmbc(tmp) < 0) {
1759c84f3f3cSopenharmony_ci		x_e_putc2(KSH_BEL);
1760c84f3f3cSopenharmony_ci		return (KSTD);
1761c84f3f3cSopenharmony_ci	}
1762c84f3f3cSopenharmony_ci	while (x_arg--) {
1763c84f3f3cSopenharmony_ci		if ((cp = (cp == xep) ? NULL : strstr(cp + 1, tmp)) == NULL &&
1764c84f3f3cSopenharmony_ci		    (cp = strstr(xbuf, tmp)) == NULL) {
1765c84f3f3cSopenharmony_ci			x_e_putc2(KSH_BEL);
1766c84f3f3cSopenharmony_ci			return (KSTD);
1767c84f3f3cSopenharmony_ci		}
1768c84f3f3cSopenharmony_ci	}
1769c84f3f3cSopenharmony_ci	x_goto(cp);
1770c84f3f3cSopenharmony_ci	return (KSTD);
1771c84f3f3cSopenharmony_ci}
1772c84f3f3cSopenharmony_ci
1773c84f3f3cSopenharmony_cistatic int
1774c84f3f3cSopenharmony_cix_search_char_back(int c MKSH_A_UNUSED)
1775c84f3f3cSopenharmony_ci{
1776c84f3f3cSopenharmony_ci	char *cp = xcp, *p, tmp[4];
1777c84f3f3cSopenharmony_ci	bool b;
1778c84f3f3cSopenharmony_ci
1779c84f3f3cSopenharmony_ci	if (x_e_getmbc(tmp) < 0) {
1780c84f3f3cSopenharmony_ci		x_e_putc2(KSH_BEL);
1781c84f3f3cSopenharmony_ci		return (KSTD);
1782c84f3f3cSopenharmony_ci	}
1783c84f3f3cSopenharmony_ci	for (; x_arg--; cp = p)
1784c84f3f3cSopenharmony_ci		for (p = cp; ; ) {
1785c84f3f3cSopenharmony_ci			if (p-- == xbuf)
1786c84f3f3cSopenharmony_ci				p = xep;
1787c84f3f3cSopenharmony_ci			if (p == cp) {
1788c84f3f3cSopenharmony_ci				x_e_putc2(KSH_BEL);
1789c84f3f3cSopenharmony_ci				return (KSTD);
1790c84f3f3cSopenharmony_ci			}
1791c84f3f3cSopenharmony_ci			if ((tmp[1] && ((p+1) > xep)) ||
1792c84f3f3cSopenharmony_ci			    (tmp[2] && ((p+2) > xep)))
1793c84f3f3cSopenharmony_ci				continue;
1794c84f3f3cSopenharmony_ci			b = true;
1795c84f3f3cSopenharmony_ci			if (*p != tmp[0])
1796c84f3f3cSopenharmony_ci				b = false;
1797c84f3f3cSopenharmony_ci			if (b && tmp[1] && p[1] != tmp[1])
1798c84f3f3cSopenharmony_ci				b = false;
1799c84f3f3cSopenharmony_ci			if (b && tmp[2] && p[2] != tmp[2])
1800c84f3f3cSopenharmony_ci				b = false;
1801c84f3f3cSopenharmony_ci			if (b)
1802c84f3f3cSopenharmony_ci				break;
1803c84f3f3cSopenharmony_ci		}
1804c84f3f3cSopenharmony_ci	x_goto(cp);
1805c84f3f3cSopenharmony_ci	return (KSTD);
1806c84f3f3cSopenharmony_ci}
1807c84f3f3cSopenharmony_ci
1808c84f3f3cSopenharmony_cistatic int
1809c84f3f3cSopenharmony_cix_newline(int c MKSH_A_UNUSED)
1810c84f3f3cSopenharmony_ci{
1811c84f3f3cSopenharmony_ci	x_e_putc2('\r');
1812c84f3f3cSopenharmony_ci	x_e_putc2('\n');
1813c84f3f3cSopenharmony_ci	x_flush();
1814c84f3f3cSopenharmony_ci	*xep++ = '\n';
1815c84f3f3cSopenharmony_ci	return (KEOL);
1816c84f3f3cSopenharmony_ci}
1817c84f3f3cSopenharmony_ci
1818c84f3f3cSopenharmony_cistatic int
1819c84f3f3cSopenharmony_cix_end_of_text(int c MKSH_A_UNUSED)
1820c84f3f3cSopenharmony_ci{
1821c84f3f3cSopenharmony_ci	unsigned char tmp[1], *cp = tmp;
1822c84f3f3cSopenharmony_ci
1823c84f3f3cSopenharmony_ci	*tmp = isedchar(edchars.eof) ? (unsigned char)edchars.eof :
1824c84f3f3cSopenharmony_ci	    (unsigned char)CTRL_D;
1825c84f3f3cSopenharmony_ci	x_zotc3((char **)&cp);
1826c84f3f3cSopenharmony_ci	x_putc('\r');
1827c84f3f3cSopenharmony_ci	x_putc('\n');
1828c84f3f3cSopenharmony_ci	x_flush();
1829c84f3f3cSopenharmony_ci	return (KEOL);
1830c84f3f3cSopenharmony_ci}
1831c84f3f3cSopenharmony_ci
1832c84f3f3cSopenharmony_cistatic int
1833c84f3f3cSopenharmony_cix_beg_hist(int c MKSH_A_UNUSED)
1834c84f3f3cSopenharmony_ci{
1835c84f3f3cSopenharmony_ci	x_load_hist(history);
1836c84f3f3cSopenharmony_ci	return (KSTD);
1837c84f3f3cSopenharmony_ci}
1838c84f3f3cSopenharmony_ci
1839c84f3f3cSopenharmony_cistatic int
1840c84f3f3cSopenharmony_cix_end_hist(int c MKSH_A_UNUSED)
1841c84f3f3cSopenharmony_ci{
1842c84f3f3cSopenharmony_ci	x_load_hist(histptr);
1843c84f3f3cSopenharmony_ci	return (KSTD);
1844c84f3f3cSopenharmony_ci}
1845c84f3f3cSopenharmony_ci
1846c84f3f3cSopenharmony_cistatic int
1847c84f3f3cSopenharmony_cix_prev_com(int c MKSH_A_UNUSED)
1848c84f3f3cSopenharmony_ci{
1849c84f3f3cSopenharmony_ci	x_load_hist(x_histp - x_arg);
1850c84f3f3cSopenharmony_ci	return (KSTD);
1851c84f3f3cSopenharmony_ci}
1852c84f3f3cSopenharmony_ci
1853c84f3f3cSopenharmony_cistatic int
1854c84f3f3cSopenharmony_cix_next_com(int c MKSH_A_UNUSED)
1855c84f3f3cSopenharmony_ci{
1856c84f3f3cSopenharmony_ci	x_load_hist(x_histp + x_arg);
1857c84f3f3cSopenharmony_ci	return (KSTD);
1858c84f3f3cSopenharmony_ci}
1859c84f3f3cSopenharmony_ci
1860c84f3f3cSopenharmony_ci/*
1861c84f3f3cSopenharmony_ci * Goto a particular history number obtained from argument.
1862c84f3f3cSopenharmony_ci * If no argument is given history 1 is probably not what you
1863c84f3f3cSopenharmony_ci * want so we'll simply go to the oldest one.
1864c84f3f3cSopenharmony_ci */
1865c84f3f3cSopenharmony_cistatic int
1866c84f3f3cSopenharmony_cix_goto_hist(int c MKSH_A_UNUSED)
1867c84f3f3cSopenharmony_ci{
1868c84f3f3cSopenharmony_ci	if (x_arg_defaulted)
1869c84f3f3cSopenharmony_ci		x_load_hist(history);
1870c84f3f3cSopenharmony_ci	else
1871c84f3f3cSopenharmony_ci		x_load_hist(histptr + x_arg - source->line);
1872c84f3f3cSopenharmony_ci	return (KSTD);
1873c84f3f3cSopenharmony_ci}
1874c84f3f3cSopenharmony_ci
1875c84f3f3cSopenharmony_cistatic void
1876c84f3f3cSopenharmony_cix_load_hist(char **hp)
1877c84f3f3cSopenharmony_ci{
1878c84f3f3cSopenharmony_ci	char *sp = NULL;
1879c84f3f3cSopenharmony_ci
1880c84f3f3cSopenharmony_ci	if (hp == histptr + 1) {
1881c84f3f3cSopenharmony_ci		sp = holdbufp;
1882c84f3f3cSopenharmony_ci		modified = 0;
1883c84f3f3cSopenharmony_ci	} else if (hp < history || hp > histptr) {
1884c84f3f3cSopenharmony_ci		x_e_putc2(KSH_BEL);
1885c84f3f3cSopenharmony_ci		return;
1886c84f3f3cSopenharmony_ci	}
1887c84f3f3cSopenharmony_ci	if (sp == NULL)
1888c84f3f3cSopenharmony_ci		sp = *hp;
1889c84f3f3cSopenharmony_ci	x_histp = hp;
1890c84f3f3cSopenharmony_ci	if (modified)
1891c84f3f3cSopenharmony_ci		strlcpy(holdbufp, xbuf, LINE);
1892c84f3f3cSopenharmony_ci	strlcpy(xbuf, sp, xend - xbuf);
1893c84f3f3cSopenharmony_ci	xbp = xbuf;
1894c84f3f3cSopenharmony_ci	xep = xcp = strnul(xbuf);
1895c84f3f3cSopenharmony_ci	x_adjust();
1896c84f3f3cSopenharmony_ci	modified = 0;
1897c84f3f3cSopenharmony_ci}
1898c84f3f3cSopenharmony_ci
1899c84f3f3cSopenharmony_cistatic int
1900c84f3f3cSopenharmony_cix_nl_next_com(int c MKSH_A_UNUSED)
1901c84f3f3cSopenharmony_ci{
1902c84f3f3cSopenharmony_ci	if (!modified)
1903c84f3f3cSopenharmony_ci		x_histmcp = x_histp;
1904c84f3f3cSopenharmony_ci	if (!x_histncp || (x_histmcp != x_histncp && x_histmcp != histptr + 1))
1905c84f3f3cSopenharmony_ci		/* fresh start of ^O */
1906c84f3f3cSopenharmony_ci		x_histncp = x_histmcp;
1907c84f3f3cSopenharmony_ci	x_nextcmd = source->line - (histptr - x_histncp) + 1;
1908c84f3f3cSopenharmony_ci	return (x_newline('\n'));
1909c84f3f3cSopenharmony_ci}
1910c84f3f3cSopenharmony_ci
1911c84f3f3cSopenharmony_cistatic int
1912c84f3f3cSopenharmony_cix_eot_del(int c)
1913c84f3f3cSopenharmony_ci{
1914c84f3f3cSopenharmony_ci	if (xep == xbuf && x_arg_defaulted)
1915c84f3f3cSopenharmony_ci		return (x_end_of_text(c));
1916c84f3f3cSopenharmony_ci	else
1917c84f3f3cSopenharmony_ci		return (x_del_char(c));
1918c84f3f3cSopenharmony_ci}
1919c84f3f3cSopenharmony_ci
1920c84f3f3cSopenharmony_ci/* reverse incremental history search */
1921c84f3f3cSopenharmony_cistatic int
1922c84f3f3cSopenharmony_cix_search_hist(int c)
1923c84f3f3cSopenharmony_ci{
1924c84f3f3cSopenharmony_ci	int offset = -1;	/* offset of match in xbuf, else -1 */
1925c84f3f3cSopenharmony_ci	char pat[80 + 1];	/* pattern buffer */
1926c84f3f3cSopenharmony_ci	char *p = pat;
1927c84f3f3cSopenharmony_ci	unsigned char f;
1928c84f3f3cSopenharmony_ci
1929c84f3f3cSopenharmony_ci	*p = '\0';
1930c84f3f3cSopenharmony_ci	while (/* CONSTCOND */ 1) {
1931c84f3f3cSopenharmony_ci		if (offset < 0) {
1932c84f3f3cSopenharmony_ci			x_e_puts("\nI-search: ");
1933c84f3f3cSopenharmony_ci			x_e_puts(pat);
1934c84f3f3cSopenharmony_ci		}
1935c84f3f3cSopenharmony_ci		x_flush();
1936c84f3f3cSopenharmony_ci		if ((c = x_e_getc()) < 0)
1937c84f3f3cSopenharmony_ci			return (KSTD);
1938c84f3f3cSopenharmony_ci		f = x_tab[0][c];
1939c84f3f3cSopenharmony_ci		if (c == CTRL_BO) {
1940c84f3f3cSopenharmony_ci			if ((f & 0x7F) == XFUNC_meta1) {
1941c84f3f3cSopenharmony_ci				if ((c = x_e_getc()) < 0)
1942c84f3f3cSopenharmony_ci					return (KSTD);
1943c84f3f3cSopenharmony_ci				f = x_tab[1][c] & 0x7F;
1944c84f3f3cSopenharmony_ci				if (f == XFUNC_meta1 || f == XFUNC_meta2)
1945c84f3f3cSopenharmony_ci					x_meta1(CTRL_BO);
1946c84f3f3cSopenharmony_ci				x_e_ungetc(c);
1947c84f3f3cSopenharmony_ci			}
1948c84f3f3cSopenharmony_ci			break;
1949c84f3f3cSopenharmony_ci		}
1950c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
1951c84f3f3cSopenharmony_ci		if (f & 0x80) {
1952c84f3f3cSopenharmony_ci			f &= 0x7F;
1953c84f3f3cSopenharmony_ci			if ((c = x_e_getc()) != '~')
1954c84f3f3cSopenharmony_ci				x_e_ungetc(c);
1955c84f3f3cSopenharmony_ci		}
1956c84f3f3cSopenharmony_ci#endif
1957c84f3f3cSopenharmony_ci		if (f == XFUNC_search_hist)
1958c84f3f3cSopenharmony_ci			offset = x_search(pat, 0, offset);
1959c84f3f3cSopenharmony_ci		else if (f == XFUNC_del_back) {
1960c84f3f3cSopenharmony_ci			if (p == pat) {
1961c84f3f3cSopenharmony_ci				offset = -1;
1962c84f3f3cSopenharmony_ci				break;
1963c84f3f3cSopenharmony_ci			}
1964c84f3f3cSopenharmony_ci			if (p > pat) {
1965c84f3f3cSopenharmony_ci				p = x_bs0(p - 1, pat);
1966c84f3f3cSopenharmony_ci				*p = '\0';
1967c84f3f3cSopenharmony_ci			}
1968c84f3f3cSopenharmony_ci			if (p == pat)
1969c84f3f3cSopenharmony_ci				offset = -1;
1970c84f3f3cSopenharmony_ci			else
1971c84f3f3cSopenharmony_ci				offset = x_search(pat, 1, offset);
1972c84f3f3cSopenharmony_ci			continue;
1973c84f3f3cSopenharmony_ci		} else if (f == XFUNC_insert) {
1974c84f3f3cSopenharmony_ci			/* add char to pattern */
1975c84f3f3cSopenharmony_ci			/* overflow check... */
1976c84f3f3cSopenharmony_ci			if ((size_t)(p - pat) >= sizeof(pat) - 1) {
1977c84f3f3cSopenharmony_ci				x_e_putc2(KSH_BEL);
1978c84f3f3cSopenharmony_ci				continue;
1979c84f3f3cSopenharmony_ci			}
1980c84f3f3cSopenharmony_ci			*p++ = c, *p = '\0';
1981c84f3f3cSopenharmony_ci			if (offset >= 0) {
1982c84f3f3cSopenharmony_ci				/* already have partial match */
1983c84f3f3cSopenharmony_ci				offset = x_match(xbuf, pat);
1984c84f3f3cSopenharmony_ci				if (offset >= 0) {
1985c84f3f3cSopenharmony_ci					x_goto(xbuf + offset + (p - pat) -
1986c84f3f3cSopenharmony_ci					    (*pat == '^' ? 1 : 0));
1987c84f3f3cSopenharmony_ci					continue;
1988c84f3f3cSopenharmony_ci				}
1989c84f3f3cSopenharmony_ci			}
1990c84f3f3cSopenharmony_ci			offset = x_search(pat, 0, offset);
1991c84f3f3cSopenharmony_ci		} else if (f == XFUNC_abort) {
1992c84f3f3cSopenharmony_ci			if (offset >= 0)
1993c84f3f3cSopenharmony_ci				x_load_hist(histptr + 1);
1994c84f3f3cSopenharmony_ci			break;
1995c84f3f3cSopenharmony_ci		} else {
1996c84f3f3cSopenharmony_ci			/* other command */
1997c84f3f3cSopenharmony_ci			x_e_ungetc(c);
1998c84f3f3cSopenharmony_ci			break;
1999c84f3f3cSopenharmony_ci		}
2000c84f3f3cSopenharmony_ci	}
2001c84f3f3cSopenharmony_ci	if (offset < 0)
2002c84f3f3cSopenharmony_ci		x_redraw('\n');
2003c84f3f3cSopenharmony_ci	return (KSTD);
2004c84f3f3cSopenharmony_ci}
2005c84f3f3cSopenharmony_ci
2006c84f3f3cSopenharmony_ci/* search backward from current line */
2007c84f3f3cSopenharmony_cistatic int
2008c84f3f3cSopenharmony_cix_search(const char *pat, int sameline, int offset)
2009c84f3f3cSopenharmony_ci{
2010c84f3f3cSopenharmony_ci	char **hp;
2011c84f3f3cSopenharmony_ci	int i;
2012c84f3f3cSopenharmony_ci	size_t patlen = strlen(pat);
2013c84f3f3cSopenharmony_ci
2014c84f3f3cSopenharmony_ci	if (*pat == '^')
2015c84f3f3cSopenharmony_ci		--patlen;
2016c84f3f3cSopenharmony_ci	for (hp = x_histp - (sameline ? 0 : 1); hp >= history; --hp) {
2017c84f3f3cSopenharmony_ci		i = x_match(*hp, pat);
2018c84f3f3cSopenharmony_ci		if (i >= 0) {
2019c84f3f3cSopenharmony_ci			if (offset < 0)
2020c84f3f3cSopenharmony_ci				x_e_putc2('\n');
2021c84f3f3cSopenharmony_ci			x_load_hist(hp);
2022c84f3f3cSopenharmony_ci			x_goto(xbuf + i + patlen);
2023c84f3f3cSopenharmony_ci			return (i);
2024c84f3f3cSopenharmony_ci		}
2025c84f3f3cSopenharmony_ci	}
2026c84f3f3cSopenharmony_ci	x_e_putc2(KSH_BEL);
2027c84f3f3cSopenharmony_ci	x_histp = histptr;
2028c84f3f3cSopenharmony_ci	return (-1);
2029c84f3f3cSopenharmony_ci}
2030c84f3f3cSopenharmony_ci
2031c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
2032c84f3f3cSopenharmony_ci/* anchored search up from current line */
2033c84f3f3cSopenharmony_cistatic int
2034c84f3f3cSopenharmony_cix_search_hist_up(int c MKSH_A_UNUSED)
2035c84f3f3cSopenharmony_ci{
2036c84f3f3cSopenharmony_ci	return (x_search_dir(-1));
2037c84f3f3cSopenharmony_ci}
2038c84f3f3cSopenharmony_ci
2039c84f3f3cSopenharmony_ci/* anchored search down from current line */
2040c84f3f3cSopenharmony_cistatic int
2041c84f3f3cSopenharmony_cix_search_hist_dn(int c MKSH_A_UNUSED)
2042c84f3f3cSopenharmony_ci{
2043c84f3f3cSopenharmony_ci	return (x_search_dir(1));
2044c84f3f3cSopenharmony_ci}
2045c84f3f3cSopenharmony_ci
2046c84f3f3cSopenharmony_ci/* anchored search in the indicated direction */
2047c84f3f3cSopenharmony_cistatic int
2048c84f3f3cSopenharmony_cix_search_dir(int search_dir /* should've been bool */)
2049c84f3f3cSopenharmony_ci{
2050c84f3f3cSopenharmony_ci	char **hp = x_histp + search_dir;
2051c84f3f3cSopenharmony_ci	size_t curs = xcp - xbuf;
2052c84f3f3cSopenharmony_ci
2053c84f3f3cSopenharmony_ci	while (histptr >= hp && hp >= history) {
2054c84f3f3cSopenharmony_ci		if (strncmp(xbuf, *hp, curs) == 0) {
2055c84f3f3cSopenharmony_ci			x_load_hist(hp);
2056c84f3f3cSopenharmony_ci			x_goto(xbuf + curs);
2057c84f3f3cSopenharmony_ci			break;
2058c84f3f3cSopenharmony_ci		}
2059c84f3f3cSopenharmony_ci		hp += search_dir;
2060c84f3f3cSopenharmony_ci	}
2061c84f3f3cSopenharmony_ci	return (KSTD);
2062c84f3f3cSopenharmony_ci}
2063c84f3f3cSopenharmony_ci#endif
2064c84f3f3cSopenharmony_ci
2065c84f3f3cSopenharmony_ci/* return position of first match of pattern in string, else -1 */
2066c84f3f3cSopenharmony_cistatic int
2067c84f3f3cSopenharmony_cix_match(const char *str, const char *pat)
2068c84f3f3cSopenharmony_ci{
2069c84f3f3cSopenharmony_ci	if (*pat == '^') {
2070c84f3f3cSopenharmony_ci		return ((strncmp(str, pat + 1, strlen(pat + 1)) == 0) ? 0 : -1);
2071c84f3f3cSopenharmony_ci	} else {
2072c84f3f3cSopenharmony_ci		char *q = strstr(str, pat);
2073c84f3f3cSopenharmony_ci		return ((q == NULL) ? -1 : q - str);
2074c84f3f3cSopenharmony_ci	}
2075c84f3f3cSopenharmony_ci}
2076c84f3f3cSopenharmony_ci
2077c84f3f3cSopenharmony_cistatic int
2078c84f3f3cSopenharmony_cix_del_line(int c MKSH_A_UNUSED)
2079c84f3f3cSopenharmony_ci{
2080c84f3f3cSopenharmony_ci	*xep = 0;
2081c84f3f3cSopenharmony_ci	x_push(xep - (xcp = xbuf));
2082c84f3f3cSopenharmony_ci	xlp = xbp = xep = xbuf;
2083c84f3f3cSopenharmony_ci	xlp_valid = true;
2084c84f3f3cSopenharmony_ci	*xcp = 0;
2085c84f3f3cSopenharmony_ci	xmp = NULL;
2086c84f3f3cSopenharmony_ci	x_redraw('\r');
2087c84f3f3cSopenharmony_ci	x_modified();
2088c84f3f3cSopenharmony_ci	return (KSTD);
2089c84f3f3cSopenharmony_ci}
2090c84f3f3cSopenharmony_ci
2091c84f3f3cSopenharmony_cistatic int
2092c84f3f3cSopenharmony_cix_mv_end(int c MKSH_A_UNUSED)
2093c84f3f3cSopenharmony_ci{
2094c84f3f3cSopenharmony_ci	x_goto(xep);
2095c84f3f3cSopenharmony_ci	return (KSTD);
2096c84f3f3cSopenharmony_ci}
2097c84f3f3cSopenharmony_ci
2098c84f3f3cSopenharmony_cistatic int
2099c84f3f3cSopenharmony_cix_mv_beg(int c MKSH_A_UNUSED)
2100c84f3f3cSopenharmony_ci{
2101c84f3f3cSopenharmony_ci	x_goto(xbuf);
2102c84f3f3cSopenharmony_ci	return (KSTD);
2103c84f3f3cSopenharmony_ci}
2104c84f3f3cSopenharmony_ci
2105c84f3f3cSopenharmony_cistatic int
2106c84f3f3cSopenharmony_cix_draw_line(int c MKSH_A_UNUSED)
2107c84f3f3cSopenharmony_ci{
2108c84f3f3cSopenharmony_ci	x_redraw('\n');
2109c84f3f3cSopenharmony_ci	return (KSTD);
2110c84f3f3cSopenharmony_ci}
2111c84f3f3cSopenharmony_ci
2112c84f3f3cSopenharmony_cistatic int
2113c84f3f3cSopenharmony_cix_cls(int c MKSH_A_UNUSED)
2114c84f3f3cSopenharmony_ci{
2115c84f3f3cSopenharmony_ci	shf_puts(MKSH_CLS_STRING, shl_out);
2116c84f3f3cSopenharmony_ci	x_redraw(0);
2117c84f3f3cSopenharmony_ci	return (KSTD);
2118c84f3f3cSopenharmony_ci}
2119c84f3f3cSopenharmony_ci
2120c84f3f3cSopenharmony_ci/*
2121c84f3f3cSopenharmony_ci * clear line from x_col (current cursor position) to xx_cols - 2,
2122c84f3f3cSopenharmony_ci * then output lastch, then go back to x_col; if lastch is space,
2123c84f3f3cSopenharmony_ci * clear with termcap instead of spaces, or not if line_was_cleared;
2124c84f3f3cSopenharmony_ci * lastch MUST be an ASCII character with wcwidth(lastch) == 1
2125c84f3f3cSopenharmony_ci */
2126c84f3f3cSopenharmony_cistatic void
2127c84f3f3cSopenharmony_cix_clrtoeol(int lastch, bool line_was_cleared)
2128c84f3f3cSopenharmony_ci{
2129c84f3f3cSopenharmony_ci	int col;
2130c84f3f3cSopenharmony_ci
2131c84f3f3cSopenharmony_ci	if (lastch == ' ' && !line_was_cleared && x_term_mode == 1) {
2132c84f3f3cSopenharmony_ci		shf_puts(KSH_ESC_STRING "[K", shl_out);
2133c84f3f3cSopenharmony_ci		line_was_cleared = true;
2134c84f3f3cSopenharmony_ci	}
2135c84f3f3cSopenharmony_ci	if (lastch == ' ' && line_was_cleared)
2136c84f3f3cSopenharmony_ci		return;
2137c84f3f3cSopenharmony_ci
2138c84f3f3cSopenharmony_ci	col = x_col;
2139c84f3f3cSopenharmony_ci	while (col < (xx_cols - 2)) {
2140c84f3f3cSopenharmony_ci		x_putc(' ');
2141c84f3f3cSopenharmony_ci		++col;
2142c84f3f3cSopenharmony_ci	}
2143c84f3f3cSopenharmony_ci	x_putc(lastch);
2144c84f3f3cSopenharmony_ci	++col;
2145c84f3f3cSopenharmony_ci	while (col > x_col) {
2146c84f3f3cSopenharmony_ci		x_putc('\b');
2147c84f3f3cSopenharmony_ci		--col;
2148c84f3f3cSopenharmony_ci	}
2149c84f3f3cSopenharmony_ci}
2150c84f3f3cSopenharmony_ci
2151c84f3f3cSopenharmony_ci/* output the prompt, assuming a line has just been started */
2152c84f3f3cSopenharmony_cistatic void
2153c84f3f3cSopenharmony_cix_pprompt(void)
2154c84f3f3cSopenharmony_ci{
2155c84f3f3cSopenharmony_ci	if (prompt_trunc != -1)
2156c84f3f3cSopenharmony_ci		pprompt(prompt, prompt_trunc);
2157c84f3f3cSopenharmony_ci	x_col = pwidth;
2158c84f3f3cSopenharmony_ci}
2159c84f3f3cSopenharmony_ci
2160c84f3f3cSopenharmony_ci/* output CR, then redraw the line, clearing to EOL if needed (cr ≠ 0, LF) */
2161c84f3f3cSopenharmony_cistatic void
2162c84f3f3cSopenharmony_cix_redraw(int cr)
2163c84f3f3cSopenharmony_ci{
2164c84f3f3cSopenharmony_ci	int lch;
2165c84f3f3cSopenharmony_ci
2166c84f3f3cSopenharmony_ci	x_adj_ok = false;
2167c84f3f3cSopenharmony_ci	/* clear the line */
2168c84f3f3cSopenharmony_ci	x_e_putc2(cr ? cr : '\r');
2169c84f3f3cSopenharmony_ci	x_flush();
2170c84f3f3cSopenharmony_ci	/* display the prompt */
2171c84f3f3cSopenharmony_ci	if (xbp == xbuf)
2172c84f3f3cSopenharmony_ci		x_pprompt();
2173c84f3f3cSopenharmony_ci	x_displen = xx_cols - 2 - x_col;
2174c84f3f3cSopenharmony_ci	/* display the line content */
2175c84f3f3cSopenharmony_ci	xlp_valid = false;
2176c84f3f3cSopenharmony_ci	x_zots(xbp);
2177c84f3f3cSopenharmony_ci	/* check whether there is more off-screen */
2178c84f3f3cSopenharmony_ci	lch = xep > xlp ? (xbp > xbuf ? '*' : '>') : (xbp > xbuf) ? '<' : ' ';
2179c84f3f3cSopenharmony_ci	/* clear the rest of the line */
2180c84f3f3cSopenharmony_ci	x_clrtoeol(lch, !cr || cr == '\n');
2181c84f3f3cSopenharmony_ci	/* go back to actual cursor position */
2182c84f3f3cSopenharmony_ci	x_lastpos();
2183c84f3f3cSopenharmony_ci	x_adj_ok = true;
2184c84f3f3cSopenharmony_ci}
2185c84f3f3cSopenharmony_ci
2186c84f3f3cSopenharmony_cistatic int
2187c84f3f3cSopenharmony_cix_transpose(int c MKSH_A_UNUSED)
2188c84f3f3cSopenharmony_ci{
2189c84f3f3cSopenharmony_ci	unsigned int tmpa, tmpb;
2190c84f3f3cSopenharmony_ci
2191c84f3f3cSopenharmony_ci	/*-
2192c84f3f3cSopenharmony_ci	 * What transpose is meant to do seems to be up for debate. This
2193c84f3f3cSopenharmony_ci	 * is a general summary of the options; the text is abcd with the
2194c84f3f3cSopenharmony_ci	 * upper case character or underscore indicating the cursor position:
2195c84f3f3cSopenharmony_ci	 *	Who			Before	After	Before	After
2196c84f3f3cSopenharmony_ci	 *	AT&T ksh in emacs mode:	abCd	abdC	abcd_	(bell)
2197c84f3f3cSopenharmony_ci	 *	AT&T ksh in gmacs mode:	abCd	baCd	abcd_	abdc_
2198c84f3f3cSopenharmony_ci	 *	gnu emacs:		abCd	acbD	abcd_	abdc_
2199c84f3f3cSopenharmony_ci	 * Pdksh currently goes with GNU behavior since I believe this is the
2200c84f3f3cSopenharmony_ci	 * most common version of emacs, unless in gmacs mode, in which case
2201c84f3f3cSopenharmony_ci	 * it does the AT&T ksh gmacs mode.
2202c84f3f3cSopenharmony_ci	 * This should really be broken up into 3 functions so users can bind
2203c84f3f3cSopenharmony_ci	 * to the one they want.
2204c84f3f3cSopenharmony_ci	 */
2205c84f3f3cSopenharmony_ci	if (xcp == xbuf) {
2206c84f3f3cSopenharmony_ci		x_e_putc2(KSH_BEL);
2207c84f3f3cSopenharmony_ci		return (KSTD);
2208c84f3f3cSopenharmony_ci	} else if (xcp == xep || Flag(FGMACS)) {
2209c84f3f3cSopenharmony_ci		if (xcp - xbuf == 1) {
2210c84f3f3cSopenharmony_ci			x_e_putc2(KSH_BEL);
2211c84f3f3cSopenharmony_ci			return (KSTD);
2212c84f3f3cSopenharmony_ci		}
2213c84f3f3cSopenharmony_ci		/*
2214c84f3f3cSopenharmony_ci		 * Gosling/Unipress emacs style: Swap two characters before
2215c84f3f3cSopenharmony_ci		 * the cursor, do not change cursor position
2216c84f3f3cSopenharmony_ci		 */
2217c84f3f3cSopenharmony_ci		x_bs3(&xcp);
2218c84f3f3cSopenharmony_ci		if (utf_mbtowc(&tmpa, xcp) == (size_t)-1) {
2219c84f3f3cSopenharmony_ci			x_e_putc2(KSH_BEL);
2220c84f3f3cSopenharmony_ci			return (KSTD);
2221c84f3f3cSopenharmony_ci		}
2222c84f3f3cSopenharmony_ci		x_bs3(&xcp);
2223c84f3f3cSopenharmony_ci		if (utf_mbtowc(&tmpb, xcp) == (size_t)-1) {
2224c84f3f3cSopenharmony_ci			x_e_putc2(KSH_BEL);
2225c84f3f3cSopenharmony_ci			return (KSTD);
2226c84f3f3cSopenharmony_ci		}
2227c84f3f3cSopenharmony_ci		utf_wctomb(xcp, tmpa);
2228c84f3f3cSopenharmony_ci		x_zotc3(&xcp);
2229c84f3f3cSopenharmony_ci		utf_wctomb(xcp, tmpb);
2230c84f3f3cSopenharmony_ci		x_zotc3(&xcp);
2231c84f3f3cSopenharmony_ci	} else {
2232c84f3f3cSopenharmony_ci		/*
2233c84f3f3cSopenharmony_ci		 * GNU emacs style: Swap the characters before and under the
2234c84f3f3cSopenharmony_ci		 * cursor, move cursor position along one.
2235c84f3f3cSopenharmony_ci		 */
2236c84f3f3cSopenharmony_ci		if (utf_mbtowc(&tmpa, xcp) == (size_t)-1) {
2237c84f3f3cSopenharmony_ci			x_e_putc2(KSH_BEL);
2238c84f3f3cSopenharmony_ci			return (KSTD);
2239c84f3f3cSopenharmony_ci		}
2240c84f3f3cSopenharmony_ci		x_bs3(&xcp);
2241c84f3f3cSopenharmony_ci		if (utf_mbtowc(&tmpb, xcp) == (size_t)-1) {
2242c84f3f3cSopenharmony_ci			x_e_putc2(KSH_BEL);
2243c84f3f3cSopenharmony_ci			return (KSTD);
2244c84f3f3cSopenharmony_ci		}
2245c84f3f3cSopenharmony_ci		utf_wctomb(xcp, tmpa);
2246c84f3f3cSopenharmony_ci		x_zotc3(&xcp);
2247c84f3f3cSopenharmony_ci		utf_wctomb(xcp, tmpb);
2248c84f3f3cSopenharmony_ci		x_zotc3(&xcp);
2249c84f3f3cSopenharmony_ci	}
2250c84f3f3cSopenharmony_ci	x_modified();
2251c84f3f3cSopenharmony_ci	return (KSTD);
2252c84f3f3cSopenharmony_ci}
2253c84f3f3cSopenharmony_ci
2254c84f3f3cSopenharmony_cistatic int
2255c84f3f3cSopenharmony_cix_literal(int c MKSH_A_UNUSED)
2256c84f3f3cSopenharmony_ci{
2257c84f3f3cSopenharmony_ci	x_curprefix = -1;
2258c84f3f3cSopenharmony_ci	return (KSTD);
2259c84f3f3cSopenharmony_ci}
2260c84f3f3cSopenharmony_ci
2261c84f3f3cSopenharmony_cistatic int
2262c84f3f3cSopenharmony_cix_meta1(int c MKSH_A_UNUSED)
2263c84f3f3cSopenharmony_ci{
2264c84f3f3cSopenharmony_ci	x_curprefix = 1;
2265c84f3f3cSopenharmony_ci	return (KSTD);
2266c84f3f3cSopenharmony_ci}
2267c84f3f3cSopenharmony_ci
2268c84f3f3cSopenharmony_cistatic int
2269c84f3f3cSopenharmony_cix_meta2(int c MKSH_A_UNUSED)
2270c84f3f3cSopenharmony_ci{
2271c84f3f3cSopenharmony_ci	x_curprefix = 2;
2272c84f3f3cSopenharmony_ci	return (KSTD);
2273c84f3f3cSopenharmony_ci}
2274c84f3f3cSopenharmony_ci
2275c84f3f3cSopenharmony_cistatic int
2276c84f3f3cSopenharmony_cix_meta3(int c MKSH_A_UNUSED)
2277c84f3f3cSopenharmony_ci{
2278c84f3f3cSopenharmony_ci	x_curprefix = 3;
2279c84f3f3cSopenharmony_ci	return (KSTD);
2280c84f3f3cSopenharmony_ci}
2281c84f3f3cSopenharmony_ci
2282c84f3f3cSopenharmony_cistatic int
2283c84f3f3cSopenharmony_cix_kill(int c MKSH_A_UNUSED)
2284c84f3f3cSopenharmony_ci{
2285c84f3f3cSopenharmony_ci	size_t col = xcp - xbuf;
2286c84f3f3cSopenharmony_ci	size_t lastcol = xep - xbuf;
2287c84f3f3cSopenharmony_ci	size_t ndel, narg;
2288c84f3f3cSopenharmony_ci
2289c84f3f3cSopenharmony_ci	if (x_arg_defaulted || (narg = x_arg) > lastcol)
2290c84f3f3cSopenharmony_ci		narg = lastcol;
2291c84f3f3cSopenharmony_ci	if (narg < col) {
2292c84f3f3cSopenharmony_ci		x_goto(xbuf + narg);
2293c84f3f3cSopenharmony_ci		ndel = col - narg;
2294c84f3f3cSopenharmony_ci	} else
2295c84f3f3cSopenharmony_ci		ndel = narg - col;
2296c84f3f3cSopenharmony_ci	x_delete(x_nb2nc(ndel), true);
2297c84f3f3cSopenharmony_ci	return (KSTD);
2298c84f3f3cSopenharmony_ci}
2299c84f3f3cSopenharmony_ci
2300c84f3f3cSopenharmony_cistatic void
2301c84f3f3cSopenharmony_cix_push(size_t nchars)
2302c84f3f3cSopenharmony_ci{
2303c84f3f3cSopenharmony_ci	afree(killstack[killsp], AEDIT);
2304c84f3f3cSopenharmony_ci	strndupx(killstack[killsp], xcp, nchars, AEDIT);
2305c84f3f3cSopenharmony_ci	killsp = (killsp + 1) % KILLSIZE;
2306c84f3f3cSopenharmony_ci}
2307c84f3f3cSopenharmony_ci
2308c84f3f3cSopenharmony_cistatic int
2309c84f3f3cSopenharmony_cix_yank(int c MKSH_A_UNUSED)
2310c84f3f3cSopenharmony_ci{
2311c84f3f3cSopenharmony_ci	if (killsp == 0)
2312c84f3f3cSopenharmony_ci		killtp = KILLSIZE;
2313c84f3f3cSopenharmony_ci	else
2314c84f3f3cSopenharmony_ci		killtp = killsp;
2315c84f3f3cSopenharmony_ci	killtp--;
2316c84f3f3cSopenharmony_ci	if (killstack[killtp] == 0) {
2317c84f3f3cSopenharmony_ci		x_e_puts("\nnothing to yank");
2318c84f3f3cSopenharmony_ci		x_redraw('\n');
2319c84f3f3cSopenharmony_ci		return (KSTD);
2320c84f3f3cSopenharmony_ci	}
2321c84f3f3cSopenharmony_ci	xmp = xcp;
2322c84f3f3cSopenharmony_ci	x_ins(killstack[killtp]);
2323c84f3f3cSopenharmony_ci	return (KSTD);
2324c84f3f3cSopenharmony_ci}
2325c84f3f3cSopenharmony_ci
2326c84f3f3cSopenharmony_cistatic int
2327c84f3f3cSopenharmony_cix_meta_yank(int c MKSH_A_UNUSED)
2328c84f3f3cSopenharmony_ci{
2329c84f3f3cSopenharmony_ci	size_t len;
2330c84f3f3cSopenharmony_ci
2331c84f3f3cSopenharmony_ci	if ((x_last_command != XFUNC_yank && x_last_command != XFUNC_meta_yank) ||
2332c84f3f3cSopenharmony_ci	    killstack[killtp] == 0) {
2333c84f3f3cSopenharmony_ci		killtp = killsp;
2334c84f3f3cSopenharmony_ci		x_e_puts("\nyank something first");
2335c84f3f3cSopenharmony_ci		x_redraw('\n');
2336c84f3f3cSopenharmony_ci		return (KSTD);
2337c84f3f3cSopenharmony_ci	}
2338c84f3f3cSopenharmony_ci	len = strlen(killstack[killtp]);
2339c84f3f3cSopenharmony_ci	x_goto(xcp - len);
2340c84f3f3cSopenharmony_ci	x_delete(x_nb2nc(len), false);
2341c84f3f3cSopenharmony_ci	do {
2342c84f3f3cSopenharmony_ci		if (killtp == 0)
2343c84f3f3cSopenharmony_ci			killtp = KILLSIZE - 1;
2344c84f3f3cSopenharmony_ci		else
2345c84f3f3cSopenharmony_ci			killtp--;
2346c84f3f3cSopenharmony_ci	} while (killstack[killtp] == 0);
2347c84f3f3cSopenharmony_ci	x_ins(killstack[killtp]);
2348c84f3f3cSopenharmony_ci	return (KSTD);
2349c84f3f3cSopenharmony_ci}
2350c84f3f3cSopenharmony_ci
2351c84f3f3cSopenharmony_ci/* fake receiving an interrupt */
2352c84f3f3cSopenharmony_cistatic void
2353c84f3f3cSopenharmony_cix_intr(int signo, int c)
2354c84f3f3cSopenharmony_ci{
2355c84f3f3cSopenharmony_ci	x_vi_zotc(c);
2356c84f3f3cSopenharmony_ci	*xep = '\0';
2357c84f3f3cSopenharmony_ci	strip_nuls(xbuf, xep - xbuf);
2358c84f3f3cSopenharmony_ci	if (*xbuf)
2359c84f3f3cSopenharmony_ci		histsave(&source->line, xbuf, HIST_STORE, true);
2360c84f3f3cSopenharmony_ci	xlp = xep = xcp = xbp = xbuf;
2361c84f3f3cSopenharmony_ci	xlp_valid = true;
2362c84f3f3cSopenharmony_ci	*xcp = 0;
2363c84f3f3cSopenharmony_ci	x_modified();
2364c84f3f3cSopenharmony_ci	x_flush();
2365c84f3f3cSopenharmony_ci	trapsig(signo);
2366c84f3f3cSopenharmony_ci	x_mode(false);
2367c84f3f3cSopenharmony_ci	unwind(LSHELL);
2368c84f3f3cSopenharmony_ci}
2369c84f3f3cSopenharmony_ci
2370c84f3f3cSopenharmony_cistatic int
2371c84f3f3cSopenharmony_cix_abort(int c MKSH_A_UNUSED)
2372c84f3f3cSopenharmony_ci{
2373c84f3f3cSopenharmony_ci	return (KINTR);
2374c84f3f3cSopenharmony_ci}
2375c84f3f3cSopenharmony_ci
2376c84f3f3cSopenharmony_cistatic int
2377c84f3f3cSopenharmony_cix_error(int c MKSH_A_UNUSED)
2378c84f3f3cSopenharmony_ci{
2379c84f3f3cSopenharmony_ci	x_e_putc2(KSH_BEL);
2380c84f3f3cSopenharmony_ci	return (KSTD);
2381c84f3f3cSopenharmony_ci}
2382c84f3f3cSopenharmony_ci
2383c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
2384c84f3f3cSopenharmony_ci/* special VT100 style key sequence hack */
2385c84f3f3cSopenharmony_cistatic int
2386c84f3f3cSopenharmony_cix_vt_hack(int c)
2387c84f3f3cSopenharmony_ci{
2388c84f3f3cSopenharmony_ci	/* we only support PF2-'1' for now */
2389c84f3f3cSopenharmony_ci	if (c != (2 << 8 | '1'))
2390c84f3f3cSopenharmony_ci		return (x_error(c));
2391c84f3f3cSopenharmony_ci
2392c84f3f3cSopenharmony_ci	/* what's the next character? */
2393c84f3f3cSopenharmony_ci	switch ((c = x_e_getc())) {
2394c84f3f3cSopenharmony_ci	case '~':
2395c84f3f3cSopenharmony_ci		x_arg = 1;
2396c84f3f3cSopenharmony_ci		x_arg_defaulted = true;
2397c84f3f3cSopenharmony_ci		return (x_mv_beg(0));
2398c84f3f3cSopenharmony_ci	case ';':
2399c84f3f3cSopenharmony_ci		/* "interesting" sequence detected */
2400c84f3f3cSopenharmony_ci		break;
2401c84f3f3cSopenharmony_ci	default:
2402c84f3f3cSopenharmony_ci		goto unwind_err;
2403c84f3f3cSopenharmony_ci	}
2404c84f3f3cSopenharmony_ci
2405c84f3f3cSopenharmony_ci	/* XXX x_e_ungetc is one-octet only */
2406c84f3f3cSopenharmony_ci	if ((c = x_e_getc()) != '5' && c != '3')
2407c84f3f3cSopenharmony_ci		goto unwind_err;
2408c84f3f3cSopenharmony_ci
2409c84f3f3cSopenharmony_ci	/*-
2410c84f3f3cSopenharmony_ci	 * At this point, we have read the following octets so far:
2411c84f3f3cSopenharmony_ci	 * - ESC+[ or ESC+O or Ctrl-X (Prefix 2)
2412c84f3f3cSopenharmony_ci	 * - 1 (vt_hack)
2413c84f3f3cSopenharmony_ci	 * - ;
2414c84f3f3cSopenharmony_ci	 * - 5 (Ctrl key combiner) or 3 (Alt key combiner)
2415c84f3f3cSopenharmony_ci	 * We can now accept one more octet designating the key.
2416c84f3f3cSopenharmony_ci	 */
2417c84f3f3cSopenharmony_ci
2418c84f3f3cSopenharmony_ci	switch ((c = x_e_getc())) {
2419c84f3f3cSopenharmony_ci	case 'C':
2420c84f3f3cSopenharmony_ci		return (x_mv_fword(c));
2421c84f3f3cSopenharmony_ci	case 'D':
2422c84f3f3cSopenharmony_ci		return (x_mv_bword(c));
2423c84f3f3cSopenharmony_ci	}
2424c84f3f3cSopenharmony_ci
2425c84f3f3cSopenharmony_ci unwind_err:
2426c84f3f3cSopenharmony_ci	x_e_ungetc(c);
2427c84f3f3cSopenharmony_ci	return (x_error(c));
2428c84f3f3cSopenharmony_ci}
2429c84f3f3cSopenharmony_ci#endif
2430c84f3f3cSopenharmony_ci
2431c84f3f3cSopenharmony_ciint
2432c84f3f3cSopenharmony_cix_bind_check(void)
2433c84f3f3cSopenharmony_ci{
2434c84f3f3cSopenharmony_ci	return (x_tab == NULL);
2435c84f3f3cSopenharmony_ci}
2436c84f3f3cSopenharmony_ci
2437c84f3f3cSopenharmony_cistatic XString x_bind_show_xs;
2438c84f3f3cSopenharmony_cistatic char *x_bind_show_xp;
2439c84f3f3cSopenharmony_ci
2440c84f3f3cSopenharmony_cistatic void
2441c84f3f3cSopenharmony_cix_bind_show_ch(unsigned char ch)
2442c84f3f3cSopenharmony_ci{
2443c84f3f3cSopenharmony_ci	Xcheck(x_bind_show_xs, x_bind_show_xp);
2444c84f3f3cSopenharmony_ci	switch (ch) {
2445c84f3f3cSopenharmony_ci	case ORD('^'):
2446c84f3f3cSopenharmony_ci	case ORD('\\'):
2447c84f3f3cSopenharmony_ci	case ORD('='):
2448c84f3f3cSopenharmony_ci		*x_bind_show_xp++ = '\\';
2449c84f3f3cSopenharmony_ci		*x_bind_show_xp++ = ch;
2450c84f3f3cSopenharmony_ci		break;
2451c84f3f3cSopenharmony_ci	default:
2452c84f3f3cSopenharmony_ci		if (ksh_isctrl(ch)) {
2453c84f3f3cSopenharmony_ci			*x_bind_show_xp++ = '^';
2454c84f3f3cSopenharmony_ci			*x_bind_show_xp++ = ksh_unctrl(ch);
2455c84f3f3cSopenharmony_ci		} else
2456c84f3f3cSopenharmony_ci			*x_bind_show_xp++ = ch;
2457c84f3f3cSopenharmony_ci		break;
2458c84f3f3cSopenharmony_ci	}
2459c84f3f3cSopenharmony_ci}
2460c84f3f3cSopenharmony_ci
2461c84f3f3cSopenharmony_cistatic void
2462c84f3f3cSopenharmony_cix_bind_showone(int prefix, int key)
2463c84f3f3cSopenharmony_ci{
2464c84f3f3cSopenharmony_ci	unsigned char f = XFUNC_VALUE(x_tab[prefix][key]);
2465c84f3f3cSopenharmony_ci
2466c84f3f3cSopenharmony_ci	if (!x_bind_show_xs.areap)
2467c84f3f3cSopenharmony_ci		XinitN(x_bind_show_xs, 16, AEDIT);
2468c84f3f3cSopenharmony_ci
2469c84f3f3cSopenharmony_ci	x_bind_show_xp = Xstring(x_bind_show_xs, x_bind_show_xp);
2470c84f3f3cSopenharmony_ci	shf_puts("bind ", shl_stdout);
2471c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
2472c84f3f3cSopenharmony_ci	if (f == XFUNC_ins_string)
2473c84f3f3cSopenharmony_ci		shf_puts("-m ", shl_stdout);
2474c84f3f3cSopenharmony_ci#endif
2475c84f3f3cSopenharmony_ci	switch (prefix) {
2476c84f3f3cSopenharmony_ci	case 1:
2477c84f3f3cSopenharmony_ci		x_bind_show_ch(CTRL_BO);
2478c84f3f3cSopenharmony_ci		break;
2479c84f3f3cSopenharmony_ci	case 2:
2480c84f3f3cSopenharmony_ci		x_bind_show_ch(CTRL_X);
2481c84f3f3cSopenharmony_ci		break;
2482c84f3f3cSopenharmony_ci	case 3:
2483c84f3f3cSopenharmony_ci		x_bind_show_ch(0);
2484c84f3f3cSopenharmony_ci		break;
2485c84f3f3cSopenharmony_ci	}
2486c84f3f3cSopenharmony_ci	x_bind_show_ch(key);
2487c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
2488c84f3f3cSopenharmony_ci	if (x_tab[prefix][key] & 0x80)
2489c84f3f3cSopenharmony_ci		*x_bind_show_xp++ = '~';
2490c84f3f3cSopenharmony_ci#endif
2491c84f3f3cSopenharmony_ci	*x_bind_show_xp = '\0';
2492c84f3f3cSopenharmony_ci	x_bind_show_xp = Xstring(x_bind_show_xs, x_bind_show_xp);
2493c84f3f3cSopenharmony_ci	print_value_quoted(shl_stdout, x_bind_show_xp);
2494c84f3f3cSopenharmony_ci	shf_putc('=', shl_stdout);
2495c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
2496c84f3f3cSopenharmony_ci	if (f == XFUNC_ins_string) {
2497c84f3f3cSopenharmony_ci		const unsigned char *cp = (const void *)x_atab[prefix][key];
2498c84f3f3cSopenharmony_ci		unsigned char c;
2499c84f3f3cSopenharmony_ci
2500c84f3f3cSopenharmony_ci		while ((c = *cp++))
2501c84f3f3cSopenharmony_ci			x_bind_show_ch(c);
2502c84f3f3cSopenharmony_ci		*x_bind_show_xp = '\0';
2503c84f3f3cSopenharmony_ci		x_bind_show_xp = Xstring(x_bind_show_xs, x_bind_show_xp);
2504c84f3f3cSopenharmony_ci		print_value_quoted(shl_stdout, x_bind_show_xp);
2505c84f3f3cSopenharmony_ci	} else
2506c84f3f3cSopenharmony_ci#endif
2507c84f3f3cSopenharmony_ci	  shf_puts(x_ftab[f].xf_name, shl_stdout);
2508c84f3f3cSopenharmony_ci	shf_putc('\n', shl_stdout);
2509c84f3f3cSopenharmony_ci}
2510c84f3f3cSopenharmony_ci
2511c84f3f3cSopenharmony_ciint
2512c84f3f3cSopenharmony_cix_bind_list(void)
2513c84f3f3cSopenharmony_ci{
2514c84f3f3cSopenharmony_ci	size_t f;
2515c84f3f3cSopenharmony_ci
2516c84f3f3cSopenharmony_ci	for (f = 0; f < NELEM(x_ftab); f++)
2517c84f3f3cSopenharmony_ci		if (!(x_ftab[f].xf_flags & XF_NOBIND))
2518c84f3f3cSopenharmony_ci			shprintf(Tf_sN, x_ftab[f].xf_name);
2519c84f3f3cSopenharmony_ci	return (0);
2520c84f3f3cSopenharmony_ci}
2521c84f3f3cSopenharmony_ci
2522c84f3f3cSopenharmony_ciint
2523c84f3f3cSopenharmony_cix_bind_showall(void)
2524c84f3f3cSopenharmony_ci{
2525c84f3f3cSopenharmony_ci	int prefix, key;
2526c84f3f3cSopenharmony_ci
2527c84f3f3cSopenharmony_ci	for (prefix = 0; prefix < X_NTABS; prefix++)
2528c84f3f3cSopenharmony_ci		for (key = 0; key < X_TABSZ; key++)
2529c84f3f3cSopenharmony_ci			switch (XFUNC_VALUE(x_tab[prefix][key])) {
2530c84f3f3cSopenharmony_ci			case XFUNC_error:	/* unset */
2531c84f3f3cSopenharmony_ci			case XFUNC_insert:	/* auto-insert */
2532c84f3f3cSopenharmony_ci				break;
2533c84f3f3cSopenharmony_ci			default:
2534c84f3f3cSopenharmony_ci				x_bind_showone(prefix, key);
2535c84f3f3cSopenharmony_ci				break;
2536c84f3f3cSopenharmony_ci			}
2537c84f3f3cSopenharmony_ci	return (0);
2538c84f3f3cSopenharmony_ci}
2539c84f3f3cSopenharmony_ci
2540c84f3f3cSopenharmony_cistatic unsigned int
2541c84f3f3cSopenharmony_cix_bind_getc(const char **ccpp)
2542c84f3f3cSopenharmony_ci{
2543c84f3f3cSopenharmony_ci	unsigned int ch, ec;
2544c84f3f3cSopenharmony_ci
2545c84f3f3cSopenharmony_ci	if ((ch = ord(**ccpp)))
2546c84f3f3cSopenharmony_ci		++(*ccpp);
2547c84f3f3cSopenharmony_ci	switch (ch) {
2548c84f3f3cSopenharmony_ci	case ORD('^'):
2549c84f3f3cSopenharmony_ci		ch = ksh_toctrl(**ccpp) | 0x100U;
2550c84f3f3cSopenharmony_ci		if (**ccpp)
2551c84f3f3cSopenharmony_ci			++(*ccpp);
2552c84f3f3cSopenharmony_ci		break;
2553c84f3f3cSopenharmony_ci	case ORD('\\'):
2554c84f3f3cSopenharmony_ci		switch ((ec = ord(**ccpp))) {
2555c84f3f3cSopenharmony_ci		case ORD('^'):
2556c84f3f3cSopenharmony_ci		case ORD('\\'):
2557c84f3f3cSopenharmony_ci		case ORD('='):
2558c84f3f3cSopenharmony_ci			ch = ec | 0x100U;
2559c84f3f3cSopenharmony_ci			++(*ccpp);
2560c84f3f3cSopenharmony_ci			break;
2561c84f3f3cSopenharmony_ci		}
2562c84f3f3cSopenharmony_ci		break;
2563c84f3f3cSopenharmony_ci	}
2564c84f3f3cSopenharmony_ci	return (ch);
2565c84f3f3cSopenharmony_ci}
2566c84f3f3cSopenharmony_ci
2567c84f3f3cSopenharmony_ciint
2568c84f3f3cSopenharmony_cix_bind(const char *s SMALLP(bool macro))
2569c84f3f3cSopenharmony_ci{
2570c84f3f3cSopenharmony_ci	const char *ccp = s;
2571c84f3f3cSopenharmony_ci	int prefix, key;
2572c84f3f3cSopenharmony_ci	unsigned int c;
2573c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
2574c84f3f3cSopenharmony_ci	bool hastilde = false;
2575c84f3f3cSopenharmony_ci	char *ms = NULL;
2576c84f3f3cSopenharmony_ci#endif
2577c84f3f3cSopenharmony_ci
2578c84f3f3cSopenharmony_ci	prefix = 0;
2579c84f3f3cSopenharmony_ci	c = x_bind_getc(&ccp);
2580c84f3f3cSopenharmony_ci	if (!c || c == ORD('=')) {
2581c84f3f3cSopenharmony_ci		bi_errorf("no key to bind");
2582c84f3f3cSopenharmony_ci		return (1);
2583c84f3f3cSopenharmony_ci	}
2584c84f3f3cSopenharmony_ci	key = c & 0xFF;
2585c84f3f3cSopenharmony_ci	while ((c = x_bind_getc(&ccp)) != ORD('=')) {
2586c84f3f3cSopenharmony_ci		if (!c) {
2587c84f3f3cSopenharmony_ci			x_bind_showone(prefix, key);
2588c84f3f3cSopenharmony_ci			return (0);
2589c84f3f3cSopenharmony_ci		}
2590c84f3f3cSopenharmony_ci		switch (XFUNC_VALUE(x_tab[prefix][key])) {
2591c84f3f3cSopenharmony_ci		case XFUNC_meta1:
2592c84f3f3cSopenharmony_ci			prefix = 1;
2593c84f3f3cSopenharmony_ci			if (0)
2594c84f3f3cSopenharmony_ci				/* FALLTHROUGH */
2595c84f3f3cSopenharmony_ci		case XFUNC_meta2:
2596c84f3f3cSopenharmony_ci			  prefix = 2;
2597c84f3f3cSopenharmony_ci			if (0)
2598c84f3f3cSopenharmony_ci				/* FALLTHROUGH */
2599c84f3f3cSopenharmony_ci		case XFUNC_meta3:
2600c84f3f3cSopenharmony_ci			  prefix = 3;
2601c84f3f3cSopenharmony_ci			key = c & 0xFF;
2602c84f3f3cSopenharmony_ci			continue;
2603c84f3f3cSopenharmony_ci		}
2604c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
2605c84f3f3cSopenharmony_ci		if (c == ORD('~')) {
2606c84f3f3cSopenharmony_ci			hastilde = true;
2607c84f3f3cSopenharmony_ci			continue;
2608c84f3f3cSopenharmony_ci		}
2609c84f3f3cSopenharmony_ci#endif
2610c84f3f3cSopenharmony_ci		bi_errorf("too long key sequence: %s", s);
2611c84f3f3cSopenharmony_ci		return (-1);
2612c84f3f3cSopenharmony_ci	}
2613c84f3f3cSopenharmony_ci
2614c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
2615c84f3f3cSopenharmony_ci	if (macro) {
2616c84f3f3cSopenharmony_ci		char *cp;
2617c84f3f3cSopenharmony_ci
2618c84f3f3cSopenharmony_ci		cp = ms = alloc(strlen(ccp) + 1, AEDIT);
2619c84f3f3cSopenharmony_ci		while ((c = x_bind_getc(&ccp)))
2620c84f3f3cSopenharmony_ci			*cp++ = c;
2621c84f3f3cSopenharmony_ci		*cp = '\0';
2622c84f3f3cSopenharmony_ci		c = XFUNC_ins_string;
2623c84f3f3cSopenharmony_ci	} else
2624c84f3f3cSopenharmony_ci#endif
2625c84f3f3cSopenharmony_ci	  if (!*ccp) {
2626c84f3f3cSopenharmony_ci		c = XFUNC_insert;
2627c84f3f3cSopenharmony_ci	} else {
2628c84f3f3cSopenharmony_ci		for (c = 0; c < NELEM(x_ftab); ++c)
2629c84f3f3cSopenharmony_ci			if (!strcmp(x_ftab[c].xf_name, ccp))
2630c84f3f3cSopenharmony_ci				break;
2631c84f3f3cSopenharmony_ci		if (c == NELEM(x_ftab) || x_ftab[c].xf_flags & XF_NOBIND) {
2632c84f3f3cSopenharmony_ci			bi_errorf("%s: no such editing command", ccp);
2633c84f3f3cSopenharmony_ci			return (1);
2634c84f3f3cSopenharmony_ci		}
2635c84f3f3cSopenharmony_ci	}
2636c84f3f3cSopenharmony_ci
2637c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
2638c84f3f3cSopenharmony_ci	if (XFUNC_VALUE(x_tab[prefix][key]) == XFUNC_ins_string)
2639c84f3f3cSopenharmony_ci		afree(x_atab[prefix][key], AEDIT);
2640c84f3f3cSopenharmony_ci	x_atab[prefix][key] = ms;
2641c84f3f3cSopenharmony_ci	if (hastilde)
2642c84f3f3cSopenharmony_ci		c |= 0x80U;
2643c84f3f3cSopenharmony_ci#endif
2644c84f3f3cSopenharmony_ci	x_tab[prefix][key] = c;
2645c84f3f3cSopenharmony_ci
2646c84f3f3cSopenharmony_ci	/* track what the user has bound, so x_mode(true) won't toast things */
2647c84f3f3cSopenharmony_ci	if (c == XFUNC_insert)
2648c84f3f3cSopenharmony_ci		x_bound[(prefix * X_TABSZ + key) / 8] &=
2649c84f3f3cSopenharmony_ci		    ~(1 << ((prefix * X_TABSZ + key) % 8));
2650c84f3f3cSopenharmony_ci	else
2651c84f3f3cSopenharmony_ci		x_bound[(prefix * X_TABSZ + key) / 8] |=
2652c84f3f3cSopenharmony_ci		    (1 << ((prefix * X_TABSZ + key) % 8));
2653c84f3f3cSopenharmony_ci
2654c84f3f3cSopenharmony_ci	return (0);
2655c84f3f3cSopenharmony_ci}
2656c84f3f3cSopenharmony_ci
2657c84f3f3cSopenharmony_cistatic void
2658c84f3f3cSopenharmony_cibind_if_not_bound(int p, int k, int func)
2659c84f3f3cSopenharmony_ci{
2660c84f3f3cSopenharmony_ci	int t;
2661c84f3f3cSopenharmony_ci
2662c84f3f3cSopenharmony_ci	/*
2663c84f3f3cSopenharmony_ci	 * Has user already bound this key?
2664c84f3f3cSopenharmony_ci	 * If so, do not override it.
2665c84f3f3cSopenharmony_ci	 */
2666c84f3f3cSopenharmony_ci	t = p * X_TABSZ + k;
2667c84f3f3cSopenharmony_ci	if (x_bound[t >> 3] & (1 << (t & 7)))
2668c84f3f3cSopenharmony_ci		return;
2669c84f3f3cSopenharmony_ci
2670c84f3f3cSopenharmony_ci	x_tab[p][k] = func;
2671c84f3f3cSopenharmony_ci}
2672c84f3f3cSopenharmony_ci
2673c84f3f3cSopenharmony_cistatic int
2674c84f3f3cSopenharmony_cix_set_mark(int c MKSH_A_UNUSED)
2675c84f3f3cSopenharmony_ci{
2676c84f3f3cSopenharmony_ci	xmp = xcp;
2677c84f3f3cSopenharmony_ci	return (KSTD);
2678c84f3f3cSopenharmony_ci}
2679c84f3f3cSopenharmony_ci
2680c84f3f3cSopenharmony_cistatic int
2681c84f3f3cSopenharmony_cix_kill_region(int c MKSH_A_UNUSED)
2682c84f3f3cSopenharmony_ci{
2683c84f3f3cSopenharmony_ci	size_t rsize;
2684c84f3f3cSopenharmony_ci	char *xr;
2685c84f3f3cSopenharmony_ci
2686c84f3f3cSopenharmony_ci	if (xmp == NULL) {
2687c84f3f3cSopenharmony_ci		x_e_putc2(KSH_BEL);
2688c84f3f3cSopenharmony_ci		return (KSTD);
2689c84f3f3cSopenharmony_ci	}
2690c84f3f3cSopenharmony_ci	if (xmp > xcp) {
2691c84f3f3cSopenharmony_ci		rsize = xmp - xcp;
2692c84f3f3cSopenharmony_ci		xr = xcp;
2693c84f3f3cSopenharmony_ci	} else {
2694c84f3f3cSopenharmony_ci		rsize = xcp - xmp;
2695c84f3f3cSopenharmony_ci		xr = xmp;
2696c84f3f3cSopenharmony_ci	}
2697c84f3f3cSopenharmony_ci	x_goto(xr);
2698c84f3f3cSopenharmony_ci	x_delete(x_nb2nc(rsize), true);
2699c84f3f3cSopenharmony_ci	xmp = xr;
2700c84f3f3cSopenharmony_ci	return (KSTD);
2701c84f3f3cSopenharmony_ci}
2702c84f3f3cSopenharmony_ci
2703c84f3f3cSopenharmony_cistatic int
2704c84f3f3cSopenharmony_cix_xchg_point_mark(int c MKSH_A_UNUSED)
2705c84f3f3cSopenharmony_ci{
2706c84f3f3cSopenharmony_ci	char *tmp;
2707c84f3f3cSopenharmony_ci
2708c84f3f3cSopenharmony_ci	if (xmp == NULL) {
2709c84f3f3cSopenharmony_ci		x_e_putc2(KSH_BEL);
2710c84f3f3cSopenharmony_ci		return (KSTD);
2711c84f3f3cSopenharmony_ci	}
2712c84f3f3cSopenharmony_ci	tmp = xmp;
2713c84f3f3cSopenharmony_ci	xmp = xcp;
2714c84f3f3cSopenharmony_ci	x_goto(tmp);
2715c84f3f3cSopenharmony_ci	return (KSTD);
2716c84f3f3cSopenharmony_ci}
2717c84f3f3cSopenharmony_ci
2718c84f3f3cSopenharmony_cistatic int
2719c84f3f3cSopenharmony_cix_noop(int c MKSH_A_UNUSED)
2720c84f3f3cSopenharmony_ci{
2721c84f3f3cSopenharmony_ci	return (KSTD);
2722c84f3f3cSopenharmony_ci}
2723c84f3f3cSopenharmony_ci
2724c84f3f3cSopenharmony_ci/*
2725c84f3f3cSopenharmony_ci *	File/command name completion routines
2726c84f3f3cSopenharmony_ci */
2727c84f3f3cSopenharmony_cistatic int
2728c84f3f3cSopenharmony_cix_comp_comm(int c MKSH_A_UNUSED)
2729c84f3f3cSopenharmony_ci{
2730c84f3f3cSopenharmony_ci	do_complete(XCF_COMMAND, CT_COMPLETE);
2731c84f3f3cSopenharmony_ci	return (KSTD);
2732c84f3f3cSopenharmony_ci}
2733c84f3f3cSopenharmony_ci
2734c84f3f3cSopenharmony_cistatic int
2735c84f3f3cSopenharmony_cix_list_comm(int c MKSH_A_UNUSED)
2736c84f3f3cSopenharmony_ci{
2737c84f3f3cSopenharmony_ci	do_complete(XCF_COMMAND, CT_LIST);
2738c84f3f3cSopenharmony_ci	return (KSTD);
2739c84f3f3cSopenharmony_ci}
2740c84f3f3cSopenharmony_ci
2741c84f3f3cSopenharmony_cistatic int
2742c84f3f3cSopenharmony_cix_complete(int c MKSH_A_UNUSED)
2743c84f3f3cSopenharmony_ci{
2744c84f3f3cSopenharmony_ci	do_complete(XCF_COMMAND_FILE, CT_COMPLETE);
2745c84f3f3cSopenharmony_ci	return (KSTD);
2746c84f3f3cSopenharmony_ci}
2747c84f3f3cSopenharmony_ci
2748c84f3f3cSopenharmony_cistatic int
2749c84f3f3cSopenharmony_cix_enumerate(int c MKSH_A_UNUSED)
2750c84f3f3cSopenharmony_ci{
2751c84f3f3cSopenharmony_ci	do_complete(XCF_COMMAND_FILE, CT_LIST);
2752c84f3f3cSopenharmony_ci	return (KSTD);
2753c84f3f3cSopenharmony_ci}
2754c84f3f3cSopenharmony_ci
2755c84f3f3cSopenharmony_cistatic int
2756c84f3f3cSopenharmony_cix_comp_file(int c MKSH_A_UNUSED)
2757c84f3f3cSopenharmony_ci{
2758c84f3f3cSopenharmony_ci	do_complete(XCF_FILE, CT_COMPLETE);
2759c84f3f3cSopenharmony_ci	return (KSTD);
2760c84f3f3cSopenharmony_ci}
2761c84f3f3cSopenharmony_ci
2762c84f3f3cSopenharmony_cistatic int
2763c84f3f3cSopenharmony_cix_list_file(int c MKSH_A_UNUSED)
2764c84f3f3cSopenharmony_ci{
2765c84f3f3cSopenharmony_ci	do_complete(XCF_FILE, CT_LIST);
2766c84f3f3cSopenharmony_ci	return (KSTD);
2767c84f3f3cSopenharmony_ci}
2768c84f3f3cSopenharmony_ci
2769c84f3f3cSopenharmony_cistatic int
2770c84f3f3cSopenharmony_cix_comp_list(int c MKSH_A_UNUSED)
2771c84f3f3cSopenharmony_ci{
2772c84f3f3cSopenharmony_ci	do_complete(XCF_COMMAND_FILE, CT_COMPLIST);
2773c84f3f3cSopenharmony_ci	return (KSTD);
2774c84f3f3cSopenharmony_ci}
2775c84f3f3cSopenharmony_ci
2776c84f3f3cSopenharmony_cistatic int
2777c84f3f3cSopenharmony_cix_expand(int c MKSH_A_UNUSED)
2778c84f3f3cSopenharmony_ci{
2779c84f3f3cSopenharmony_ci	char **words;
2780c84f3f3cSopenharmony_ci	int start, end, nwords, i;
2781c84f3f3cSopenharmony_ci
2782c84f3f3cSopenharmony_ci	i = XCF_FILE;
2783c84f3f3cSopenharmony_ci	nwords = x_cf_glob(&i, xbuf, xep - xbuf, xcp - xbuf,
2784c84f3f3cSopenharmony_ci	    &start, &end, &words);
2785c84f3f3cSopenharmony_ci
2786c84f3f3cSopenharmony_ci	if (nwords == 0) {
2787c84f3f3cSopenharmony_ci		x_e_putc2(KSH_BEL);
2788c84f3f3cSopenharmony_ci		return (KSTD);
2789c84f3f3cSopenharmony_ci	}
2790c84f3f3cSopenharmony_ci	x_goto(xbuf + start);
2791c84f3f3cSopenharmony_ci	x_delete(x_nb2nc(end - start), false);
2792c84f3f3cSopenharmony_ci
2793c84f3f3cSopenharmony_ci	i = 0;
2794c84f3f3cSopenharmony_ci	while (i < nwords) {
2795c84f3f3cSopenharmony_ci		if (x_escape(words[i], strlen(words[i]), x_do_ins) < 0 ||
2796c84f3f3cSopenharmony_ci		    (++i < nwords && x_ins(T1space) < 0)) {
2797c84f3f3cSopenharmony_ci			x_e_putc2(KSH_BEL);
2798c84f3f3cSopenharmony_ci			return (KSTD);
2799c84f3f3cSopenharmony_ci		}
2800c84f3f3cSopenharmony_ci	}
2801c84f3f3cSopenharmony_ci	x_adjust();
2802c84f3f3cSopenharmony_ci
2803c84f3f3cSopenharmony_ci	return (KSTD);
2804c84f3f3cSopenharmony_ci}
2805c84f3f3cSopenharmony_ci
2806c84f3f3cSopenharmony_cistatic void
2807c84f3f3cSopenharmony_cido_complete(
2808c84f3f3cSopenharmony_ci    /* XCF_{COMMAND,FILE,COMMAND_FILE} */
2809c84f3f3cSopenharmony_ci    int flags,
2810c84f3f3cSopenharmony_ci    /* 0 for list, 1 for complete and 2 for complete-list */
2811c84f3f3cSopenharmony_ci    Comp_type type)
2812c84f3f3cSopenharmony_ci{
2813c84f3f3cSopenharmony_ci	char **words;
2814c84f3f3cSopenharmony_ci	int start, end, nlen, olen, nwords;
2815c84f3f3cSopenharmony_ci	bool completed;
2816c84f3f3cSopenharmony_ci
2817c84f3f3cSopenharmony_ci	nwords = x_cf_glob(&flags, xbuf, xep - xbuf, xcp - xbuf,
2818c84f3f3cSopenharmony_ci	    &start, &end, &words);
2819c84f3f3cSopenharmony_ci	/* no match */
2820c84f3f3cSopenharmony_ci	if (nwords == 0) {
2821c84f3f3cSopenharmony_ci		x_e_putc2(KSH_BEL);
2822c84f3f3cSopenharmony_ci		return;
2823c84f3f3cSopenharmony_ci	}
2824c84f3f3cSopenharmony_ci	if (type == CT_LIST) {
2825c84f3f3cSopenharmony_ci		x_print_expansions(nwords, words,
2826c84f3f3cSopenharmony_ci		    tobool(flags & XCF_IS_COMMAND));
2827c84f3f3cSopenharmony_ci		x_redraw(0);
2828c84f3f3cSopenharmony_ci		x_free_words(nwords, words);
2829c84f3f3cSopenharmony_ci		return;
2830c84f3f3cSopenharmony_ci	}
2831c84f3f3cSopenharmony_ci	olen = end - start;
2832c84f3f3cSopenharmony_ci	nlen = x_longest_prefix(nwords, words);
2833c84f3f3cSopenharmony_ci	if (nwords == 1) {
2834c84f3f3cSopenharmony_ci		/*
2835c84f3f3cSopenharmony_ci		 * always complete single matches;
2836c84f3f3cSopenharmony_ci		 * any expansion of parameter substitution
2837c84f3f3cSopenharmony_ci		 * is always at most one result, too
2838c84f3f3cSopenharmony_ci		 */
2839c84f3f3cSopenharmony_ci		completed = true;
2840c84f3f3cSopenharmony_ci	} else {
2841c84f3f3cSopenharmony_ci		char *unescaped;
2842c84f3f3cSopenharmony_ci
2843c84f3f3cSopenharmony_ci		/* make a copy of the original string part */
2844c84f3f3cSopenharmony_ci		strndupx(unescaped, xbuf + start, olen, ATEMP);
2845c84f3f3cSopenharmony_ci
2846c84f3f3cSopenharmony_ci		/* expand any tilde and unescape the string for comparison */
2847c84f3f3cSopenharmony_ci		unescaped = x_glob_hlp_tilde_and_rem_qchar(unescaped, true);
2848c84f3f3cSopenharmony_ci
2849c84f3f3cSopenharmony_ci		/*
2850c84f3f3cSopenharmony_ci		 * match iff entire original string is part of the
2851c84f3f3cSopenharmony_ci		 * longest prefix, implying the latter is at least
2852c84f3f3cSopenharmony_ci		 * the same size (after unescaping)
2853c84f3f3cSopenharmony_ci		 */
2854c84f3f3cSopenharmony_ci		completed = !strncmp(words[0], unescaped, strlen(unescaped));
2855c84f3f3cSopenharmony_ci
2856c84f3f3cSopenharmony_ci		afree(unescaped, ATEMP);
2857c84f3f3cSopenharmony_ci	}
2858c84f3f3cSopenharmony_ci	if (type == CT_COMPLIST && nwords > 1) {
2859c84f3f3cSopenharmony_ci		/*
2860c84f3f3cSopenharmony_ci		 * print expansions, since we didn't get back
2861c84f3f3cSopenharmony_ci		 * just a single match
2862c84f3f3cSopenharmony_ci		 */
2863c84f3f3cSopenharmony_ci		x_print_expansions(nwords, words,
2864c84f3f3cSopenharmony_ci		    tobool(flags & XCF_IS_COMMAND));
2865c84f3f3cSopenharmony_ci	}
2866c84f3f3cSopenharmony_ci	if (completed) {
2867c84f3f3cSopenharmony_ci		/* expand on the command line */
2868c84f3f3cSopenharmony_ci		xmp = NULL;
2869c84f3f3cSopenharmony_ci		xcp = xbuf + start;
2870c84f3f3cSopenharmony_ci		xep -= olen;
2871c84f3f3cSopenharmony_ci		memmove(xcp, xcp + olen, xep - xcp + 1);
2872c84f3f3cSopenharmony_ci		x_escape(words[0], nlen, x_do_ins);
2873c84f3f3cSopenharmony_ci	}
2874c84f3f3cSopenharmony_ci	x_adjust();
2875c84f3f3cSopenharmony_ci	/*
2876c84f3f3cSopenharmony_ci	 * append a space if this is a single non-directory match
2877c84f3f3cSopenharmony_ci	 * and not a parameter or homedir substitution
2878c84f3f3cSopenharmony_ci	 */
2879c84f3f3cSopenharmony_ci	if (nwords == 1 && !mksh_cdirsep(words[0][nlen - 1]) &&
2880c84f3f3cSopenharmony_ci	    !(flags & XCF_IS_NOSPACE)) {
2881c84f3f3cSopenharmony_ci		x_ins(T1space);
2882c84f3f3cSopenharmony_ci	}
2883c84f3f3cSopenharmony_ci
2884c84f3f3cSopenharmony_ci	x_free_words(nwords, words);
2885c84f3f3cSopenharmony_ci}
2886c84f3f3cSopenharmony_ci
2887c84f3f3cSopenharmony_ci/*-
2888c84f3f3cSopenharmony_ci * NAME:
2889c84f3f3cSopenharmony_ci *	x_adjust - redraw the line adjusting starting point etc.
2890c84f3f3cSopenharmony_ci *
2891c84f3f3cSopenharmony_ci * DESCRIPTION:
2892c84f3f3cSopenharmony_ci *	This function is called when we have exceeded the bounds
2893c84f3f3cSopenharmony_ci *	of the edit window. It increments x_adj_done so that
2894c84f3f3cSopenharmony_ci *	functions like x_ins and x_delete know that we have been
2895c84f3f3cSopenharmony_ci *	called and can skip the x_bs() stuff which has already
2896c84f3f3cSopenharmony_ci *	been done by x_redraw.
2897c84f3f3cSopenharmony_ci *
2898c84f3f3cSopenharmony_ci * RETURN VALUE:
2899c84f3f3cSopenharmony_ci *	None
2900c84f3f3cSopenharmony_ci */
2901c84f3f3cSopenharmony_cistatic void
2902c84f3f3cSopenharmony_cix_adjust(void)
2903c84f3f3cSopenharmony_ci{
2904c84f3f3cSopenharmony_ci	int col_left, n;
2905c84f3f3cSopenharmony_ci
2906c84f3f3cSopenharmony_ci	/* flag the fact that we were called */
2907c84f3f3cSopenharmony_ci	x_adj_done++;
2908c84f3f3cSopenharmony_ci
2909c84f3f3cSopenharmony_ci	/*
2910c84f3f3cSopenharmony_ci	 * calculate the amount of columns we need to "go back"
2911c84f3f3cSopenharmony_ci	 * from xcp to set xbp to (but never < xbuf) to 2/3 of
2912c84f3f3cSopenharmony_ci	 * the display width; take care of pwidth though
2913c84f3f3cSopenharmony_ci	 */
2914c84f3f3cSopenharmony_ci	if ((col_left = xx_cols * 2 / 3) < MIN_EDIT_SPACE) {
2915c84f3f3cSopenharmony_ci		/*
2916c84f3f3cSopenharmony_ci		 * cowardly refuse to do anything
2917c84f3f3cSopenharmony_ci		 * if the available space is too small;
2918c84f3f3cSopenharmony_ci		 * fall back to dumb pdksh code
2919c84f3f3cSopenharmony_ci		 */
2920c84f3f3cSopenharmony_ci		if ((xbp = xcp - (x_displen / 2)) < xbuf)
2921c84f3f3cSopenharmony_ci			xbp = xbuf;
2922c84f3f3cSopenharmony_ci		/* elide UTF-8 fixup as penalty */
2923c84f3f3cSopenharmony_ci		goto x_adjust_out;
2924c84f3f3cSopenharmony_ci	}
2925c84f3f3cSopenharmony_ci
2926c84f3f3cSopenharmony_ci	/* fix up xbp to just past a character end first */
2927c84f3f3cSopenharmony_ci	xbp = xcp >= xep ? xep : x_bs0(xcp, xbuf);
2928c84f3f3cSopenharmony_ci	/* walk backwards */
2929c84f3f3cSopenharmony_ci	while (xbp > xbuf && col_left > 0) {
2930c84f3f3cSopenharmony_ci		xbp = x_bs0(xbp - 1, xbuf);
2931c84f3f3cSopenharmony_ci		col_left -= (n = x_size2(xbp, NULL));
2932c84f3f3cSopenharmony_ci	}
2933c84f3f3cSopenharmony_ci	/* check if we hit the prompt */
2934c84f3f3cSopenharmony_ci	if (xbp == xbuf && xcp != xbuf && col_left >= 0 && col_left < pwidth) {
2935c84f3f3cSopenharmony_ci		/* so we did; force scrolling occurs */
2936c84f3f3cSopenharmony_ci		xbp += utf_ptradj(xbp);
2937c84f3f3cSopenharmony_ci	}
2938c84f3f3cSopenharmony_ci
2939c84f3f3cSopenharmony_ci x_adjust_out:
2940c84f3f3cSopenharmony_ci	xlp_valid = false;
2941c84f3f3cSopenharmony_ci	x_redraw('\r');
2942c84f3f3cSopenharmony_ci	x_flush();
2943c84f3f3cSopenharmony_ci}
2944c84f3f3cSopenharmony_ci
2945c84f3f3cSopenharmony_cistatic void
2946c84f3f3cSopenharmony_cix_e_ungetc(int c)
2947c84f3f3cSopenharmony_ci{
2948c84f3f3cSopenharmony_ci	unget_char = c < 0 ? -1 : (c & 255);
2949c84f3f3cSopenharmony_ci}
2950c84f3f3cSopenharmony_ci
2951c84f3f3cSopenharmony_cistatic int
2952c84f3f3cSopenharmony_cix_e_getc(void)
2953c84f3f3cSopenharmony_ci{
2954c84f3f3cSopenharmony_ci	int c;
2955c84f3f3cSopenharmony_ci
2956c84f3f3cSopenharmony_ci	if (unget_char >= 0) {
2957c84f3f3cSopenharmony_ci		c = unget_char;
2958c84f3f3cSopenharmony_ci		unget_char = -1;
2959c84f3f3cSopenharmony_ci		return (c);
2960c84f3f3cSopenharmony_ci	}
2961c84f3f3cSopenharmony_ci
2962c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
2963c84f3f3cSopenharmony_ci	if (macroptr) {
2964c84f3f3cSopenharmony_ci		if ((c = (unsigned char)*macroptr++))
2965c84f3f3cSopenharmony_ci			return (c);
2966c84f3f3cSopenharmony_ci		macroptr = NULL;
2967c84f3f3cSopenharmony_ci	}
2968c84f3f3cSopenharmony_ci#endif
2969c84f3f3cSopenharmony_ci
2970c84f3f3cSopenharmony_ci	return (x_getc());
2971c84f3f3cSopenharmony_ci}
2972c84f3f3cSopenharmony_ci
2973c84f3f3cSopenharmony_cistatic void
2974c84f3f3cSopenharmony_cix_e_putc2(int c)
2975c84f3f3cSopenharmony_ci{
2976c84f3f3cSopenharmony_ci	int width = 1;
2977c84f3f3cSopenharmony_ci
2978c84f3f3cSopenharmony_ci	if (ctype(c, C_CR | C_LF))
2979c84f3f3cSopenharmony_ci		x_col = 0;
2980c84f3f3cSopenharmony_ci	if (x_col < xx_cols) {
2981c84f3f3cSopenharmony_ci#ifndef MKSH_EBCDIC
2982c84f3f3cSopenharmony_ci		if (UTFMODE && (c > 0x7F)) {
2983c84f3f3cSopenharmony_ci			char utf_tmp[3];
2984c84f3f3cSopenharmony_ci			size_t x;
2985c84f3f3cSopenharmony_ci
2986c84f3f3cSopenharmony_ci			if (c < 0xA0)
2987c84f3f3cSopenharmony_ci				c = 0xFFFD;
2988c84f3f3cSopenharmony_ci			x = utf_wctomb(utf_tmp, c);
2989c84f3f3cSopenharmony_ci			x_putc(utf_tmp[0]);
2990c84f3f3cSopenharmony_ci			if (x > 1)
2991c84f3f3cSopenharmony_ci				x_putc(utf_tmp[1]);
2992c84f3f3cSopenharmony_ci			if (x > 2)
2993c84f3f3cSopenharmony_ci				x_putc(utf_tmp[2]);
2994c84f3f3cSopenharmony_ci			width = utf_wcwidth(c);
2995c84f3f3cSopenharmony_ci		} else
2996c84f3f3cSopenharmony_ci#endif
2997c84f3f3cSopenharmony_ci			x_putc(c);
2998c84f3f3cSopenharmony_ci		switch (c) {
2999c84f3f3cSopenharmony_ci		case KSH_BEL:
3000c84f3f3cSopenharmony_ci			break;
3001c84f3f3cSopenharmony_ci		case '\r':
3002c84f3f3cSopenharmony_ci		case '\n':
3003c84f3f3cSopenharmony_ci			break;
3004c84f3f3cSopenharmony_ci		case '\b':
3005c84f3f3cSopenharmony_ci			x_col--;
3006c84f3f3cSopenharmony_ci			break;
3007c84f3f3cSopenharmony_ci		default:
3008c84f3f3cSopenharmony_ci			x_col += width;
3009c84f3f3cSopenharmony_ci			break;
3010c84f3f3cSopenharmony_ci		}
3011c84f3f3cSopenharmony_ci	}
3012c84f3f3cSopenharmony_ci	if (x_adj_ok && (x_col < 0 || x_col >= (xx_cols - 2)))
3013c84f3f3cSopenharmony_ci		x_adjust();
3014c84f3f3cSopenharmony_ci}
3015c84f3f3cSopenharmony_ci
3016c84f3f3cSopenharmony_cistatic void
3017c84f3f3cSopenharmony_cix_e_putc3(const char **cp)
3018c84f3f3cSopenharmony_ci{
3019c84f3f3cSopenharmony_ci	int width = 1, c = **(const unsigned char **)cp;
3020c84f3f3cSopenharmony_ci
3021c84f3f3cSopenharmony_ci	if (ctype(c, C_CR | C_LF))
3022c84f3f3cSopenharmony_ci		x_col = 0;
3023c84f3f3cSopenharmony_ci	if (x_col < xx_cols) {
3024c84f3f3cSopenharmony_ci		if (UTFMODE && (c > 0x7F)) {
3025c84f3f3cSopenharmony_ci			char *cp2;
3026c84f3f3cSopenharmony_ci
3027c84f3f3cSopenharmony_ci			width = utf_widthadj(*cp, (const char **)&cp2);
3028c84f3f3cSopenharmony_ci			if (cp2 == *cp + 1) {
3029c84f3f3cSopenharmony_ci				(*cp)++;
3030c84f3f3cSopenharmony_ci#ifdef MKSH_EBCDIC
3031c84f3f3cSopenharmony_ci				x_putc(asc2rtt(0xEF));
3032c84f3f3cSopenharmony_ci				x_putc(asc2rtt(0xBF));
3033c84f3f3cSopenharmony_ci				x_putc(asc2rtt(0xBD));
3034c84f3f3cSopenharmony_ci#else
3035c84f3f3cSopenharmony_ci				shf_puts("\xEF\xBF\xBD", shl_out);
3036c84f3f3cSopenharmony_ci#endif
3037c84f3f3cSopenharmony_ci			} else
3038c84f3f3cSopenharmony_ci				while (*cp < cp2)
3039c84f3f3cSopenharmony_ci					x_putcf(*(*cp)++);
3040c84f3f3cSopenharmony_ci		} else {
3041c84f3f3cSopenharmony_ci			(*cp)++;
3042c84f3f3cSopenharmony_ci			x_putc(c);
3043c84f3f3cSopenharmony_ci		}
3044c84f3f3cSopenharmony_ci		switch (c) {
3045c84f3f3cSopenharmony_ci		case KSH_BEL:
3046c84f3f3cSopenharmony_ci			break;
3047c84f3f3cSopenharmony_ci		case '\r':
3048c84f3f3cSopenharmony_ci		case '\n':
3049c84f3f3cSopenharmony_ci			break;
3050c84f3f3cSopenharmony_ci		case '\b':
3051c84f3f3cSopenharmony_ci			x_col--;
3052c84f3f3cSopenharmony_ci			break;
3053c84f3f3cSopenharmony_ci		default:
3054c84f3f3cSopenharmony_ci			x_col += width;
3055c84f3f3cSopenharmony_ci			break;
3056c84f3f3cSopenharmony_ci		}
3057c84f3f3cSopenharmony_ci	}
3058c84f3f3cSopenharmony_ci	if (x_adj_ok && (x_col < 0 || x_col >= (xx_cols - 2)))
3059c84f3f3cSopenharmony_ci		x_adjust();
3060c84f3f3cSopenharmony_ci}
3061c84f3f3cSopenharmony_ci
3062c84f3f3cSopenharmony_cistatic void
3063c84f3f3cSopenharmony_cix_e_puts(const char *s)
3064c84f3f3cSopenharmony_ci{
3065c84f3f3cSopenharmony_ci	int adj = x_adj_done;
3066c84f3f3cSopenharmony_ci
3067c84f3f3cSopenharmony_ci	while (*s && adj == x_adj_done)
3068c84f3f3cSopenharmony_ci		x_e_putc3(&s);
3069c84f3f3cSopenharmony_ci}
3070c84f3f3cSopenharmony_ci
3071c84f3f3cSopenharmony_ci/*-
3072c84f3f3cSopenharmony_ci * NAME:
3073c84f3f3cSopenharmony_ci *	x_set_arg - set an arg value for next function
3074c84f3f3cSopenharmony_ci *
3075c84f3f3cSopenharmony_ci * DESCRIPTION:
3076c84f3f3cSopenharmony_ci *	This is a simple implementation of M-[0-9].
3077c84f3f3cSopenharmony_ci *
3078c84f3f3cSopenharmony_ci * RETURN VALUE:
3079c84f3f3cSopenharmony_ci *	KSTD
3080c84f3f3cSopenharmony_ci */
3081c84f3f3cSopenharmony_cistatic int
3082c84f3f3cSopenharmony_cix_set_arg(int c)
3083c84f3f3cSopenharmony_ci{
3084c84f3f3cSopenharmony_ci	unsigned int n = 0;
3085c84f3f3cSopenharmony_ci	bool first = true;
3086c84f3f3cSopenharmony_ci
3087c84f3f3cSopenharmony_ci	/* strip command prefix */
3088c84f3f3cSopenharmony_ci	c &= 255;
3089c84f3f3cSopenharmony_ci	while (c >= 0 && ctype(c, C_DIGIT)) {
3090c84f3f3cSopenharmony_ci		n = n * 10 + ksh_numdig(c);
3091c84f3f3cSopenharmony_ci		if (n > LINE)
3092c84f3f3cSopenharmony_ci			/* upper bound for repeat */
3093c84f3f3cSopenharmony_ci			goto x_set_arg_too_big;
3094c84f3f3cSopenharmony_ci		c = x_e_getc();
3095c84f3f3cSopenharmony_ci		first = false;
3096c84f3f3cSopenharmony_ci	}
3097c84f3f3cSopenharmony_ci	if (c < 0 || first) {
3098c84f3f3cSopenharmony_ci x_set_arg_too_big:
3099c84f3f3cSopenharmony_ci		x_e_putc2(KSH_BEL);
3100c84f3f3cSopenharmony_ci		x_arg = 1;
3101c84f3f3cSopenharmony_ci		x_arg_defaulted = true;
3102c84f3f3cSopenharmony_ci	} else {
3103c84f3f3cSopenharmony_ci		x_e_ungetc(c);
3104c84f3f3cSopenharmony_ci		x_arg = n;
3105c84f3f3cSopenharmony_ci		x_arg_defaulted = false;
3106c84f3f3cSopenharmony_ci	}
3107c84f3f3cSopenharmony_ci	return (KSTD);
3108c84f3f3cSopenharmony_ci}
3109c84f3f3cSopenharmony_ci
3110c84f3f3cSopenharmony_ci/* Comment or uncomment the current line. */
3111c84f3f3cSopenharmony_cistatic int
3112c84f3f3cSopenharmony_cix_comment(int c MKSH_A_UNUSED)
3113c84f3f3cSopenharmony_ci{
3114c84f3f3cSopenharmony_ci	ssize_t len = xep - xbuf;
3115c84f3f3cSopenharmony_ci	int ret = x_do_comment(xbuf, xend - xbuf, &len);
3116c84f3f3cSopenharmony_ci
3117c84f3f3cSopenharmony_ci	if (ret < 0)
3118c84f3f3cSopenharmony_ci		x_e_putc2(KSH_BEL);
3119c84f3f3cSopenharmony_ci	else {
3120c84f3f3cSopenharmony_ci		x_modified();
3121c84f3f3cSopenharmony_ci		xep = xbuf + len;
3122c84f3f3cSopenharmony_ci		*xep = '\0';
3123c84f3f3cSopenharmony_ci		xcp = xbp = xbuf;
3124c84f3f3cSopenharmony_ci		x_redraw('\r');
3125c84f3f3cSopenharmony_ci		if (ret > 0)
3126c84f3f3cSopenharmony_ci			return (x_newline('\n'));
3127c84f3f3cSopenharmony_ci	}
3128c84f3f3cSopenharmony_ci	return (KSTD);
3129c84f3f3cSopenharmony_ci}
3130c84f3f3cSopenharmony_ci
3131c84f3f3cSopenharmony_cistatic int
3132c84f3f3cSopenharmony_cix_version(int c MKSH_A_UNUSED)
3133c84f3f3cSopenharmony_ci{
3134c84f3f3cSopenharmony_ci	char *o_xbuf = xbuf, *o_xend = xend;
3135c84f3f3cSopenharmony_ci	char *o_xbp = xbp, *o_xep = xep, *o_xcp = xcp;
3136c84f3f3cSopenharmony_ci	char *v;
3137c84f3f3cSopenharmony_ci
3138c84f3f3cSopenharmony_ci	strdupx(v, KSH_VERSION, ATEMP);
3139c84f3f3cSopenharmony_ci
3140c84f3f3cSopenharmony_ci	xbuf = xbp = xcp = v;
3141c84f3f3cSopenharmony_ci	xend = xep = strnul(v);
3142c84f3f3cSopenharmony_ci	x_redraw('\r');
3143c84f3f3cSopenharmony_ci	x_flush();
3144c84f3f3cSopenharmony_ci
3145c84f3f3cSopenharmony_ci	c = x_e_getc();
3146c84f3f3cSopenharmony_ci	xbuf = o_xbuf;
3147c84f3f3cSopenharmony_ci	xend = o_xend;
3148c84f3f3cSopenharmony_ci	xbp = o_xbp;
3149c84f3f3cSopenharmony_ci	xep = o_xep;
3150c84f3f3cSopenharmony_ci	xcp = o_xcp;
3151c84f3f3cSopenharmony_ci	x_redraw('\r');
3152c84f3f3cSopenharmony_ci
3153c84f3f3cSopenharmony_ci	if (c < 0)
3154c84f3f3cSopenharmony_ci		return (KSTD);
3155c84f3f3cSopenharmony_ci	/* This is what AT&T ksh seems to do... Very bizarre */
3156c84f3f3cSopenharmony_ci	if (c != ' ')
3157c84f3f3cSopenharmony_ci		x_e_ungetc(c);
3158c84f3f3cSopenharmony_ci
3159c84f3f3cSopenharmony_ci	afree(v, ATEMP);
3160c84f3f3cSopenharmony_ci	return (KSTD);
3161c84f3f3cSopenharmony_ci}
3162c84f3f3cSopenharmony_ci
3163c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
3164c84f3f3cSopenharmony_cistatic int
3165c84f3f3cSopenharmony_cix_edit_line(int c MKSH_A_UNUSED)
3166c84f3f3cSopenharmony_ci{
3167c84f3f3cSopenharmony_ci	if (x_arg_defaulted) {
3168c84f3f3cSopenharmony_ci		if (modified) {
3169c84f3f3cSopenharmony_ci			*xep = '\0';
3170c84f3f3cSopenharmony_ci			histsave(&source->line, xbuf, HIST_STORE, true);
3171c84f3f3cSopenharmony_ci			x_arg = 0;
3172c84f3f3cSopenharmony_ci		} else
3173c84f3f3cSopenharmony_ci			x_arg = source->line - (histptr - x_histp);
3174c84f3f3cSopenharmony_ci	}
3175c84f3f3cSopenharmony_ci	if (x_arg)
3176c84f3f3cSopenharmony_ci		shf_snprintf(xbuf, xend - xbuf, Tf_sd, ctrl_x_e, x_arg);
3177c84f3f3cSopenharmony_ci	else
3178c84f3f3cSopenharmony_ci		strlcpy(xbuf, ctrl_x_e, xend - xbuf);
3179c84f3f3cSopenharmony_ci	xep = strnul(xbuf);
3180c84f3f3cSopenharmony_ci	return (x_newline('\n'));
3181c84f3f3cSopenharmony_ci}
3182c84f3f3cSopenharmony_ci#endif
3183c84f3f3cSopenharmony_ci
3184c84f3f3cSopenharmony_ci/*-
3185c84f3f3cSopenharmony_ci * NAME:
3186c84f3f3cSopenharmony_ci *	x_prev_histword - recover word from prev command
3187c84f3f3cSopenharmony_ci *
3188c84f3f3cSopenharmony_ci * DESCRIPTION:
3189c84f3f3cSopenharmony_ci *	This function recovers the last word from the previous
3190c84f3f3cSopenharmony_ci *	command and inserts it into the current edit line. If a
3191c84f3f3cSopenharmony_ci *	numeric arg is supplied then the n'th word from the
3192c84f3f3cSopenharmony_ci *	start of the previous command is used.
3193c84f3f3cSopenharmony_ci *	As a side effect, trashes the mark in order to achieve
3194c84f3f3cSopenharmony_ci *	being called in a repeatable fashion.
3195c84f3f3cSopenharmony_ci *
3196c84f3f3cSopenharmony_ci *	Bound to M-.
3197c84f3f3cSopenharmony_ci *
3198c84f3f3cSopenharmony_ci * RETURN VALUE:
3199c84f3f3cSopenharmony_ci *	KSTD
3200c84f3f3cSopenharmony_ci */
3201c84f3f3cSopenharmony_cistatic int
3202c84f3f3cSopenharmony_cix_prev_histword(int c MKSH_A_UNUSED)
3203c84f3f3cSopenharmony_ci{
3204c84f3f3cSopenharmony_ci	char *rcp, *cp;
3205c84f3f3cSopenharmony_ci	char **xhp;
3206c84f3f3cSopenharmony_ci	int m = 1;
3207c84f3f3cSopenharmony_ci	/* -1 = defaulted; 0+ = argument */
3208c84f3f3cSopenharmony_ci	static int last_arg = -1;
3209c84f3f3cSopenharmony_ci
3210c84f3f3cSopenharmony_ci	if (x_last_command == XFUNC_prev_histword) {
3211c84f3f3cSopenharmony_ci		if (xmp && modified > 1)
3212c84f3f3cSopenharmony_ci			x_kill_region(0);
3213c84f3f3cSopenharmony_ci		if (modified)
3214c84f3f3cSopenharmony_ci			m = modified;
3215c84f3f3cSopenharmony_ci	} else
3216c84f3f3cSopenharmony_ci		last_arg = x_arg_defaulted ? -1 : x_arg;
3217c84f3f3cSopenharmony_ci	xhp = histptr - (m - 1);
3218c84f3f3cSopenharmony_ci	if ((xhp < history) || !(cp = *xhp)) {
3219c84f3f3cSopenharmony_ci		x_e_putc2(KSH_BEL);
3220c84f3f3cSopenharmony_ci		x_modified();
3221c84f3f3cSopenharmony_ci		return (KSTD);
3222c84f3f3cSopenharmony_ci	}
3223c84f3f3cSopenharmony_ci	x_set_mark(0);
3224c84f3f3cSopenharmony_ci	if ((x_arg = last_arg) == -1) {
3225c84f3f3cSopenharmony_ci		/* x_arg_defaulted */
3226c84f3f3cSopenharmony_ci
3227c84f3f3cSopenharmony_ci		rcp = &cp[strlen(cp) - 1];
3228c84f3f3cSopenharmony_ci		/*
3229c84f3f3cSopenharmony_ci		 * ignore white-space after the last word
3230c84f3f3cSopenharmony_ci		 */
3231c84f3f3cSopenharmony_ci		while (rcp > cp && ctype(*rcp, C_CFS))
3232c84f3f3cSopenharmony_ci			rcp--;
3233c84f3f3cSopenharmony_ci		while (rcp > cp && !ctype(*rcp, C_CFS))
3234c84f3f3cSopenharmony_ci			rcp--;
3235c84f3f3cSopenharmony_ci		if (ctype(*rcp, C_CFS))
3236c84f3f3cSopenharmony_ci			rcp++;
3237c84f3f3cSopenharmony_ci		x_ins(rcp);
3238c84f3f3cSopenharmony_ci	} else {
3239c84f3f3cSopenharmony_ci		/* not x_arg_defaulted */
3240c84f3f3cSopenharmony_ci		char ch;
3241c84f3f3cSopenharmony_ci
3242c84f3f3cSopenharmony_ci		rcp = cp;
3243c84f3f3cSopenharmony_ci		/*
3244c84f3f3cSopenharmony_ci		 * ignore white-space at start of line
3245c84f3f3cSopenharmony_ci		 */
3246c84f3f3cSopenharmony_ci		while (*rcp && ctype(*rcp, C_CFS))
3247c84f3f3cSopenharmony_ci			rcp++;
3248c84f3f3cSopenharmony_ci		while (x_arg-- > 0) {
3249c84f3f3cSopenharmony_ci			while (*rcp && !ctype(*rcp, C_CFS))
3250c84f3f3cSopenharmony_ci				rcp++;
3251c84f3f3cSopenharmony_ci			while (*rcp && ctype(*rcp, C_CFS))
3252c84f3f3cSopenharmony_ci				rcp++;
3253c84f3f3cSopenharmony_ci		}
3254c84f3f3cSopenharmony_ci		cp = rcp;
3255c84f3f3cSopenharmony_ci		while (*rcp && !ctype(*rcp, C_CFS))
3256c84f3f3cSopenharmony_ci			rcp++;
3257c84f3f3cSopenharmony_ci		ch = *rcp;
3258c84f3f3cSopenharmony_ci		*rcp = '\0';
3259c84f3f3cSopenharmony_ci		x_ins(cp);
3260c84f3f3cSopenharmony_ci		*rcp = ch;
3261c84f3f3cSopenharmony_ci	}
3262c84f3f3cSopenharmony_ci	if (!modified)
3263c84f3f3cSopenharmony_ci		x_histmcp = x_histp;
3264c84f3f3cSopenharmony_ci	modified = m + 1;
3265c84f3f3cSopenharmony_ci	return (KSTD);
3266c84f3f3cSopenharmony_ci}
3267c84f3f3cSopenharmony_ci
3268c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
3269c84f3f3cSopenharmony_ci/* Uppercase N(1) words */
3270c84f3f3cSopenharmony_cistatic int
3271c84f3f3cSopenharmony_cix_fold_upper(int c MKSH_A_UNUSED)
3272c84f3f3cSopenharmony_ci{
3273c84f3f3cSopenharmony_ci	return (x_fold_case('U'));
3274c84f3f3cSopenharmony_ci}
3275c84f3f3cSopenharmony_ci
3276c84f3f3cSopenharmony_ci/* Lowercase N(1) words */
3277c84f3f3cSopenharmony_cistatic int
3278c84f3f3cSopenharmony_cix_fold_lower(int c MKSH_A_UNUSED)
3279c84f3f3cSopenharmony_ci{
3280c84f3f3cSopenharmony_ci	return (x_fold_case('L'));
3281c84f3f3cSopenharmony_ci}
3282c84f3f3cSopenharmony_ci
3283c84f3f3cSopenharmony_ci/* Titlecase N(1) words */
3284c84f3f3cSopenharmony_cistatic int
3285c84f3f3cSopenharmony_cix_fold_capitalise(int c MKSH_A_UNUSED)
3286c84f3f3cSopenharmony_ci{
3287c84f3f3cSopenharmony_ci	return (x_fold_case('C'));
3288c84f3f3cSopenharmony_ci}
3289c84f3f3cSopenharmony_ci
3290c84f3f3cSopenharmony_ci/*-
3291c84f3f3cSopenharmony_ci * NAME:
3292c84f3f3cSopenharmony_ci *	x_fold_case - convert word to UPPER/lower/Capital case
3293c84f3f3cSopenharmony_ci *
3294c84f3f3cSopenharmony_ci * DESCRIPTION:
3295c84f3f3cSopenharmony_ci *	This function is used to implement M-U/M-u, M-L/M-l, M-C/M-c
3296c84f3f3cSopenharmony_ci *	to UPPER CASE, lower case or Capitalise Words.
3297c84f3f3cSopenharmony_ci *
3298c84f3f3cSopenharmony_ci * RETURN VALUE:
3299c84f3f3cSopenharmony_ci *	None
3300c84f3f3cSopenharmony_ci */
3301c84f3f3cSopenharmony_cistatic int
3302c84f3f3cSopenharmony_cix_fold_case(int c)
3303c84f3f3cSopenharmony_ci{
3304c84f3f3cSopenharmony_ci	char *cp = xcp;
3305c84f3f3cSopenharmony_ci
3306c84f3f3cSopenharmony_ci	if (cp == xep) {
3307c84f3f3cSopenharmony_ci		x_e_putc2(KSH_BEL);
3308c84f3f3cSopenharmony_ci		return (KSTD);
3309c84f3f3cSopenharmony_ci	}
3310c84f3f3cSopenharmony_ci	while (x_arg--) {
3311c84f3f3cSopenharmony_ci		/*
3312c84f3f3cSopenharmony_ci		 * first skip over any white-space
3313c84f3f3cSopenharmony_ci		 */
3314c84f3f3cSopenharmony_ci		while (cp != xep && ctype(*cp, C_MFS))
3315c84f3f3cSopenharmony_ci			cp++;
3316c84f3f3cSopenharmony_ci		/*
3317c84f3f3cSopenharmony_ci		 * do the first char on its own since it may be
3318c84f3f3cSopenharmony_ci		 * a different action than for the rest.
3319c84f3f3cSopenharmony_ci		 */
3320c84f3f3cSopenharmony_ci		if (cp != xep) {
3321c84f3f3cSopenharmony_ci			if (c == 'L')
3322c84f3f3cSopenharmony_ci				/* lowercase */
3323c84f3f3cSopenharmony_ci				*cp = ksh_tolower(*cp);
3324c84f3f3cSopenharmony_ci			else
3325c84f3f3cSopenharmony_ci				/* uppercase, capitalise */
3326c84f3f3cSopenharmony_ci				*cp = ksh_toupper(*cp);
3327c84f3f3cSopenharmony_ci			cp++;
3328c84f3f3cSopenharmony_ci		}
3329c84f3f3cSopenharmony_ci		/*
3330c84f3f3cSopenharmony_ci		 * now for the rest of the word
3331c84f3f3cSopenharmony_ci		 */
3332c84f3f3cSopenharmony_ci		while (cp != xep && !ctype(*cp, C_MFS)) {
3333c84f3f3cSopenharmony_ci			if (c == 'U')
3334c84f3f3cSopenharmony_ci				/* uppercase */
3335c84f3f3cSopenharmony_ci				*cp = ksh_toupper(*cp);
3336c84f3f3cSopenharmony_ci			else
3337c84f3f3cSopenharmony_ci				/* lowercase, capitalise */
3338c84f3f3cSopenharmony_ci				*cp = ksh_tolower(*cp);
3339c84f3f3cSopenharmony_ci			cp++;
3340c84f3f3cSopenharmony_ci		}
3341c84f3f3cSopenharmony_ci	}
3342c84f3f3cSopenharmony_ci	x_goto(cp);
3343c84f3f3cSopenharmony_ci	x_modified();
3344c84f3f3cSopenharmony_ci	return (KSTD);
3345c84f3f3cSopenharmony_ci}
3346c84f3f3cSopenharmony_ci#endif
3347c84f3f3cSopenharmony_ci
3348c84f3f3cSopenharmony_ci/*-
3349c84f3f3cSopenharmony_ci * NAME:
3350c84f3f3cSopenharmony_ci *	x_lastcp - last visible char
3351c84f3f3cSopenharmony_ci *
3352c84f3f3cSopenharmony_ci * DESCRIPTION:
3353c84f3f3cSopenharmony_ci *	This function returns a pointer to that char in the
3354c84f3f3cSopenharmony_ci *	edit buffer that will be the last displayed on the
3355c84f3f3cSopenharmony_ci *	screen.
3356c84f3f3cSopenharmony_ci */
3357c84f3f3cSopenharmony_cistatic char *
3358c84f3f3cSopenharmony_cix_lastcp(void)
3359c84f3f3cSopenharmony_ci{
3360c84f3f3cSopenharmony_ci	if (!xlp_valid) {
3361c84f3f3cSopenharmony_ci		int i = 0, j;
3362c84f3f3cSopenharmony_ci		char *xlp2;
3363c84f3f3cSopenharmony_ci
3364c84f3f3cSopenharmony_ci		xlp = xbp;
3365c84f3f3cSopenharmony_ci		while (xlp < xep) {
3366c84f3f3cSopenharmony_ci			j = x_size2(xlp, &xlp2);
3367c84f3f3cSopenharmony_ci			if ((i + j) > x_displen)
3368c84f3f3cSopenharmony_ci				break;
3369c84f3f3cSopenharmony_ci			i += j;
3370c84f3f3cSopenharmony_ci			xlp = xlp2;
3371c84f3f3cSopenharmony_ci		}
3372c84f3f3cSopenharmony_ci	}
3373c84f3f3cSopenharmony_ci	xlp_valid = true;
3374c84f3f3cSopenharmony_ci	return (xlp);
3375c84f3f3cSopenharmony_ci}
3376c84f3f3cSopenharmony_ci
3377c84f3f3cSopenharmony_ci/* correctly position the cursor on the screen from end of visible area */
3378c84f3f3cSopenharmony_cistatic void
3379c84f3f3cSopenharmony_cix_lastpos(void)
3380c84f3f3cSopenharmony_ci{
3381c84f3f3cSopenharmony_ci	char *cp = x_lastcp();
3382c84f3f3cSopenharmony_ci
3383c84f3f3cSopenharmony_ci	while (cp > xcp)
3384c84f3f3cSopenharmony_ci		x_bs3(&cp);
3385c84f3f3cSopenharmony_ci}
3386c84f3f3cSopenharmony_ci
3387c84f3f3cSopenharmony_cistatic void
3388c84f3f3cSopenharmony_cix_mode(bool onoff)
3389c84f3f3cSopenharmony_ci{
3390c84f3f3cSopenharmony_ci	static bool x_cur_mode;
3391c84f3f3cSopenharmony_ci
3392c84f3f3cSopenharmony_ci	if (x_cur_mode == onoff)
3393c84f3f3cSopenharmony_ci		return;
3394c84f3f3cSopenharmony_ci	x_cur_mode = onoff;
3395c84f3f3cSopenharmony_ci
3396c84f3f3cSopenharmony_ci	if (onoff) {
3397c84f3f3cSopenharmony_ci		x_mkraw(tty_fd, NULL, false);
3398c84f3f3cSopenharmony_ci
3399c84f3f3cSopenharmony_ci		edchars.erase = toedchar(tty_state.c_cc[VERASE]);
3400c84f3f3cSopenharmony_ci		edchars.kill = toedchar(tty_state.c_cc[VKILL]);
3401c84f3f3cSopenharmony_ci		edchars.intr = toedchar(tty_state.c_cc[VINTR]);
3402c84f3f3cSopenharmony_ci		edchars.quit = toedchar(tty_state.c_cc[VQUIT]);
3403c84f3f3cSopenharmony_ci		edchars.eof = toedchar(tty_state.c_cc[VEOF]);
3404c84f3f3cSopenharmony_ci#ifdef VWERASE
3405c84f3f3cSopenharmony_ci		edchars.werase = toedchar(tty_state.c_cc[VWERASE]);
3406c84f3f3cSopenharmony_ci#else
3407c84f3f3cSopenharmony_ci		edchars.werase = 0;
3408c84f3f3cSopenharmony_ci#endif
3409c84f3f3cSopenharmony_ci
3410c84f3f3cSopenharmony_ci		if (!edchars.erase)
3411c84f3f3cSopenharmony_ci			edchars.erase = CTRL_H;
3412c84f3f3cSopenharmony_ci		if (!edchars.kill)
3413c84f3f3cSopenharmony_ci			edchars.kill = CTRL_U;
3414c84f3f3cSopenharmony_ci		if (!edchars.intr)
3415c84f3f3cSopenharmony_ci			edchars.intr = CTRL_C;
3416c84f3f3cSopenharmony_ci		if (!edchars.quit)
3417c84f3f3cSopenharmony_ci			edchars.quit = CTRL_BK;
3418c84f3f3cSopenharmony_ci		if (!edchars.eof)
3419c84f3f3cSopenharmony_ci			edchars.eof = CTRL_D;
3420c84f3f3cSopenharmony_ci		if (!edchars.werase)
3421c84f3f3cSopenharmony_ci			edchars.werase = CTRL_W;
3422c84f3f3cSopenharmony_ci
3423c84f3f3cSopenharmony_ci		if (isedchar(edchars.erase)) {
3424c84f3f3cSopenharmony_ci			bind_if_not_bound(0, edchars.erase, XFUNC_del_back);
3425c84f3f3cSopenharmony_ci			bind_if_not_bound(1, edchars.erase, XFUNC_del_bword);
3426c84f3f3cSopenharmony_ci		}
3427c84f3f3cSopenharmony_ci		if (isedchar(edchars.kill))
3428c84f3f3cSopenharmony_ci			bind_if_not_bound(0, edchars.kill, XFUNC_del_line);
3429c84f3f3cSopenharmony_ci		if (isedchar(edchars.werase))
3430c84f3f3cSopenharmony_ci			bind_if_not_bound(0, edchars.werase, XFUNC_del_bword);
3431c84f3f3cSopenharmony_ci		if (isedchar(edchars.intr))
3432c84f3f3cSopenharmony_ci			bind_if_not_bound(0, edchars.intr, XFUNC_abort);
3433c84f3f3cSopenharmony_ci		if (isedchar(edchars.quit))
3434c84f3f3cSopenharmony_ci			bind_if_not_bound(0, edchars.quit, XFUNC_noop);
3435c84f3f3cSopenharmony_ci	} else
3436c84f3f3cSopenharmony_ci		mksh_tcset(tty_fd, &tty_state);
3437c84f3f3cSopenharmony_ci}
3438c84f3f3cSopenharmony_ci
3439c84f3f3cSopenharmony_ci#if !MKSH_S_NOVI
3440c84f3f3cSopenharmony_ci/* +++ vi editing mode +++ */
3441c84f3f3cSopenharmony_ci
3442c84f3f3cSopenharmony_cistruct edstate {
3443c84f3f3cSopenharmony_ci	char *cbuf;
3444c84f3f3cSopenharmony_ci	ssize_t winleft;
3445c84f3f3cSopenharmony_ci	ssize_t cbufsize;
3446c84f3f3cSopenharmony_ci	ssize_t linelen;
3447c84f3f3cSopenharmony_ci	ssize_t cursor;
3448c84f3f3cSopenharmony_ci};
3449c84f3f3cSopenharmony_ci
3450c84f3f3cSopenharmony_cistatic int vi_hook(int);
3451c84f3f3cSopenharmony_cistatic int nextstate(int);
3452c84f3f3cSopenharmony_cistatic int vi_insert(int);
3453c84f3f3cSopenharmony_cistatic int vi_cmd(int, const char *);
3454c84f3f3cSopenharmony_cistatic int domove(int, const char *, int);
3455c84f3f3cSopenharmony_cistatic int domovebeg(void);
3456c84f3f3cSopenharmony_cistatic int redo_insert(int);
3457c84f3f3cSopenharmony_cistatic void yank_range(int, int);
3458c84f3f3cSopenharmony_cistatic int bracktype(int);
3459c84f3f3cSopenharmony_cistatic void save_cbuf(void);
3460c84f3f3cSopenharmony_cistatic void restore_cbuf(void);
3461c84f3f3cSopenharmony_cistatic int putbuf(const char *, ssize_t, bool);
3462c84f3f3cSopenharmony_cistatic void del_range(int, int);
3463c84f3f3cSopenharmony_cistatic int findch(int, int, bool, bool) MKSH_A_PURE;
3464c84f3f3cSopenharmony_cistatic int forwword(int);
3465c84f3f3cSopenharmony_cistatic int backword(int);
3466c84f3f3cSopenharmony_cistatic int endword(int);
3467c84f3f3cSopenharmony_cistatic int Forwword(int);
3468c84f3f3cSopenharmony_cistatic int Backword(int);
3469c84f3f3cSopenharmony_cistatic int Endword(int);
3470c84f3f3cSopenharmony_cistatic int grabhist(int, int);
3471c84f3f3cSopenharmony_cistatic int grabsearch(const char *, int, int, bool);
3472c84f3f3cSopenharmony_cistatic void redraw_line(bool);
3473c84f3f3cSopenharmony_cistatic void refresh(bool);
3474c84f3f3cSopenharmony_cistatic int outofwin(void);
3475c84f3f3cSopenharmony_cistatic void rewindow(void);
3476c84f3f3cSopenharmony_cistatic int newcol(unsigned char, int);
3477c84f3f3cSopenharmony_cistatic void display(char *, char *, bool);
3478c84f3f3cSopenharmony_cistatic void ed_mov_opt(int, char *);
3479c84f3f3cSopenharmony_cistatic int expand_word(int);
3480c84f3f3cSopenharmony_cistatic int complete_word(int, int);
3481c84f3f3cSopenharmony_cistatic int print_expansions(struct edstate *, int);
3482c84f3f3cSopenharmony_cistatic void vi_error(void);
3483c84f3f3cSopenharmony_cistatic void vi_macro_reset(void);
3484c84f3f3cSopenharmony_cistatic int x_vi_putbuf(const char *, size_t);
3485c84f3f3cSopenharmony_ci#define char_len(c) (ksh_isctrl(c) ? 2 : 1)
3486c84f3f3cSopenharmony_ci
3487c84f3f3cSopenharmony_ci#define vC	0x01		/* a valid command that isn't a vM, vE, vU */
3488c84f3f3cSopenharmony_ci#define vM	0x02		/* movement command (h, l, etc.) */
3489c84f3f3cSopenharmony_ci#define vE	0x04		/* extended command (c, d, y) */
3490c84f3f3cSopenharmony_ci#define vX	0x08		/* long command (@, f, F, t, T, etc.) */
3491c84f3f3cSopenharmony_ci#define vU	0x10		/* an UN-undoable command (that isn't a vM) */
3492c84f3f3cSopenharmony_ci#define vB	0x20		/* bad command (^@) */
3493c84f3f3cSopenharmony_ci#define vZ	0x40		/* repeat count defaults to 0 (not 1) */
3494c84f3f3cSopenharmony_ci#define vS	0x80		/* search (/, ?) */
3495c84f3f3cSopenharmony_ci
3496c84f3f3cSopenharmony_ci#define is_bad(c)	(classify[rtt2asc(c) & 0x7F] & vB)
3497c84f3f3cSopenharmony_ci#define is_cmd(c)	(classify[rtt2asc(c) & 0x7F] & (vM | vE | vC | vU))
3498c84f3f3cSopenharmony_ci#define is_move(c)	(classify[rtt2asc(c) & 0x7F] & vM)
3499c84f3f3cSopenharmony_ci#define is_extend(c)	(classify[rtt2asc(c) & 0x7F] & vE)
3500c84f3f3cSopenharmony_ci#define is_long(c)	(classify[rtt2asc(c) & 0x7F] & vX)
3501c84f3f3cSopenharmony_ci#define is_undoable(c)	(!(classify[rtt2asc(c) & 0x7F] & vU))
3502c84f3f3cSopenharmony_ci#define is_srch(c)	(classify[rtt2asc(c) & 0x7F] & vS)
3503c84f3f3cSopenharmony_ci#define is_zerocount(c)	(classify[rtt2asc(c) & 0x7F] & vZ)
3504c84f3f3cSopenharmony_ci
3505c84f3f3cSopenharmony_cistatic const unsigned char classify[128] = {
3506c84f3f3cSopenharmony_ci/*	 0	1	2	3	4	5	6	7	*/
3507c84f3f3cSopenharmony_ci/* 0	^@	^A	^B	^C	^D	^E	^F	^G	*/
3508c84f3f3cSopenharmony_ci	vB,	0,	0,	0,	0,	vC|vU,	vC|vZ,	0,
3509c84f3f3cSopenharmony_ci/* 1	^H	^I	^J	^K	^L	^M	^N	^O	*/
3510c84f3f3cSopenharmony_ci	vM,	vC|vZ,	0,	0,	vC|vU,	0,	vC,	0,
3511c84f3f3cSopenharmony_ci/* 2	^P	^Q	^R	^S	^T	^U	^V	^W	*/
3512c84f3f3cSopenharmony_ci	vC,	0,	vC|vU,	0,	0,	0,	vC,	0,
3513c84f3f3cSopenharmony_ci/* 3	^X	^Y	^Z	^[	^\	^]	^^	^_	*/
3514c84f3f3cSopenharmony_ci	vC,	0,	0,	vC|vZ,	0,	0,	0,	0,
3515c84f3f3cSopenharmony_ci/* 4	<space>	!	"	#	$	%	&	'	*/
3516c84f3f3cSopenharmony_ci	vM,	0,	0,	vC,	vM,	vM,	0,	0,
3517c84f3f3cSopenharmony_ci/* 5	(	)	*	+	,	-	.	/	*/
3518c84f3f3cSopenharmony_ci	0,	0,	vC,	vC,	vM,	vC,	0,	vC|vS,
3519c84f3f3cSopenharmony_ci/* 6	0	1	2	3	4	5	6	7	*/
3520c84f3f3cSopenharmony_ci	vM,	0,	0,	0,	0,	0,	0,	0,
3521c84f3f3cSopenharmony_ci/* 7	8	9	:	;	<	=	>	?	*/
3522c84f3f3cSopenharmony_ci	0,	0,	0,	vM,	0,	vC,	0,	vC|vS,
3523c84f3f3cSopenharmony_ci/* 8	@	A	B	C	D	E	F	G	*/
3524c84f3f3cSopenharmony_ci	vC|vX,	vC,	vM,	vC,	vC,	vM,	vM|vX,	vC|vU|vZ,
3525c84f3f3cSopenharmony_ci/* 9	H	I	J	K	L	M	N	O	*/
3526c84f3f3cSopenharmony_ci	0,	vC,	0,	0,	0,	0,	vC|vU,	vU,
3527c84f3f3cSopenharmony_ci/* A	P	Q	R	S	T	U	V	W	*/
3528c84f3f3cSopenharmony_ci	vC,	0,	vC,	vC,	vM|vX,	vC,	0,	vM,
3529c84f3f3cSopenharmony_ci/* B	X	Y	Z	[	\	]	^	_	*/
3530c84f3f3cSopenharmony_ci	vC,	vC|vU,	0,	vU,	vC|vZ,	0,	vM,	vC|vZ,
3531c84f3f3cSopenharmony_ci/* C	`	a	b	c	d	e	f	g	*/
3532c84f3f3cSopenharmony_ci	0,	vC,	vM,	vE,	vE,	vM,	vM|vX,	vC|vZ,
3533c84f3f3cSopenharmony_ci/* D	h	i	j	k	l	m	n	o	*/
3534c84f3f3cSopenharmony_ci	vM,	vC,	vC|vU,	vC|vU,	vM,	0,	vC|vU,	0,
3535c84f3f3cSopenharmony_ci/* E	p	q	r	s	t	u	v	w	*/
3536c84f3f3cSopenharmony_ci	vC,	0,	vX,	vC,	vM|vX,	vC|vU,	vC|vU|vZ, vM,
3537c84f3f3cSopenharmony_ci/* F	x	y	z	{	|	}	~	^?	*/
3538c84f3f3cSopenharmony_ci	vC,	vE|vU,	0,	0,	vM|vZ,	0,	vC,	0
3539c84f3f3cSopenharmony_ci};
3540c84f3f3cSopenharmony_ci
3541c84f3f3cSopenharmony_ci#define MAXVICMD	3
3542c84f3f3cSopenharmony_ci#define SRCHLEN		40
3543c84f3f3cSopenharmony_ci
3544c84f3f3cSopenharmony_ci#define INSERT		1
3545c84f3f3cSopenharmony_ci#define REPLACE		2
3546c84f3f3cSopenharmony_ci
3547c84f3f3cSopenharmony_ci#define VNORMAL		0		/* command, insert or replace mode */
3548c84f3f3cSopenharmony_ci#define VARG1		1		/* digit prefix (first, eg, 5l) */
3549c84f3f3cSopenharmony_ci#define VEXTCMD		2		/* cmd + movement (eg, cl) */
3550c84f3f3cSopenharmony_ci#define VARG2		3		/* digit prefix (second, eg, 2c3l) */
3551c84f3f3cSopenharmony_ci#define VXCH		4		/* f, F, t, T, @ */
3552c84f3f3cSopenharmony_ci#define VFAIL		5		/* bad command */
3553c84f3f3cSopenharmony_ci#define VCMD		6		/* single char command (eg, X) */
3554c84f3f3cSopenharmony_ci#define VREDO		7		/* . */
3555c84f3f3cSopenharmony_ci#define VLIT		8		/* ^V */
3556c84f3f3cSopenharmony_ci#define VSEARCH		9		/* /, ? */
3557c84f3f3cSopenharmony_ci#define VVERSION	10		/* <ESC> ^V */
3558c84f3f3cSopenharmony_ci#define VPREFIX2	11		/* ^[[ and ^[O in insert mode */
3559c84f3f3cSopenharmony_ci
3560c84f3f3cSopenharmony_cistatic struct edstate	*save_edstate(struct edstate *old);
3561c84f3f3cSopenharmony_cistatic void		restore_edstate(struct edstate *old, struct edstate *news);
3562c84f3f3cSopenharmony_cistatic void		free_edstate(struct edstate *old);
3563c84f3f3cSopenharmony_ci
3564c84f3f3cSopenharmony_cistatic struct edstate	ebuf;
3565c84f3f3cSopenharmony_cistatic struct edstate	undobuf;
3566c84f3f3cSopenharmony_ci
3567c84f3f3cSopenharmony_cistatic struct edstate	*vs;		/* current Vi editing mode state */
3568c84f3f3cSopenharmony_cistatic struct edstate	*undo;
3569c84f3f3cSopenharmony_ci
3570c84f3f3cSopenharmony_cistatic char *ibuf;			/* input buffer */
3571c84f3f3cSopenharmony_cistatic bool first_insert;		/* set when starting in insert mode */
3572c84f3f3cSopenharmony_cistatic int saved_inslen;		/* saved inslen for first insert */
3573c84f3f3cSopenharmony_cistatic int inslen;			/* length of input buffer */
3574c84f3f3cSopenharmony_cistatic int srchlen;			/* length of current search pattern */
3575c84f3f3cSopenharmony_cistatic char *ybuf;			/* yank buffer */
3576c84f3f3cSopenharmony_cistatic int yanklen;			/* length of yank buffer */
3577c84f3f3cSopenharmony_cistatic uint8_t fsavecmd = ORD(' ');	/* last find command */
3578c84f3f3cSopenharmony_cistatic int fsavech;			/* character to find */
3579c84f3f3cSopenharmony_cistatic char lastcmd[MAXVICMD];		/* last non-move command */
3580c84f3f3cSopenharmony_cistatic int lastac;			/* argcnt for lastcmd */
3581c84f3f3cSopenharmony_cistatic uint8_t lastsearch = ORD(' ');	/* last search command */
3582c84f3f3cSopenharmony_cistatic char srchpat[SRCHLEN];		/* last search pattern */
3583c84f3f3cSopenharmony_cistatic int insert;			/* <>0 in insert mode */
3584c84f3f3cSopenharmony_cistatic int hnum;			/* position in history */
3585c84f3f3cSopenharmony_cistatic int ohnum;			/* history line copied (after mod) */
3586c84f3f3cSopenharmony_cistatic int hlast;			/* 1 past last position in history */
3587c84f3f3cSopenharmony_cistatic int state;
3588c84f3f3cSopenharmony_ci
3589c84f3f3cSopenharmony_ci/*
3590c84f3f3cSopenharmony_ci * Information for keeping track of macros that are being expanded.
3591c84f3f3cSopenharmony_ci * The format of buf is the alias contents followed by a NUL byte followed
3592c84f3f3cSopenharmony_ci * by the name (letter) of the alias. The end of the buffer is marked by
3593c84f3f3cSopenharmony_ci * a double NUL. The name of the alias is stored so recursive macros can
3594c84f3f3cSopenharmony_ci * be detected.
3595c84f3f3cSopenharmony_ci */
3596c84f3f3cSopenharmony_cistruct macro_state {
3597c84f3f3cSopenharmony_ci	unsigned char *p;	/* current position in buf */
3598c84f3f3cSopenharmony_ci	unsigned char *buf;	/* pointer to macro(s) being expanded */
3599c84f3f3cSopenharmony_ci	size_t len;		/* how much data in buffer */
3600c84f3f3cSopenharmony_ci};
3601c84f3f3cSopenharmony_cistatic struct macro_state macro;
3602c84f3f3cSopenharmony_ci
3603c84f3f3cSopenharmony_ci/* last input was expanded */
3604c84f3f3cSopenharmony_cistatic enum expand_mode {
3605c84f3f3cSopenharmony_ci	NONE = 0, EXPAND, COMPLETE, PRINT
3606c84f3f3cSopenharmony_ci} expanded;
3607c84f3f3cSopenharmony_ci
3608c84f3f3cSopenharmony_cistatic int
3609c84f3f3cSopenharmony_cix_vi(char *buf)
3610c84f3f3cSopenharmony_ci{
3611c84f3f3cSopenharmony_ci	int c;
3612c84f3f3cSopenharmony_ci
3613c84f3f3cSopenharmony_ci	state = VNORMAL;
3614c84f3f3cSopenharmony_ci	ohnum = hnum = hlast = histnum(-1) + 1;
3615c84f3f3cSopenharmony_ci	insert = INSERT;
3616c84f3f3cSopenharmony_ci	saved_inslen = inslen;
3617c84f3f3cSopenharmony_ci	first_insert = true;
3618c84f3f3cSopenharmony_ci	inslen = 0;
3619c84f3f3cSopenharmony_ci	vi_macro_reset();
3620c84f3f3cSopenharmony_ci
3621c84f3f3cSopenharmony_ci	ebuf.cbuf = buf;
3622c84f3f3cSopenharmony_ci	if (undobuf.cbuf == NULL) {
3623c84f3f3cSopenharmony_ci		ibuf = alloc(LINE, AEDIT);
3624c84f3f3cSopenharmony_ci		ybuf = alloc(LINE, AEDIT);
3625c84f3f3cSopenharmony_ci		undobuf.cbuf = alloc(LINE, AEDIT);
3626c84f3f3cSopenharmony_ci	}
3627c84f3f3cSopenharmony_ci	undobuf.cbufsize = ebuf.cbufsize = LINE;
3628c84f3f3cSopenharmony_ci	undobuf.linelen = ebuf.linelen = 0;
3629c84f3f3cSopenharmony_ci	undobuf.cursor = ebuf.cursor = 0;
3630c84f3f3cSopenharmony_ci	undobuf.winleft = ebuf.winleft = 0;
3631c84f3f3cSopenharmony_ci	vs = &ebuf;
3632c84f3f3cSopenharmony_ci	undo = &undobuf;
3633c84f3f3cSopenharmony_ci
3634c84f3f3cSopenharmony_ci	x_init_prompt(true);
3635c84f3f3cSopenharmony_ci	x_col = pwidth;
3636c84f3f3cSopenharmony_ci
3637c84f3f3cSopenharmony_ci	if (wbuf_len != x_cols - 3 && ((wbuf_len = x_cols - 3))) {
3638c84f3f3cSopenharmony_ci		wbuf[0] = aresize(wbuf[0], wbuf_len, AEDIT);
3639c84f3f3cSopenharmony_ci		wbuf[1] = aresize(wbuf[1], wbuf_len, AEDIT);
3640c84f3f3cSopenharmony_ci	}
3641c84f3f3cSopenharmony_ci	if (wbuf_len) {
3642c84f3f3cSopenharmony_ci		memset(wbuf[0], ' ', wbuf_len);
3643c84f3f3cSopenharmony_ci		memset(wbuf[1], ' ', wbuf_len);
3644c84f3f3cSopenharmony_ci	}
3645c84f3f3cSopenharmony_ci	winwidth = x_cols - pwidth - 3;
3646c84f3f3cSopenharmony_ci	win = 0;
3647c84f3f3cSopenharmony_ci	morec = ' ';
3648c84f3f3cSopenharmony_ci	holdlen = 0;
3649c84f3f3cSopenharmony_ci
3650c84f3f3cSopenharmony_ci	editmode = 2;
3651c84f3f3cSopenharmony_ci	x_flush();
3652c84f3f3cSopenharmony_ci	while (/* CONSTCOND */ 1) {
3653c84f3f3cSopenharmony_ci		if (macro.p) {
3654c84f3f3cSopenharmony_ci			c = (unsigned char)*macro.p++;
3655c84f3f3cSopenharmony_ci			/* end of current macro? */
3656c84f3f3cSopenharmony_ci			if (!c) {
3657c84f3f3cSopenharmony_ci				/* more macros left to finish? */
3658c84f3f3cSopenharmony_ci				if (*macro.p++)
3659c84f3f3cSopenharmony_ci					continue;
3660c84f3f3cSopenharmony_ci				/* must be the end of all the macros */
3661c84f3f3cSopenharmony_ci				vi_macro_reset();
3662c84f3f3cSopenharmony_ci				c = x_getc();
3663c84f3f3cSopenharmony_ci			}
3664c84f3f3cSopenharmony_ci		} else
3665c84f3f3cSopenharmony_ci			c = x_getc();
3666c84f3f3cSopenharmony_ci
3667c84f3f3cSopenharmony_ci		if (c == -1)
3668c84f3f3cSopenharmony_ci			break;
3669c84f3f3cSopenharmony_ci		if (state != VLIT) {
3670c84f3f3cSopenharmony_ci			if (isched(c, edchars.intr) ||
3671c84f3f3cSopenharmony_ci			    isched(c, edchars.quit)) {
3672c84f3f3cSopenharmony_ci				/* shove input buffer away */
3673c84f3f3cSopenharmony_ci				xbuf = ebuf.cbuf;
3674c84f3f3cSopenharmony_ci				xep = xbuf;
3675c84f3f3cSopenharmony_ci				if (ebuf.linelen > 0)
3676c84f3f3cSopenharmony_ci					xep += ebuf.linelen;
3677c84f3f3cSopenharmony_ci				/* pretend we got an interrupt */
3678c84f3f3cSopenharmony_ci				x_intr(isched(c, edchars.intr) ?
3679c84f3f3cSopenharmony_ci				    SIGINT : SIGQUIT, c);
3680c84f3f3cSopenharmony_ci			} else if (isched(c, edchars.eof) &&
3681c84f3f3cSopenharmony_ci			    state != VVERSION) {
3682c84f3f3cSopenharmony_ci				if (vs->linelen == 0) {
3683c84f3f3cSopenharmony_ci					x_vi_zotc(c);
3684c84f3f3cSopenharmony_ci					c = -1;
3685c84f3f3cSopenharmony_ci					break;
3686c84f3f3cSopenharmony_ci				}
3687c84f3f3cSopenharmony_ci				continue;
3688c84f3f3cSopenharmony_ci			}
3689c84f3f3cSopenharmony_ci		}
3690c84f3f3cSopenharmony_ci		if (vi_hook(c))
3691c84f3f3cSopenharmony_ci			break;
3692c84f3f3cSopenharmony_ci		x_flush();
3693c84f3f3cSopenharmony_ci	}
3694c84f3f3cSopenharmony_ci
3695c84f3f3cSopenharmony_ci	x_putc('\r');
3696c84f3f3cSopenharmony_ci	x_putc('\n');
3697c84f3f3cSopenharmony_ci	x_flush();
3698c84f3f3cSopenharmony_ci
3699c84f3f3cSopenharmony_ci	if (c == -1 || (ssize_t)LINE <= vs->linelen)
3700c84f3f3cSopenharmony_ci		return (-1);
3701c84f3f3cSopenharmony_ci
3702c84f3f3cSopenharmony_ci	if (vs->cbuf != buf)
3703c84f3f3cSopenharmony_ci		memcpy(buf, vs->cbuf, vs->linelen);
3704c84f3f3cSopenharmony_ci
3705c84f3f3cSopenharmony_ci	buf[vs->linelen++] = '\n';
3706c84f3f3cSopenharmony_ci
3707c84f3f3cSopenharmony_ci	return (vs->linelen);
3708c84f3f3cSopenharmony_ci}
3709c84f3f3cSopenharmony_ci
3710c84f3f3cSopenharmony_cistatic int
3711c84f3f3cSopenharmony_civi_hook(int ch)
3712c84f3f3cSopenharmony_ci{
3713c84f3f3cSopenharmony_ci	static char curcmd[MAXVICMD], locpat[SRCHLEN];
3714c84f3f3cSopenharmony_ci	static int cmdlen, argc1, argc2;
3715c84f3f3cSopenharmony_ci
3716c84f3f3cSopenharmony_ci	switch (state) {
3717c84f3f3cSopenharmony_ci
3718c84f3f3cSopenharmony_ci	case VNORMAL:
3719c84f3f3cSopenharmony_ci		/* PC scancodes */
3720c84f3f3cSopenharmony_ci		if (!ch) {
3721c84f3f3cSopenharmony_ci			cmdlen = 0;
3722c84f3f3cSopenharmony_ci			switch (ch = x_getc()) {
3723c84f3f3cSopenharmony_ci			case 71: ch = ORD('0'); goto pseudo_vi_command;
3724c84f3f3cSopenharmony_ci			case 72: ch = ORD('k'); goto pseudo_vi_command;
3725c84f3f3cSopenharmony_ci			case 73: ch = ORD('A'); goto vi_xfunc_search;
3726c84f3f3cSopenharmony_ci			case 75: ch = ORD('h'); goto pseudo_vi_command;
3727c84f3f3cSopenharmony_ci			case 77: ch = ORD('l'); goto pseudo_vi_command;
3728c84f3f3cSopenharmony_ci			case 79: ch = ORD('$'); goto pseudo_vi_command;
3729c84f3f3cSopenharmony_ci			case 80: ch = ORD('j'); goto pseudo_vi_command;
3730c84f3f3cSopenharmony_ci			case 81: ch = ORD('B'); goto vi_xfunc_search;
3731c84f3f3cSopenharmony_ci			case 83: ch = ORD('x'); goto pseudo_vi_command;
3732c84f3f3cSopenharmony_ci			default: ch = 0; goto vi_insert_failed;
3733c84f3f3cSopenharmony_ci			}
3734c84f3f3cSopenharmony_ci		}
3735c84f3f3cSopenharmony_ci		if (insert != 0) {
3736c84f3f3cSopenharmony_ci			if (ch == CTRL_V) {
3737c84f3f3cSopenharmony_ci				state = VLIT;
3738c84f3f3cSopenharmony_ci				ch = ORD('^');
3739c84f3f3cSopenharmony_ci			}
3740c84f3f3cSopenharmony_ci			switch (vi_insert(ch)) {
3741c84f3f3cSopenharmony_ci			case -1:
3742c84f3f3cSopenharmony_ci vi_insert_failed:
3743c84f3f3cSopenharmony_ci				vi_error();
3744c84f3f3cSopenharmony_ci				state = VNORMAL;
3745c84f3f3cSopenharmony_ci				break;
3746c84f3f3cSopenharmony_ci			case 0:
3747c84f3f3cSopenharmony_ci				if (state == VLIT) {
3748c84f3f3cSopenharmony_ci					vs->cursor--;
3749c84f3f3cSopenharmony_ci					refresh(false);
3750c84f3f3cSopenharmony_ci				} else
3751c84f3f3cSopenharmony_ci					refresh(insert != 0);
3752c84f3f3cSopenharmony_ci				break;
3753c84f3f3cSopenharmony_ci			case 1:
3754c84f3f3cSopenharmony_ci				return (1);
3755c84f3f3cSopenharmony_ci			}
3756c84f3f3cSopenharmony_ci		} else {
3757c84f3f3cSopenharmony_ci			if (ctype(ch, C_CR | C_LF))
3758c84f3f3cSopenharmony_ci				return (1);
3759c84f3f3cSopenharmony_ci			cmdlen = 0;
3760c84f3f3cSopenharmony_ci			argc1 = 0;
3761c84f3f3cSopenharmony_ci			if (ctype(ch, C_DIGIT) && ord(ch) != ORD('0')) {
3762c84f3f3cSopenharmony_ci				argc1 = ksh_numdig(ch);
3763c84f3f3cSopenharmony_ci				state = VARG1;
3764c84f3f3cSopenharmony_ci			} else {
3765c84f3f3cSopenharmony_ci pseudo_vi_command:
3766c84f3f3cSopenharmony_ci				curcmd[cmdlen++] = ch;
3767c84f3f3cSopenharmony_ci				state = nextstate(ch);
3768c84f3f3cSopenharmony_ci				if (state == VSEARCH) {
3769c84f3f3cSopenharmony_ci					save_cbuf();
3770c84f3f3cSopenharmony_ci					vs->cursor = 0;
3771c84f3f3cSopenharmony_ci					vs->linelen = 0;
3772c84f3f3cSopenharmony_ci					if (putbuf(ord(ch) == ORD('/') ?
3773c84f3f3cSopenharmony_ci					    "/" : "?", 1, false) != 0)
3774c84f3f3cSopenharmony_ci						return (-1);
3775c84f3f3cSopenharmony_ci					refresh(false);
3776c84f3f3cSopenharmony_ci				}
3777c84f3f3cSopenharmony_ci				if (state == VVERSION) {
3778c84f3f3cSopenharmony_ci					save_cbuf();
3779c84f3f3cSopenharmony_ci					vs->cursor = 0;
3780c84f3f3cSopenharmony_ci					vs->linelen = 0;
3781c84f3f3cSopenharmony_ci					putbuf(KSH_VERSION,
3782c84f3f3cSopenharmony_ci					    strlen(KSH_VERSION), false);
3783c84f3f3cSopenharmony_ci					refresh(false);
3784c84f3f3cSopenharmony_ci				}
3785c84f3f3cSopenharmony_ci			}
3786c84f3f3cSopenharmony_ci		}
3787c84f3f3cSopenharmony_ci		break;
3788c84f3f3cSopenharmony_ci
3789c84f3f3cSopenharmony_ci	case VLIT:
3790c84f3f3cSopenharmony_ci		if (is_bad(ch)) {
3791c84f3f3cSopenharmony_ci			del_range(vs->cursor, vs->cursor + 1);
3792c84f3f3cSopenharmony_ci			vi_error();
3793c84f3f3cSopenharmony_ci		} else
3794c84f3f3cSopenharmony_ci			vs->cbuf[vs->cursor++] = ch;
3795c84f3f3cSopenharmony_ci		refresh(true);
3796c84f3f3cSopenharmony_ci		state = VNORMAL;
3797c84f3f3cSopenharmony_ci		break;
3798c84f3f3cSopenharmony_ci
3799c84f3f3cSopenharmony_ci	case VVERSION:
3800c84f3f3cSopenharmony_ci		restore_cbuf();
3801c84f3f3cSopenharmony_ci		state = VNORMAL;
3802c84f3f3cSopenharmony_ci		refresh(false);
3803c84f3f3cSopenharmony_ci		break;
3804c84f3f3cSopenharmony_ci
3805c84f3f3cSopenharmony_ci	case VARG1:
3806c84f3f3cSopenharmony_ci		if (ctype(ch, C_DIGIT))
3807c84f3f3cSopenharmony_ci			argc1 = argc1 * 10 + ksh_numdig(ch);
3808c84f3f3cSopenharmony_ci		else {
3809c84f3f3cSopenharmony_ci			curcmd[cmdlen++] = ch;
3810c84f3f3cSopenharmony_ci			state = nextstate(ch);
3811c84f3f3cSopenharmony_ci		}
3812c84f3f3cSopenharmony_ci		break;
3813c84f3f3cSopenharmony_ci
3814c84f3f3cSopenharmony_ci	case VEXTCMD:
3815c84f3f3cSopenharmony_ci		argc2 = 0;
3816c84f3f3cSopenharmony_ci		if (ctype(ch, C_DIGIT) && ord(ch) != ORD('0')) {
3817c84f3f3cSopenharmony_ci			argc2 = ksh_numdig(ch);
3818c84f3f3cSopenharmony_ci			state = VARG2;
3819c84f3f3cSopenharmony_ci			return (0);
3820c84f3f3cSopenharmony_ci		} else {
3821c84f3f3cSopenharmony_ci			curcmd[cmdlen++] = ch;
3822c84f3f3cSopenharmony_ci			if (ch == curcmd[0])
3823c84f3f3cSopenharmony_ci				state = VCMD;
3824c84f3f3cSopenharmony_ci			else if (is_move(ch))
3825c84f3f3cSopenharmony_ci				state = nextstate(ch);
3826c84f3f3cSopenharmony_ci			else
3827c84f3f3cSopenharmony_ci				state = VFAIL;
3828c84f3f3cSopenharmony_ci		}
3829c84f3f3cSopenharmony_ci		break;
3830c84f3f3cSopenharmony_ci
3831c84f3f3cSopenharmony_ci	case VARG2:
3832c84f3f3cSopenharmony_ci		if (ctype(ch, C_DIGIT))
3833c84f3f3cSopenharmony_ci			argc2 = argc2 * 10 + ksh_numdig(ch);
3834c84f3f3cSopenharmony_ci		else {
3835c84f3f3cSopenharmony_ci			if (argc1 == 0)
3836c84f3f3cSopenharmony_ci				argc1 = argc2;
3837c84f3f3cSopenharmony_ci			else
3838c84f3f3cSopenharmony_ci				argc1 *= argc2;
3839c84f3f3cSopenharmony_ci			curcmd[cmdlen++] = ch;
3840c84f3f3cSopenharmony_ci			if (ch == curcmd[0])
3841c84f3f3cSopenharmony_ci				state = VCMD;
3842c84f3f3cSopenharmony_ci			else if (is_move(ch))
3843c84f3f3cSopenharmony_ci				state = nextstate(ch);
3844c84f3f3cSopenharmony_ci			else
3845c84f3f3cSopenharmony_ci				state = VFAIL;
3846c84f3f3cSopenharmony_ci		}
3847c84f3f3cSopenharmony_ci		break;
3848c84f3f3cSopenharmony_ci
3849c84f3f3cSopenharmony_ci	case VXCH:
3850c84f3f3cSopenharmony_ci		if (ch == CTRL_BO)
3851c84f3f3cSopenharmony_ci			state = VNORMAL;
3852c84f3f3cSopenharmony_ci		else {
3853c84f3f3cSopenharmony_ci			curcmd[cmdlen++] = ch;
3854c84f3f3cSopenharmony_ci			state = VCMD;
3855c84f3f3cSopenharmony_ci		}
3856c84f3f3cSopenharmony_ci		break;
3857c84f3f3cSopenharmony_ci
3858c84f3f3cSopenharmony_ci	case VSEARCH:
3859c84f3f3cSopenharmony_ci		if (ctype(ch, C_CR | C_LF) /* || ch == CTRL_BO */ ) {
3860c84f3f3cSopenharmony_ci			restore_cbuf();
3861c84f3f3cSopenharmony_ci			/* Repeat last search? */
3862c84f3f3cSopenharmony_ci			if (srchlen == 0) {
3863c84f3f3cSopenharmony_ci				if (!srchpat[0]) {
3864c84f3f3cSopenharmony_ci					vi_error();
3865c84f3f3cSopenharmony_ci					state = VNORMAL;
3866c84f3f3cSopenharmony_ci					refresh(false);
3867c84f3f3cSopenharmony_ci					return (0);
3868c84f3f3cSopenharmony_ci				}
3869c84f3f3cSopenharmony_ci			} else {
3870c84f3f3cSopenharmony_ci				locpat[srchlen] = '\0';
3871c84f3f3cSopenharmony_ci				memcpy(srchpat, locpat, srchlen + 1);
3872c84f3f3cSopenharmony_ci			}
3873c84f3f3cSopenharmony_ci			state = VCMD;
3874c84f3f3cSopenharmony_ci		} else if (isched(ch, edchars.erase) || ch == CTRL_H) {
3875c84f3f3cSopenharmony_ci			if (srchlen != 0) {
3876c84f3f3cSopenharmony_ci				srchlen--;
3877c84f3f3cSopenharmony_ci				vs->linelen -= char_len(locpat[srchlen]);
3878c84f3f3cSopenharmony_ci				vs->cursor = vs->linelen;
3879c84f3f3cSopenharmony_ci				refresh(false);
3880c84f3f3cSopenharmony_ci				return (0);
3881c84f3f3cSopenharmony_ci			}
3882c84f3f3cSopenharmony_ci			restore_cbuf();
3883c84f3f3cSopenharmony_ci			state = VNORMAL;
3884c84f3f3cSopenharmony_ci			refresh(false);
3885c84f3f3cSopenharmony_ci		} else if (isched(ch, edchars.kill)) {
3886c84f3f3cSopenharmony_ci			srchlen = 0;
3887c84f3f3cSopenharmony_ci			vs->linelen = 1;
3888c84f3f3cSopenharmony_ci			vs->cursor = 1;
3889c84f3f3cSopenharmony_ci			refresh(false);
3890c84f3f3cSopenharmony_ci			return (0);
3891c84f3f3cSopenharmony_ci		} else if (isched(ch, edchars.werase)) {
3892c84f3f3cSopenharmony_ci			unsigned int i, n;
3893c84f3f3cSopenharmony_ci			struct edstate new_es, *save_es;
3894c84f3f3cSopenharmony_ci
3895c84f3f3cSopenharmony_ci			new_es.cursor = srchlen;
3896c84f3f3cSopenharmony_ci			new_es.cbuf = locpat;
3897c84f3f3cSopenharmony_ci
3898c84f3f3cSopenharmony_ci			save_es = vs;
3899c84f3f3cSopenharmony_ci			vs = &new_es;
3900c84f3f3cSopenharmony_ci			n = backword(1);
3901c84f3f3cSopenharmony_ci			vs = save_es;
3902c84f3f3cSopenharmony_ci
3903c84f3f3cSopenharmony_ci			i = (unsigned)srchlen;
3904c84f3f3cSopenharmony_ci			while (i-- > n)
3905c84f3f3cSopenharmony_ci				vs->linelen -= char_len(locpat[i]);
3906c84f3f3cSopenharmony_ci			srchlen = (int)n;
3907c84f3f3cSopenharmony_ci			vs->cursor = vs->linelen;
3908c84f3f3cSopenharmony_ci			refresh(false);
3909c84f3f3cSopenharmony_ci			return (0);
3910c84f3f3cSopenharmony_ci		} else {
3911c84f3f3cSopenharmony_ci			if (srchlen == SRCHLEN - 1)
3912c84f3f3cSopenharmony_ci				vi_error();
3913c84f3f3cSopenharmony_ci			else {
3914c84f3f3cSopenharmony_ci				locpat[srchlen++] = ch;
3915c84f3f3cSopenharmony_ci				if (ksh_isctrl(ch)) {
3916c84f3f3cSopenharmony_ci					if ((size_t)vs->linelen + 2 >
3917c84f3f3cSopenharmony_ci					    (size_t)vs->cbufsize)
3918c84f3f3cSopenharmony_ci						vi_error();
3919c84f3f3cSopenharmony_ci					vs->cbuf[vs->linelen++] = '^';
3920c84f3f3cSopenharmony_ci					vs->cbuf[vs->linelen++] = ksh_unctrl(ch);
3921c84f3f3cSopenharmony_ci				} else {
3922c84f3f3cSopenharmony_ci					if (vs->linelen >= vs->cbufsize)
3923c84f3f3cSopenharmony_ci						vi_error();
3924c84f3f3cSopenharmony_ci					vs->cbuf[vs->linelen++] = ch;
3925c84f3f3cSopenharmony_ci				}
3926c84f3f3cSopenharmony_ci				vs->cursor = vs->linelen;
3927c84f3f3cSopenharmony_ci				refresh(false);
3928c84f3f3cSopenharmony_ci			}
3929c84f3f3cSopenharmony_ci			return (0);
3930c84f3f3cSopenharmony_ci		}
3931c84f3f3cSopenharmony_ci		break;
3932c84f3f3cSopenharmony_ci
3933c84f3f3cSopenharmony_ci	case VPREFIX2:
3934c84f3f3cSopenharmony_ci vi_xfunc_search:
3935c84f3f3cSopenharmony_ci		state = VFAIL;
3936c84f3f3cSopenharmony_ci		switch (ch) {
3937c84f3f3cSopenharmony_ci		case ORD('A'):
3938c84f3f3cSopenharmony_ci		case ORD('B'):
3939c84f3f3cSopenharmony_ci			/* the cursor may not be at the BOL */
3940c84f3f3cSopenharmony_ci			if (!vs->cursor)
3941c84f3f3cSopenharmony_ci				break;
3942c84f3f3cSopenharmony_ci			/* nor further in the line than we can search for */
3943c84f3f3cSopenharmony_ci			if ((size_t)vs->cursor >= sizeof(srchpat) - 1)
3944c84f3f3cSopenharmony_ci				vs->cursor = sizeof(srchpat) - 2;
3945c84f3f3cSopenharmony_ci			/* anchor the search pattern */
3946c84f3f3cSopenharmony_ci			srchpat[0] = '^';
3947c84f3f3cSopenharmony_ci			/* take current line up to the cursor */
3948c84f3f3cSopenharmony_ci			memcpy(srchpat + 1, vs->cbuf, vs->cursor);
3949c84f3f3cSopenharmony_ci			srchpat[vs->cursor + 1] = '\0';
3950c84f3f3cSopenharmony_ci			/* set a magic flag */
3951c84f3f3cSopenharmony_ci			argc1 = 2 + (int)vs->cursor;
3952c84f3f3cSopenharmony_ci			/* and emulate a history search */
3953c84f3f3cSopenharmony_ci			/* search backwards if PgUp, forwards for PgDn */
3954c84f3f3cSopenharmony_ci			lastsearch = ch == ORD('A') ? '/' : '?';
3955c84f3f3cSopenharmony_ci			*curcmd = 'n';
3956c84f3f3cSopenharmony_ci			goto pseudo_VCMD;
3957c84f3f3cSopenharmony_ci		}
3958c84f3f3cSopenharmony_ci		break;
3959c84f3f3cSopenharmony_ci	}
3960c84f3f3cSopenharmony_ci
3961c84f3f3cSopenharmony_ci	switch (state) {
3962c84f3f3cSopenharmony_ci	case VCMD:
3963c84f3f3cSopenharmony_ci pseudo_VCMD:
3964c84f3f3cSopenharmony_ci		state = VNORMAL;
3965c84f3f3cSopenharmony_ci		switch (vi_cmd(argc1, curcmd)) {
3966c84f3f3cSopenharmony_ci		case -1:
3967c84f3f3cSopenharmony_ci			vi_error();
3968c84f3f3cSopenharmony_ci			refresh(false);
3969c84f3f3cSopenharmony_ci			break;
3970c84f3f3cSopenharmony_ci		case 0:
3971c84f3f3cSopenharmony_ci			if (insert != 0)
3972c84f3f3cSopenharmony_ci				inslen = 0;
3973c84f3f3cSopenharmony_ci			refresh(insert != 0);
3974c84f3f3cSopenharmony_ci			break;
3975c84f3f3cSopenharmony_ci		case 1:
3976c84f3f3cSopenharmony_ci			refresh(false);
3977c84f3f3cSopenharmony_ci			return (1);
3978c84f3f3cSopenharmony_ci		case 2:
3979c84f3f3cSopenharmony_ci			/* back from a 'v' command - don't redraw the screen */
3980c84f3f3cSopenharmony_ci			return (1);
3981c84f3f3cSopenharmony_ci		}
3982c84f3f3cSopenharmony_ci		break;
3983c84f3f3cSopenharmony_ci
3984c84f3f3cSopenharmony_ci	case VREDO:
3985c84f3f3cSopenharmony_ci		state = VNORMAL;
3986c84f3f3cSopenharmony_ci		if (argc1 != 0)
3987c84f3f3cSopenharmony_ci			lastac = argc1;
3988c84f3f3cSopenharmony_ci		switch (vi_cmd(lastac, lastcmd)) {
3989c84f3f3cSopenharmony_ci		case -1:
3990c84f3f3cSopenharmony_ci			vi_error();
3991c84f3f3cSopenharmony_ci			refresh(false);
3992c84f3f3cSopenharmony_ci			break;
3993c84f3f3cSopenharmony_ci		case 0:
3994c84f3f3cSopenharmony_ci			if (insert != 0) {
3995c84f3f3cSopenharmony_ci				if (lastcmd[0] == 's' ||
3996c84f3f3cSopenharmony_ci				    ksh_eq(lastcmd[0], 'C', 'c')) {
3997c84f3f3cSopenharmony_ci					if (redo_insert(1) != 0)
3998c84f3f3cSopenharmony_ci						vi_error();
3999c84f3f3cSopenharmony_ci				} else {
4000c84f3f3cSopenharmony_ci					if (redo_insert(lastac) != 0)
4001c84f3f3cSopenharmony_ci						vi_error();
4002c84f3f3cSopenharmony_ci				}
4003c84f3f3cSopenharmony_ci			}
4004c84f3f3cSopenharmony_ci			refresh(false);
4005c84f3f3cSopenharmony_ci			break;
4006c84f3f3cSopenharmony_ci		case 1:
4007c84f3f3cSopenharmony_ci			refresh(false);
4008c84f3f3cSopenharmony_ci			return (1);
4009c84f3f3cSopenharmony_ci		case 2:
4010c84f3f3cSopenharmony_ci			/* back from a 'v' command - can't happen */
4011c84f3f3cSopenharmony_ci			break;
4012c84f3f3cSopenharmony_ci		}
4013c84f3f3cSopenharmony_ci		break;
4014c84f3f3cSopenharmony_ci
4015c84f3f3cSopenharmony_ci	case VFAIL:
4016c84f3f3cSopenharmony_ci		state = VNORMAL;
4017c84f3f3cSopenharmony_ci		vi_error();
4018c84f3f3cSopenharmony_ci		break;
4019c84f3f3cSopenharmony_ci	}
4020c84f3f3cSopenharmony_ci	return (0);
4021c84f3f3cSopenharmony_ci}
4022c84f3f3cSopenharmony_ci
4023c84f3f3cSopenharmony_cistatic int
4024c84f3f3cSopenharmony_cinextstate(int ch)
4025c84f3f3cSopenharmony_ci{
4026c84f3f3cSopenharmony_ci	if (is_extend(ch))
4027c84f3f3cSopenharmony_ci		return (VEXTCMD);
4028c84f3f3cSopenharmony_ci	else if (is_srch(ch))
4029c84f3f3cSopenharmony_ci		return (VSEARCH);
4030c84f3f3cSopenharmony_ci	else if (is_long(ch))
4031c84f3f3cSopenharmony_ci		return (VXCH);
4032c84f3f3cSopenharmony_ci	else if (ch == '.')
4033c84f3f3cSopenharmony_ci		return (VREDO);
4034c84f3f3cSopenharmony_ci	else if (ch == CTRL_V)
4035c84f3f3cSopenharmony_ci		return (VVERSION);
4036c84f3f3cSopenharmony_ci	else if (is_cmd(ch))
4037c84f3f3cSopenharmony_ci		return (VCMD);
4038c84f3f3cSopenharmony_ci	else
4039c84f3f3cSopenharmony_ci		return (VFAIL);
4040c84f3f3cSopenharmony_ci}
4041c84f3f3cSopenharmony_ci
4042c84f3f3cSopenharmony_cistatic int
4043c84f3f3cSopenharmony_civi_insert(int ch)
4044c84f3f3cSopenharmony_ci{
4045c84f3f3cSopenharmony_ci	int tcursor;
4046c84f3f3cSopenharmony_ci
4047c84f3f3cSopenharmony_ci	if (isched(ch, edchars.erase) || ch == CTRL_H) {
4048c84f3f3cSopenharmony_ci		if (insert == REPLACE) {
4049c84f3f3cSopenharmony_ci			if (vs->cursor == undo->cursor) {
4050c84f3f3cSopenharmony_ci				vi_error();
4051c84f3f3cSopenharmony_ci				return (0);
4052c84f3f3cSopenharmony_ci			}
4053c84f3f3cSopenharmony_ci			if (inslen > 0)
4054c84f3f3cSopenharmony_ci				inslen--;
4055c84f3f3cSopenharmony_ci			vs->cursor--;
4056c84f3f3cSopenharmony_ci			if (vs->cursor >= undo->linelen)
4057c84f3f3cSopenharmony_ci				vs->linelen--;
4058c84f3f3cSopenharmony_ci			else
4059c84f3f3cSopenharmony_ci				vs->cbuf[vs->cursor] = undo->cbuf[vs->cursor];
4060c84f3f3cSopenharmony_ci		} else {
4061c84f3f3cSopenharmony_ci			if (vs->cursor == 0)
4062c84f3f3cSopenharmony_ci				return (0);
4063c84f3f3cSopenharmony_ci			if (inslen > 0)
4064c84f3f3cSopenharmony_ci				inslen--;
4065c84f3f3cSopenharmony_ci			vs->cursor--;
4066c84f3f3cSopenharmony_ci			vs->linelen--;
4067c84f3f3cSopenharmony_ci			memmove(&vs->cbuf[vs->cursor], &vs->cbuf[vs->cursor + 1],
4068c84f3f3cSopenharmony_ci			    vs->linelen - vs->cursor + 1);
4069c84f3f3cSopenharmony_ci		}
4070c84f3f3cSopenharmony_ci		expanded = NONE;
4071c84f3f3cSopenharmony_ci		return (0);
4072c84f3f3cSopenharmony_ci	}
4073c84f3f3cSopenharmony_ci	if (isched(ch, edchars.kill)) {
4074c84f3f3cSopenharmony_ci		if (vs->cursor != 0) {
4075c84f3f3cSopenharmony_ci			inslen = 0;
4076c84f3f3cSopenharmony_ci			memmove(vs->cbuf, &vs->cbuf[vs->cursor],
4077c84f3f3cSopenharmony_ci			    vs->linelen - vs->cursor);
4078c84f3f3cSopenharmony_ci			vs->linelen -= vs->cursor;
4079c84f3f3cSopenharmony_ci			vs->cursor = 0;
4080c84f3f3cSopenharmony_ci		}
4081c84f3f3cSopenharmony_ci		expanded = NONE;
4082c84f3f3cSopenharmony_ci		return (0);
4083c84f3f3cSopenharmony_ci	}
4084c84f3f3cSopenharmony_ci	if (isched(ch, edchars.werase)) {
4085c84f3f3cSopenharmony_ci		if (vs->cursor != 0) {
4086c84f3f3cSopenharmony_ci			tcursor = backword(1);
4087c84f3f3cSopenharmony_ci			memmove(&vs->cbuf[tcursor], &vs->cbuf[vs->cursor],
4088c84f3f3cSopenharmony_ci			    vs->linelen - vs->cursor);
4089c84f3f3cSopenharmony_ci			vs->linelen -= vs->cursor - tcursor;
4090c84f3f3cSopenharmony_ci			if (inslen < vs->cursor - tcursor)
4091c84f3f3cSopenharmony_ci				inslen = 0;
4092c84f3f3cSopenharmony_ci			else
4093c84f3f3cSopenharmony_ci				inslen -= vs->cursor - tcursor;
4094c84f3f3cSopenharmony_ci			vs->cursor = tcursor;
4095c84f3f3cSopenharmony_ci		}
4096c84f3f3cSopenharmony_ci		expanded = NONE;
4097c84f3f3cSopenharmony_ci		return (0);
4098c84f3f3cSopenharmony_ci	}
4099c84f3f3cSopenharmony_ci	/*
4100c84f3f3cSopenharmony_ci	 * If any chars are entered before escape, trash the saved insert
4101c84f3f3cSopenharmony_ci	 * buffer (if user inserts & deletes char, ibuf gets trashed and
4102c84f3f3cSopenharmony_ci	 * we don't want to use it)
4103c84f3f3cSopenharmony_ci	 */
4104c84f3f3cSopenharmony_ci	if (first_insert && ch != CTRL_BO)
4105c84f3f3cSopenharmony_ci		saved_inslen = 0;
4106c84f3f3cSopenharmony_ci	switch (ch) {
4107c84f3f3cSopenharmony_ci	case '\0':
4108c84f3f3cSopenharmony_ci		return (-1);
4109c84f3f3cSopenharmony_ci
4110c84f3f3cSopenharmony_ci	case '\r':
4111c84f3f3cSopenharmony_ci	case '\n':
4112c84f3f3cSopenharmony_ci		return (1);
4113c84f3f3cSopenharmony_ci
4114c84f3f3cSopenharmony_ci	case CTRL_BO:
4115c84f3f3cSopenharmony_ci		expanded = NONE;
4116c84f3f3cSopenharmony_ci		if (first_insert) {
4117c84f3f3cSopenharmony_ci			first_insert = false;
4118c84f3f3cSopenharmony_ci			if (inslen == 0) {
4119c84f3f3cSopenharmony_ci				inslen = saved_inslen;
4120c84f3f3cSopenharmony_ci				return (redo_insert(0));
4121c84f3f3cSopenharmony_ci			}
4122c84f3f3cSopenharmony_ci			lastcmd[0] = 'a';
4123c84f3f3cSopenharmony_ci			lastac = 1;
4124c84f3f3cSopenharmony_ci		}
4125c84f3f3cSopenharmony_ci		if (lastcmd[0] == 's' || ksh_eq(lastcmd[0], 'C', 'c'))
4126c84f3f3cSopenharmony_ci			return (redo_insert(0));
4127c84f3f3cSopenharmony_ci		else
4128c84f3f3cSopenharmony_ci			return (redo_insert(lastac - 1));
4129c84f3f3cSopenharmony_ci
4130c84f3f3cSopenharmony_ci	/* { start nonstandard vi commands */
4131c84f3f3cSopenharmony_ci	case CTRL_X:
4132c84f3f3cSopenharmony_ci		expand_word(0);
4133c84f3f3cSopenharmony_ci		break;
4134c84f3f3cSopenharmony_ci
4135c84f3f3cSopenharmony_ci	case CTRL_F:
4136c84f3f3cSopenharmony_ci		complete_word(0, 0);
4137c84f3f3cSopenharmony_ci		break;
4138c84f3f3cSopenharmony_ci
4139c84f3f3cSopenharmony_ci	case CTRL_E:
4140c84f3f3cSopenharmony_ci		print_expansions(vs, 0);
4141c84f3f3cSopenharmony_ci		break;
4142c84f3f3cSopenharmony_ci
4143c84f3f3cSopenharmony_ci	case CTRL_I:
4144c84f3f3cSopenharmony_ci		if (Flag(FVITABCOMPLETE)) {
4145c84f3f3cSopenharmony_ci			complete_word(0, 0);
4146c84f3f3cSopenharmony_ci			break;
4147c84f3f3cSopenharmony_ci		}
4148c84f3f3cSopenharmony_ci		/* FALLTHROUGH */
4149c84f3f3cSopenharmony_ci	/* end nonstandard vi commands } */
4150c84f3f3cSopenharmony_ci
4151c84f3f3cSopenharmony_ci	default:
4152c84f3f3cSopenharmony_ci		if (vs->linelen >= vs->cbufsize - 1)
4153c84f3f3cSopenharmony_ci			return (-1);
4154c84f3f3cSopenharmony_ci		ibuf[inslen++] = ch;
4155c84f3f3cSopenharmony_ci		if (insert == INSERT) {
4156c84f3f3cSopenharmony_ci			memmove(&vs->cbuf[vs->cursor + 1], &vs->cbuf[vs->cursor],
4157c84f3f3cSopenharmony_ci			    vs->linelen - vs->cursor);
4158c84f3f3cSopenharmony_ci			vs->linelen++;
4159c84f3f3cSopenharmony_ci		}
4160c84f3f3cSopenharmony_ci		vs->cbuf[vs->cursor++] = ch;
4161c84f3f3cSopenharmony_ci		if (insert == REPLACE && vs->cursor > vs->linelen)
4162c84f3f3cSopenharmony_ci			vs->linelen++;
4163c84f3f3cSopenharmony_ci		expanded = NONE;
4164c84f3f3cSopenharmony_ci	}
4165c84f3f3cSopenharmony_ci	return (0);
4166c84f3f3cSopenharmony_ci}
4167c84f3f3cSopenharmony_ci
4168c84f3f3cSopenharmony_cistatic int
4169c84f3f3cSopenharmony_civi_cmd(int argcnt, const char *cmd)
4170c84f3f3cSopenharmony_ci{
4171c84f3f3cSopenharmony_ci	int ncursor;
4172c84f3f3cSopenharmony_ci	int cur, c1, c2;
4173c84f3f3cSopenharmony_ci	int any;
4174c84f3f3cSopenharmony_ci	bool b;
4175c84f3f3cSopenharmony_ci	struct edstate *t;
4176c84f3f3cSopenharmony_ci
4177c84f3f3cSopenharmony_ci	if (argcnt == 0 && !is_zerocount(*cmd))
4178c84f3f3cSopenharmony_ci		argcnt = 1;
4179c84f3f3cSopenharmony_ci
4180c84f3f3cSopenharmony_ci	if (is_move(*cmd)) {
4181c84f3f3cSopenharmony_ci		if ((cur = domove(argcnt, cmd, 0)) >= 0) {
4182c84f3f3cSopenharmony_ci			if (cur == vs->linelen && cur != 0)
4183c84f3f3cSopenharmony_ci				cur--;
4184c84f3f3cSopenharmony_ci			vs->cursor = cur;
4185c84f3f3cSopenharmony_ci		} else
4186c84f3f3cSopenharmony_ci			return (-1);
4187c84f3f3cSopenharmony_ci	} else {
4188c84f3f3cSopenharmony_ci		/* Don't save state in middle of macro.. */
4189c84f3f3cSopenharmony_ci		if (is_undoable(*cmd) && !macro.p) {
4190c84f3f3cSopenharmony_ci			undo->winleft = vs->winleft;
4191c84f3f3cSopenharmony_ci			memmove(undo->cbuf, vs->cbuf, vs->linelen);
4192c84f3f3cSopenharmony_ci			undo->linelen = vs->linelen;
4193c84f3f3cSopenharmony_ci			undo->cursor = vs->cursor;
4194c84f3f3cSopenharmony_ci			lastac = argcnt;
4195c84f3f3cSopenharmony_ci			memmove(lastcmd, cmd, MAXVICMD);
4196c84f3f3cSopenharmony_ci		}
4197c84f3f3cSopenharmony_ci		switch (ord(*cmd)) {
4198c84f3f3cSopenharmony_ci
4199c84f3f3cSopenharmony_ci		case CTRL_L:
4200c84f3f3cSopenharmony_ci		case CTRL_R:
4201c84f3f3cSopenharmony_ci			redraw_line(true);
4202c84f3f3cSopenharmony_ci			break;
4203c84f3f3cSopenharmony_ci
4204c84f3f3cSopenharmony_ci		case ORD('@'):
4205c84f3f3cSopenharmony_ci			{
4206c84f3f3cSopenharmony_ci				static char alias[] = "_\0";
4207c84f3f3cSopenharmony_ci				struct tbl *ap;
4208c84f3f3cSopenharmony_ci				size_t olen, nlen;
4209c84f3f3cSopenharmony_ci				char *p, *nbuf;
4210c84f3f3cSopenharmony_ci
4211c84f3f3cSopenharmony_ci				/* lookup letter in alias list... */
4212c84f3f3cSopenharmony_ci				alias[1] = cmd[1];
4213c84f3f3cSopenharmony_ci				ap = ktsearch(&aliases, alias, hash(alias));
4214c84f3f3cSopenharmony_ci				if (!cmd[1] || !ap || !(ap->flag & ISSET))
4215c84f3f3cSopenharmony_ci					return (-1);
4216c84f3f3cSopenharmony_ci				/* check if this is a recursive call... */
4217c84f3f3cSopenharmony_ci				if ((p = (char *)macro.p))
4218c84f3f3cSopenharmony_ci					while ((p = strnul(p)) && p[1])
4219c84f3f3cSopenharmony_ci						if (*++p == cmd[1])
4220c84f3f3cSopenharmony_ci							return (-1);
4221c84f3f3cSopenharmony_ci				/* insert alias into macro buffer */
4222c84f3f3cSopenharmony_ci				nlen = strlen(ap->val.s) + 1;
4223c84f3f3cSopenharmony_ci				olen = !macro.p ? 2 :
4224c84f3f3cSopenharmony_ci				    macro.len - (macro.p - macro.buf);
4225c84f3f3cSopenharmony_ci				/*
4226c84f3f3cSopenharmony_ci				 * at this point, it's fairly reasonable that
4227c84f3f3cSopenharmony_ci				 * nlen + olen + 2 doesn't overflow
4228c84f3f3cSopenharmony_ci				 */
4229c84f3f3cSopenharmony_ci				nbuf = alloc(nlen + 1 + olen, AEDIT);
4230c84f3f3cSopenharmony_ci				memcpy(nbuf, ap->val.s, nlen);
4231c84f3f3cSopenharmony_ci				nbuf[nlen++] = cmd[1];
4232c84f3f3cSopenharmony_ci				if (macro.p) {
4233c84f3f3cSopenharmony_ci					memcpy(nbuf + nlen, macro.p, olen);
4234c84f3f3cSopenharmony_ci					afree(macro.buf, AEDIT);
4235c84f3f3cSopenharmony_ci					nlen += olen;
4236c84f3f3cSopenharmony_ci				} else {
4237c84f3f3cSopenharmony_ci					nbuf[nlen++] = '\0';
4238c84f3f3cSopenharmony_ci					nbuf[nlen++] = '\0';
4239c84f3f3cSopenharmony_ci				}
4240c84f3f3cSopenharmony_ci				macro.p = macro.buf = (unsigned char *)nbuf;
4241c84f3f3cSopenharmony_ci				macro.len = nlen;
4242c84f3f3cSopenharmony_ci			}
4243c84f3f3cSopenharmony_ci			break;
4244c84f3f3cSopenharmony_ci
4245c84f3f3cSopenharmony_ci		case ORD('a'):
4246c84f3f3cSopenharmony_ci			modified = 1;
4247c84f3f3cSopenharmony_ci			hnum = hlast;
4248c84f3f3cSopenharmony_ci			if (vs->linelen != 0)
4249c84f3f3cSopenharmony_ci				vs->cursor++;
4250c84f3f3cSopenharmony_ci			insert = INSERT;
4251c84f3f3cSopenharmony_ci			break;
4252c84f3f3cSopenharmony_ci
4253c84f3f3cSopenharmony_ci		case ORD('A'):
4254c84f3f3cSopenharmony_ci			modified = 1;
4255c84f3f3cSopenharmony_ci			hnum = hlast;
4256c84f3f3cSopenharmony_ci			del_range(0, 0);
4257c84f3f3cSopenharmony_ci			vs->cursor = vs->linelen;
4258c84f3f3cSopenharmony_ci			insert = INSERT;
4259c84f3f3cSopenharmony_ci			break;
4260c84f3f3cSopenharmony_ci
4261c84f3f3cSopenharmony_ci		case ORD('S'):
4262c84f3f3cSopenharmony_ci			vs->cursor = domovebeg();
4263c84f3f3cSopenharmony_ci			del_range(vs->cursor, vs->linelen);
4264c84f3f3cSopenharmony_ci			modified = 1;
4265c84f3f3cSopenharmony_ci			hnum = hlast;
4266c84f3f3cSopenharmony_ci			insert = INSERT;
4267c84f3f3cSopenharmony_ci			break;
4268c84f3f3cSopenharmony_ci
4269c84f3f3cSopenharmony_ci		case ORD('Y'):
4270c84f3f3cSopenharmony_ci			cmd = "y$";
4271c84f3f3cSopenharmony_ci			/* ahhhhhh... */
4272c84f3f3cSopenharmony_ci
4273c84f3f3cSopenharmony_ci			/* FALLTHROUGH */
4274c84f3f3cSopenharmony_ci		case ORD('c'):
4275c84f3f3cSopenharmony_ci		case ORD('d'):
4276c84f3f3cSopenharmony_ci		case ORD('y'):
4277c84f3f3cSopenharmony_ci			if (*cmd == cmd[1]) {
4278c84f3f3cSopenharmony_ci				c1 = *cmd == 'c' ? domovebeg() : 0;
4279c84f3f3cSopenharmony_ci				c2 = vs->linelen;
4280c84f3f3cSopenharmony_ci			} else if (!is_move(cmd[1]))
4281c84f3f3cSopenharmony_ci				return (-1);
4282c84f3f3cSopenharmony_ci			else {
4283c84f3f3cSopenharmony_ci				if ((ncursor = domove(argcnt, &cmd[1], 1)) < 0)
4284c84f3f3cSopenharmony_ci					return (-1);
4285c84f3f3cSopenharmony_ci				if (*cmd == 'c' && ksh_eq(cmd[1], 'W', 'w') &&
4286c84f3f3cSopenharmony_ci				    !ctype(vs->cbuf[vs->cursor], C_SPACE)) {
4287c84f3f3cSopenharmony_ci					do {
4288c84f3f3cSopenharmony_ci						--ncursor;
4289c84f3f3cSopenharmony_ci					} while (ctype(vs->cbuf[ncursor], C_SPACE));
4290c84f3f3cSopenharmony_ci					ncursor++;
4291c84f3f3cSopenharmony_ci				}
4292c84f3f3cSopenharmony_ci				if (ncursor > vs->cursor) {
4293c84f3f3cSopenharmony_ci					c1 = vs->cursor;
4294c84f3f3cSopenharmony_ci					c2 = ncursor;
4295c84f3f3cSopenharmony_ci				} else {
4296c84f3f3cSopenharmony_ci					c1 = ncursor;
4297c84f3f3cSopenharmony_ci					c2 = vs->cursor;
4298c84f3f3cSopenharmony_ci					if (cmd[1] == '%')
4299c84f3f3cSopenharmony_ci						c2++;
4300c84f3f3cSopenharmony_ci				}
4301c84f3f3cSopenharmony_ci			}
4302c84f3f3cSopenharmony_ci			if (*cmd != 'c' && c1 != c2)
4303c84f3f3cSopenharmony_ci				yank_range(c1, c2);
4304c84f3f3cSopenharmony_ci			if (*cmd != 'y') {
4305c84f3f3cSopenharmony_ci				del_range(c1, c2);
4306c84f3f3cSopenharmony_ci				vs->cursor = c1;
4307c84f3f3cSopenharmony_ci			}
4308c84f3f3cSopenharmony_ci			if (*cmd == 'c') {
4309c84f3f3cSopenharmony_ci				modified = 1;
4310c84f3f3cSopenharmony_ci				hnum = hlast;
4311c84f3f3cSopenharmony_ci				insert = INSERT;
4312c84f3f3cSopenharmony_ci			}
4313c84f3f3cSopenharmony_ci			break;
4314c84f3f3cSopenharmony_ci
4315c84f3f3cSopenharmony_ci		case ORD('p'):
4316c84f3f3cSopenharmony_ci			modified = 1;
4317c84f3f3cSopenharmony_ci			hnum = hlast;
4318c84f3f3cSopenharmony_ci			if (vs->linelen != 0)
4319c84f3f3cSopenharmony_ci				vs->cursor++;
4320c84f3f3cSopenharmony_ci			while (putbuf(ybuf, yanklen, false) == 0 &&
4321c84f3f3cSopenharmony_ci			    --argcnt > 0)
4322c84f3f3cSopenharmony_ci				;
4323c84f3f3cSopenharmony_ci			if (vs->cursor != 0)
4324c84f3f3cSopenharmony_ci				vs->cursor--;
4325c84f3f3cSopenharmony_ci			if (argcnt != 0)
4326c84f3f3cSopenharmony_ci				return (-1);
4327c84f3f3cSopenharmony_ci			break;
4328c84f3f3cSopenharmony_ci
4329c84f3f3cSopenharmony_ci		case ORD('P'):
4330c84f3f3cSopenharmony_ci			modified = 1;
4331c84f3f3cSopenharmony_ci			hnum = hlast;
4332c84f3f3cSopenharmony_ci			any = 0;
4333c84f3f3cSopenharmony_ci			while (putbuf(ybuf, yanklen, false) == 0 &&
4334c84f3f3cSopenharmony_ci			    --argcnt > 0)
4335c84f3f3cSopenharmony_ci				any = 1;
4336c84f3f3cSopenharmony_ci			if (any && vs->cursor != 0)
4337c84f3f3cSopenharmony_ci				vs->cursor--;
4338c84f3f3cSopenharmony_ci			if (argcnt != 0)
4339c84f3f3cSopenharmony_ci				return (-1);
4340c84f3f3cSopenharmony_ci			break;
4341c84f3f3cSopenharmony_ci
4342c84f3f3cSopenharmony_ci		case ORD('C'):
4343c84f3f3cSopenharmony_ci			modified = 1;
4344c84f3f3cSopenharmony_ci			hnum = hlast;
4345c84f3f3cSopenharmony_ci			del_range(vs->cursor, vs->linelen);
4346c84f3f3cSopenharmony_ci			insert = INSERT;
4347c84f3f3cSopenharmony_ci			break;
4348c84f3f3cSopenharmony_ci
4349c84f3f3cSopenharmony_ci		case ORD('D'):
4350c84f3f3cSopenharmony_ci			yank_range(vs->cursor, vs->linelen);
4351c84f3f3cSopenharmony_ci			del_range(vs->cursor, vs->linelen);
4352c84f3f3cSopenharmony_ci			if (vs->cursor != 0)
4353c84f3f3cSopenharmony_ci				vs->cursor--;
4354c84f3f3cSopenharmony_ci			break;
4355c84f3f3cSopenharmony_ci
4356c84f3f3cSopenharmony_ci		case ORD('g'):
4357c84f3f3cSopenharmony_ci			if (!argcnt)
4358c84f3f3cSopenharmony_ci				argcnt = hlast;
4359c84f3f3cSopenharmony_ci			/* FALLTHROUGH */
4360c84f3f3cSopenharmony_ci		case ORD('G'):
4361c84f3f3cSopenharmony_ci			if (!argcnt)
4362c84f3f3cSopenharmony_ci				argcnt = 1;
4363c84f3f3cSopenharmony_ci			else
4364c84f3f3cSopenharmony_ci				argcnt = hlast - (source->line - argcnt);
4365c84f3f3cSopenharmony_ci			if (grabhist(modified, argcnt - 1) < 0)
4366c84f3f3cSopenharmony_ci				return (-1);
4367c84f3f3cSopenharmony_ci			else {
4368c84f3f3cSopenharmony_ci				modified = 0;
4369c84f3f3cSopenharmony_ci				hnum = argcnt - 1;
4370c84f3f3cSopenharmony_ci			}
4371c84f3f3cSopenharmony_ci			break;
4372c84f3f3cSopenharmony_ci
4373c84f3f3cSopenharmony_ci		case ORD('i'):
4374c84f3f3cSopenharmony_ci			modified = 1;
4375c84f3f3cSopenharmony_ci			hnum = hlast;
4376c84f3f3cSopenharmony_ci			insert = INSERT;
4377c84f3f3cSopenharmony_ci			break;
4378c84f3f3cSopenharmony_ci
4379c84f3f3cSopenharmony_ci		case ORD('I'):
4380c84f3f3cSopenharmony_ci			modified = 1;
4381c84f3f3cSopenharmony_ci			hnum = hlast;
4382c84f3f3cSopenharmony_ci			vs->cursor = domovebeg();
4383c84f3f3cSopenharmony_ci			insert = INSERT;
4384c84f3f3cSopenharmony_ci			break;
4385c84f3f3cSopenharmony_ci
4386c84f3f3cSopenharmony_ci		case ORD('j'):
4387c84f3f3cSopenharmony_ci		case ORD('+'):
4388c84f3f3cSopenharmony_ci		case CTRL_N:
4389c84f3f3cSopenharmony_ci			if (grabhist(modified, hnum + argcnt) < 0)
4390c84f3f3cSopenharmony_ci				return (-1);
4391c84f3f3cSopenharmony_ci			else {
4392c84f3f3cSopenharmony_ci				modified = 0;
4393c84f3f3cSopenharmony_ci				hnum += argcnt;
4394c84f3f3cSopenharmony_ci			}
4395c84f3f3cSopenharmony_ci			break;
4396c84f3f3cSopenharmony_ci
4397c84f3f3cSopenharmony_ci		case ORD('k'):
4398c84f3f3cSopenharmony_ci		case ORD('-'):
4399c84f3f3cSopenharmony_ci		case CTRL_P:
4400c84f3f3cSopenharmony_ci			if (grabhist(modified, hnum - argcnt) < 0)
4401c84f3f3cSopenharmony_ci				return (-1);
4402c84f3f3cSopenharmony_ci			else {
4403c84f3f3cSopenharmony_ci				modified = 0;
4404c84f3f3cSopenharmony_ci				hnum -= argcnt;
4405c84f3f3cSopenharmony_ci			}
4406c84f3f3cSopenharmony_ci			break;
4407c84f3f3cSopenharmony_ci
4408c84f3f3cSopenharmony_ci		case ORD('r'):
4409c84f3f3cSopenharmony_ci			if (vs->linelen == 0)
4410c84f3f3cSopenharmony_ci				return (-1);
4411c84f3f3cSopenharmony_ci			modified = 1;
4412c84f3f3cSopenharmony_ci			hnum = hlast;
4413c84f3f3cSopenharmony_ci			if (cmd[1] == 0)
4414c84f3f3cSopenharmony_ci				vi_error();
4415c84f3f3cSopenharmony_ci			else {
4416c84f3f3cSopenharmony_ci				int n;
4417c84f3f3cSopenharmony_ci
4418c84f3f3cSopenharmony_ci				if (vs->cursor + argcnt > vs->linelen)
4419c84f3f3cSopenharmony_ci					return (-1);
4420c84f3f3cSopenharmony_ci				for (n = 0; n < argcnt; ++n)
4421c84f3f3cSopenharmony_ci					vs->cbuf[vs->cursor + n] = cmd[1];
4422c84f3f3cSopenharmony_ci				vs->cursor += n - 1;
4423c84f3f3cSopenharmony_ci			}
4424c84f3f3cSopenharmony_ci			break;
4425c84f3f3cSopenharmony_ci
4426c84f3f3cSopenharmony_ci		case ORD('R'):
4427c84f3f3cSopenharmony_ci			modified = 1;
4428c84f3f3cSopenharmony_ci			hnum = hlast;
4429c84f3f3cSopenharmony_ci			insert = REPLACE;
4430c84f3f3cSopenharmony_ci			break;
4431c84f3f3cSopenharmony_ci
4432c84f3f3cSopenharmony_ci		case ORD('s'):
4433c84f3f3cSopenharmony_ci			if (vs->linelen == 0)
4434c84f3f3cSopenharmony_ci				return (-1);
4435c84f3f3cSopenharmony_ci			modified = 1;
4436c84f3f3cSopenharmony_ci			hnum = hlast;
4437c84f3f3cSopenharmony_ci			if (vs->cursor + argcnt > vs->linelen)
4438c84f3f3cSopenharmony_ci				argcnt = vs->linelen - vs->cursor;
4439c84f3f3cSopenharmony_ci			del_range(vs->cursor, vs->cursor + argcnt);
4440c84f3f3cSopenharmony_ci			insert = INSERT;
4441c84f3f3cSopenharmony_ci			break;
4442c84f3f3cSopenharmony_ci
4443c84f3f3cSopenharmony_ci		case ORD('v'):
4444c84f3f3cSopenharmony_ci			if (!argcnt) {
4445c84f3f3cSopenharmony_ci				if (modified) {
4446c84f3f3cSopenharmony_ci					vs->cbuf[vs->linelen] = '\0';
4447c84f3f3cSopenharmony_ci					histsave(&source->line, vs->cbuf,
4448c84f3f3cSopenharmony_ci					    HIST_STORE, true);
4449c84f3f3cSopenharmony_ci				} else
4450c84f3f3cSopenharmony_ci					argcnt = source->line + 1 -
4451c84f3f3cSopenharmony_ci					    (hlast - hnum);
4452c84f3f3cSopenharmony_ci			}
4453c84f3f3cSopenharmony_ci			if (argcnt)
4454c84f3f3cSopenharmony_ci				shf_snprintf(vs->cbuf, vs->cbufsize, Tf_sd,
4455c84f3f3cSopenharmony_ci				    ctrl_x_e, argcnt);
4456c84f3f3cSopenharmony_ci			else
4457c84f3f3cSopenharmony_ci				strlcpy(vs->cbuf, ctrl_x_e, vs->cbufsize);
4458c84f3f3cSopenharmony_ci			vs->linelen = strlen(vs->cbuf);
4459c84f3f3cSopenharmony_ci			return (2);
4460c84f3f3cSopenharmony_ci
4461c84f3f3cSopenharmony_ci		case ORD('x'):
4462c84f3f3cSopenharmony_ci			if (vs->linelen == 0)
4463c84f3f3cSopenharmony_ci				return (-1);
4464c84f3f3cSopenharmony_ci			modified = 1;
4465c84f3f3cSopenharmony_ci			hnum = hlast;
4466c84f3f3cSopenharmony_ci			if (vs->cursor + argcnt > vs->linelen)
4467c84f3f3cSopenharmony_ci				argcnt = vs->linelen - vs->cursor;
4468c84f3f3cSopenharmony_ci			yank_range(vs->cursor, vs->cursor + argcnt);
4469c84f3f3cSopenharmony_ci			del_range(vs->cursor, vs->cursor + argcnt);
4470c84f3f3cSopenharmony_ci			break;
4471c84f3f3cSopenharmony_ci
4472c84f3f3cSopenharmony_ci		case ORD('X'):
4473c84f3f3cSopenharmony_ci			if (vs->cursor > 0) {
4474c84f3f3cSopenharmony_ci				modified = 1;
4475c84f3f3cSopenharmony_ci				hnum = hlast;
4476c84f3f3cSopenharmony_ci				if (vs->cursor < argcnt)
4477c84f3f3cSopenharmony_ci					argcnt = vs->cursor;
4478c84f3f3cSopenharmony_ci				yank_range(vs->cursor - argcnt, vs->cursor);
4479c84f3f3cSopenharmony_ci				del_range(vs->cursor - argcnt, vs->cursor);
4480c84f3f3cSopenharmony_ci				vs->cursor -= argcnt;
4481c84f3f3cSopenharmony_ci			} else
4482c84f3f3cSopenharmony_ci				return (-1);
4483c84f3f3cSopenharmony_ci			break;
4484c84f3f3cSopenharmony_ci
4485c84f3f3cSopenharmony_ci		case ORD('u'):
4486c84f3f3cSopenharmony_ci			t = vs;
4487c84f3f3cSopenharmony_ci			vs = undo;
4488c84f3f3cSopenharmony_ci			undo = t;
4489c84f3f3cSopenharmony_ci			break;
4490c84f3f3cSopenharmony_ci
4491c84f3f3cSopenharmony_ci		case ORD('U'):
4492c84f3f3cSopenharmony_ci			if (!modified)
4493c84f3f3cSopenharmony_ci				return (-1);
4494c84f3f3cSopenharmony_ci			if (grabhist(modified, ohnum) < 0)
4495c84f3f3cSopenharmony_ci				return (-1);
4496c84f3f3cSopenharmony_ci			modified = 0;
4497c84f3f3cSopenharmony_ci			hnum = ohnum;
4498c84f3f3cSopenharmony_ci			break;
4499c84f3f3cSopenharmony_ci
4500c84f3f3cSopenharmony_ci		case ORD('?'):
4501c84f3f3cSopenharmony_ci			if (hnum == hlast)
4502c84f3f3cSopenharmony_ci				hnum = -1;
4503c84f3f3cSopenharmony_ci			/* ahhh */
4504c84f3f3cSopenharmony_ci
4505c84f3f3cSopenharmony_ci			/* FALLTHROUGH */
4506c84f3f3cSopenharmony_ci		case ORD('/'):
4507c84f3f3cSopenharmony_ci			c1 = 1;
4508c84f3f3cSopenharmony_ci			srchlen = 0;
4509c84f3f3cSopenharmony_ci			lastsearch = *cmd;
4510c84f3f3cSopenharmony_ci			if (0)
4511c84f3f3cSopenharmony_ci				/* FALLTHROUGH */
4512c84f3f3cSopenharmony_ci		case ORD('n'):
4513c84f3f3cSopenharmony_ci		case ORD('N'):
4514c84f3f3cSopenharmony_ci			  c1 = 0;
4515c84f3f3cSopenharmony_ci			if (lastsearch == ORD(' '))
4516c84f3f3cSopenharmony_ci				return (-1);
4517c84f3f3cSopenharmony_ci			b = (lastsearch == ORD('?'));
4518c84f3f3cSopenharmony_ci			if (*cmd == 'N')
4519c84f3f3cSopenharmony_ci				b = !b;
4520c84f3f3cSopenharmony_ci			if ((c2 = grabsearch(srchpat, modified, hnum, b)) < 0) {
4521c84f3f3cSopenharmony_ci				if (c1) {
4522c84f3f3cSopenharmony_ci					restore_cbuf();
4523c84f3f3cSopenharmony_ci					refresh(false);
4524c84f3f3cSopenharmony_ci				}
4525c84f3f3cSopenharmony_ci				return (-1);
4526c84f3f3cSopenharmony_ci			} else {
4527c84f3f3cSopenharmony_ci				modified = 0;
4528c84f3f3cSopenharmony_ci				hnum = c2;
4529c84f3f3cSopenharmony_ci				ohnum = hnum;
4530c84f3f3cSopenharmony_ci			}
4531c84f3f3cSopenharmony_ci			if (argcnt >= 2) {
4532c84f3f3cSopenharmony_ci				/* flag from cursor-up command */
4533c84f3f3cSopenharmony_ci				vs->cursor = argcnt - 2;
4534c84f3f3cSopenharmony_ci				return (0);
4535c84f3f3cSopenharmony_ci			}
4536c84f3f3cSopenharmony_ci			break;
4537c84f3f3cSopenharmony_ci		case ORD('_'):
4538c84f3f3cSopenharmony_ci			{
4539c84f3f3cSopenharmony_ci				bool inspace;
4540c84f3f3cSopenharmony_ci				char *p, *sp;
4541c84f3f3cSopenharmony_ci
4542c84f3f3cSopenharmony_ci				if (histnum(-1) < 0)
4543c84f3f3cSopenharmony_ci					return (-1);
4544c84f3f3cSopenharmony_ci				p = *histpos();
4545c84f3f3cSopenharmony_ci				if (argcnt) {
4546c84f3f3cSopenharmony_ci					while (ctype(*p, C_SPACE))
4547c84f3f3cSopenharmony_ci						p++;
4548c84f3f3cSopenharmony_ci					while (*p && --argcnt) {
4549c84f3f3cSopenharmony_ci						while (*p && !ctype(*p, C_SPACE))
4550c84f3f3cSopenharmony_ci							p++;
4551c84f3f3cSopenharmony_ci						while (ctype(*p, C_SPACE))
4552c84f3f3cSopenharmony_ci							p++;
4553c84f3f3cSopenharmony_ci					}
4554c84f3f3cSopenharmony_ci					if (!*p)
4555c84f3f3cSopenharmony_ci						return (-1);
4556c84f3f3cSopenharmony_ci					sp = p;
4557c84f3f3cSopenharmony_ci				} else {
4558c84f3f3cSopenharmony_ci					sp = p;
4559c84f3f3cSopenharmony_ci					inspace = false;
4560c84f3f3cSopenharmony_ci					while (*p) {
4561c84f3f3cSopenharmony_ci						if (ctype(*p, C_SPACE))
4562c84f3f3cSopenharmony_ci							inspace = true;
4563c84f3f3cSopenharmony_ci						else if (inspace) {
4564c84f3f3cSopenharmony_ci							inspace = false;
4565c84f3f3cSopenharmony_ci							sp = p;
4566c84f3f3cSopenharmony_ci						}
4567c84f3f3cSopenharmony_ci						p++;
4568c84f3f3cSopenharmony_ci					}
4569c84f3f3cSopenharmony_ci					p = sp;
4570c84f3f3cSopenharmony_ci				}
4571c84f3f3cSopenharmony_ci				modified = 1;
4572c84f3f3cSopenharmony_ci				hnum = hlast;
4573c84f3f3cSopenharmony_ci				if (vs->cursor != vs->linelen)
4574c84f3f3cSopenharmony_ci					vs->cursor++;
4575c84f3f3cSopenharmony_ci				while (*p && !ctype(*p, C_SPACE)) {
4576c84f3f3cSopenharmony_ci					argcnt++;
4577c84f3f3cSopenharmony_ci					p++;
4578c84f3f3cSopenharmony_ci				}
4579c84f3f3cSopenharmony_ci				if (putbuf(T1space, 1, false) != 0 ||
4580c84f3f3cSopenharmony_ci				    putbuf(sp, argcnt, false) != 0) {
4581c84f3f3cSopenharmony_ci					if (vs->cursor != 0)
4582c84f3f3cSopenharmony_ci						vs->cursor--;
4583c84f3f3cSopenharmony_ci					return (-1);
4584c84f3f3cSopenharmony_ci				}
4585c84f3f3cSopenharmony_ci				insert = INSERT;
4586c84f3f3cSopenharmony_ci			}
4587c84f3f3cSopenharmony_ci			break;
4588c84f3f3cSopenharmony_ci
4589c84f3f3cSopenharmony_ci		case ORD('~'):
4590c84f3f3cSopenharmony_ci			{
4591c84f3f3cSopenharmony_ci				char *p;
4592c84f3f3cSopenharmony_ci				int i;
4593c84f3f3cSopenharmony_ci
4594c84f3f3cSopenharmony_ci				if (vs->linelen == 0)
4595c84f3f3cSopenharmony_ci					return (-1);
4596c84f3f3cSopenharmony_ci				for (i = 0; i < argcnt; i++) {
4597c84f3f3cSopenharmony_ci					p = &vs->cbuf[vs->cursor];
4598c84f3f3cSopenharmony_ci					if (ctype(*p, C_LOWER)) {
4599c84f3f3cSopenharmony_ci						modified = 1;
4600c84f3f3cSopenharmony_ci						hnum = hlast;
4601c84f3f3cSopenharmony_ci						*p = ksh_toupper(*p);
4602c84f3f3cSopenharmony_ci					} else if (ctype(*p, C_UPPER)) {
4603c84f3f3cSopenharmony_ci						modified = 1;
4604c84f3f3cSopenharmony_ci						hnum = hlast;
4605c84f3f3cSopenharmony_ci						*p = ksh_tolower(*p);
4606c84f3f3cSopenharmony_ci					}
4607c84f3f3cSopenharmony_ci					if (vs->cursor < vs->linelen - 1)
4608c84f3f3cSopenharmony_ci						vs->cursor++;
4609c84f3f3cSopenharmony_ci				}
4610c84f3f3cSopenharmony_ci				break;
4611c84f3f3cSopenharmony_ci			}
4612c84f3f3cSopenharmony_ci
4613c84f3f3cSopenharmony_ci		case ORD('#'):
4614c84f3f3cSopenharmony_ci			{
4615c84f3f3cSopenharmony_ci				int ret = x_do_comment(vs->cbuf, vs->cbufsize,
4616c84f3f3cSopenharmony_ci				    &vs->linelen);
4617c84f3f3cSopenharmony_ci				if (ret >= 0)
4618c84f3f3cSopenharmony_ci					vs->cursor = 0;
4619c84f3f3cSopenharmony_ci				return (ret);
4620c84f3f3cSopenharmony_ci			}
4621c84f3f3cSopenharmony_ci
4622c84f3f3cSopenharmony_ci		/* AT&T ksh */
4623c84f3f3cSopenharmony_ci		case ORD('='):
4624c84f3f3cSopenharmony_ci		/* Nonstandard vi/ksh */
4625c84f3f3cSopenharmony_ci		case CTRL_E:
4626c84f3f3cSopenharmony_ci			print_expansions(vs, 1);
4627c84f3f3cSopenharmony_ci			break;
4628c84f3f3cSopenharmony_ci
4629c84f3f3cSopenharmony_ci
4630c84f3f3cSopenharmony_ci		/* Nonstandard vi/ksh */
4631c84f3f3cSopenharmony_ci		case CTRL_I:
4632c84f3f3cSopenharmony_ci			if (!Flag(FVITABCOMPLETE))
4633c84f3f3cSopenharmony_ci				return (-1);
4634c84f3f3cSopenharmony_ci			complete_word(1, argcnt);
4635c84f3f3cSopenharmony_ci			break;
4636c84f3f3cSopenharmony_ci
4637c84f3f3cSopenharmony_ci		/* some annoying AT&T kshs */
4638c84f3f3cSopenharmony_ci		case CTRL_BO:
4639c84f3f3cSopenharmony_ci			if (!Flag(FVIESCCOMPLETE))
4640c84f3f3cSopenharmony_ci				return (-1);
4641c84f3f3cSopenharmony_ci			/* FALLTHROUGH */
4642c84f3f3cSopenharmony_ci		/* AT&T ksh */
4643c84f3f3cSopenharmony_ci		case ORD('\\'):
4644c84f3f3cSopenharmony_ci		/* Nonstandard vi/ksh */
4645c84f3f3cSopenharmony_ci		case CTRL_F:
4646c84f3f3cSopenharmony_ci			complete_word(1, argcnt);
4647c84f3f3cSopenharmony_ci			break;
4648c84f3f3cSopenharmony_ci
4649c84f3f3cSopenharmony_ci
4650c84f3f3cSopenharmony_ci		/* AT&T ksh */
4651c84f3f3cSopenharmony_ci		case ORD('*'):
4652c84f3f3cSopenharmony_ci		/* Nonstandard vi/ksh */
4653c84f3f3cSopenharmony_ci		case CTRL_X:
4654c84f3f3cSopenharmony_ci			expand_word(1);
4655c84f3f3cSopenharmony_ci			break;
4656c84f3f3cSopenharmony_ci
4657c84f3f3cSopenharmony_ci
4658c84f3f3cSopenharmony_ci		/* mksh: cursor movement */
4659c84f3f3cSopenharmony_ci		case ORD('['):
4660c84f3f3cSopenharmony_ci		case ORD('O'):
4661c84f3f3cSopenharmony_ci			state = VPREFIX2;
4662c84f3f3cSopenharmony_ci			if (vs->linelen != 0)
4663c84f3f3cSopenharmony_ci				vs->cursor++;
4664c84f3f3cSopenharmony_ci			insert = INSERT;
4665c84f3f3cSopenharmony_ci			return (0);
4666c84f3f3cSopenharmony_ci		}
4667c84f3f3cSopenharmony_ci		if (insert == 0 && vs->cursor != 0 && vs->cursor >= vs->linelen)
4668c84f3f3cSopenharmony_ci			vs->cursor--;
4669c84f3f3cSopenharmony_ci	}
4670c84f3f3cSopenharmony_ci	return (0);
4671c84f3f3cSopenharmony_ci}
4672c84f3f3cSopenharmony_ci
4673c84f3f3cSopenharmony_cistatic int
4674c84f3f3cSopenharmony_cidomove(int argcnt, const char *cmd, int sub)
4675c84f3f3cSopenharmony_ci{
4676c84f3f3cSopenharmony_ci	int ncursor = 0, i = 0, t;
4677c84f3f3cSopenharmony_ci	unsigned int bcount;
4678c84f3f3cSopenharmony_ci
4679c84f3f3cSopenharmony_ci	switch (ord(*cmd)) {
4680c84f3f3cSopenharmony_ci	case ORD('b'):
4681c84f3f3cSopenharmony_ci		if (!sub && vs->cursor == 0)
4682c84f3f3cSopenharmony_ci			return (-1);
4683c84f3f3cSopenharmony_ci		ncursor = backword(argcnt);
4684c84f3f3cSopenharmony_ci		break;
4685c84f3f3cSopenharmony_ci
4686c84f3f3cSopenharmony_ci	case ORD('B'):
4687c84f3f3cSopenharmony_ci		if (!sub && vs->cursor == 0)
4688c84f3f3cSopenharmony_ci			return (-1);
4689c84f3f3cSopenharmony_ci		ncursor = Backword(argcnt);
4690c84f3f3cSopenharmony_ci		break;
4691c84f3f3cSopenharmony_ci
4692c84f3f3cSopenharmony_ci	case ORD('e'):
4693c84f3f3cSopenharmony_ci		if (!sub && vs->cursor + 1 >= vs->linelen)
4694c84f3f3cSopenharmony_ci			return (-1);
4695c84f3f3cSopenharmony_ci		ncursor = endword(argcnt);
4696c84f3f3cSopenharmony_ci		if (sub && ncursor < vs->linelen)
4697c84f3f3cSopenharmony_ci			ncursor++;
4698c84f3f3cSopenharmony_ci		break;
4699c84f3f3cSopenharmony_ci
4700c84f3f3cSopenharmony_ci	case ORD('E'):
4701c84f3f3cSopenharmony_ci		if (!sub && vs->cursor + 1 >= vs->linelen)
4702c84f3f3cSopenharmony_ci			return (-1);
4703c84f3f3cSopenharmony_ci		ncursor = Endword(argcnt);
4704c84f3f3cSopenharmony_ci		if (sub && ncursor < vs->linelen)
4705c84f3f3cSopenharmony_ci			ncursor++;
4706c84f3f3cSopenharmony_ci		break;
4707c84f3f3cSopenharmony_ci
4708c84f3f3cSopenharmony_ci	case ORD('f'):
4709c84f3f3cSopenharmony_ci	case ORD('F'):
4710c84f3f3cSopenharmony_ci	case ORD('t'):
4711c84f3f3cSopenharmony_ci	case ORD('T'):
4712c84f3f3cSopenharmony_ci		fsavecmd = *cmd;
4713c84f3f3cSopenharmony_ci		fsavech = cmd[1];
4714c84f3f3cSopenharmony_ci		/* FALLTHROUGH */
4715c84f3f3cSopenharmony_ci	case ORD(','):
4716c84f3f3cSopenharmony_ci	case ORD(';'):
4717c84f3f3cSopenharmony_ci		if (fsavecmd == ORD(' '))
4718c84f3f3cSopenharmony_ci			return (-1);
4719c84f3f3cSopenharmony_ci		i = ksh_eq(fsavecmd, 'F', 'f');
4720c84f3f3cSopenharmony_ci		t = rtt2asc(fsavecmd) > rtt2asc('a');
4721c84f3f3cSopenharmony_ci		if (*cmd == ',')
4722c84f3f3cSopenharmony_ci			t = !t;
4723c84f3f3cSopenharmony_ci		if ((ncursor = findch(fsavech, argcnt, tobool(t),
4724c84f3f3cSopenharmony_ci		    tobool(i))) < 0)
4725c84f3f3cSopenharmony_ci			return (-1);
4726c84f3f3cSopenharmony_ci		if (sub && t)
4727c84f3f3cSopenharmony_ci			ncursor++;
4728c84f3f3cSopenharmony_ci		break;
4729c84f3f3cSopenharmony_ci
4730c84f3f3cSopenharmony_ci	case ORD('h'):
4731c84f3f3cSopenharmony_ci	case CTRL_H:
4732c84f3f3cSopenharmony_ci		if (!sub && vs->cursor == 0)
4733c84f3f3cSopenharmony_ci			return (-1);
4734c84f3f3cSopenharmony_ci		ncursor = vs->cursor - argcnt;
4735c84f3f3cSopenharmony_ci		if (ncursor < 0)
4736c84f3f3cSopenharmony_ci			ncursor = 0;
4737c84f3f3cSopenharmony_ci		break;
4738c84f3f3cSopenharmony_ci
4739c84f3f3cSopenharmony_ci	case ORD(' '):
4740c84f3f3cSopenharmony_ci	case ORD('l'):
4741c84f3f3cSopenharmony_ci		if (!sub && vs->cursor + 1 >= vs->linelen)
4742c84f3f3cSopenharmony_ci			return (-1);
4743c84f3f3cSopenharmony_ci		if (vs->linelen != 0) {
4744c84f3f3cSopenharmony_ci			ncursor = vs->cursor + argcnt;
4745c84f3f3cSopenharmony_ci			if (ncursor > vs->linelen)
4746c84f3f3cSopenharmony_ci				ncursor = vs->linelen;
4747c84f3f3cSopenharmony_ci		}
4748c84f3f3cSopenharmony_ci		break;
4749c84f3f3cSopenharmony_ci
4750c84f3f3cSopenharmony_ci	case ORD('w'):
4751c84f3f3cSopenharmony_ci		if (!sub && vs->cursor + 1 >= vs->linelen)
4752c84f3f3cSopenharmony_ci			return (-1);
4753c84f3f3cSopenharmony_ci		ncursor = forwword(argcnt);
4754c84f3f3cSopenharmony_ci		break;
4755c84f3f3cSopenharmony_ci
4756c84f3f3cSopenharmony_ci	case ORD('W'):
4757c84f3f3cSopenharmony_ci		if (!sub && vs->cursor + 1 >= vs->linelen)
4758c84f3f3cSopenharmony_ci			return (-1);
4759c84f3f3cSopenharmony_ci		ncursor = Forwword(argcnt);
4760c84f3f3cSopenharmony_ci		break;
4761c84f3f3cSopenharmony_ci
4762c84f3f3cSopenharmony_ci	case ORD('0'):
4763c84f3f3cSopenharmony_ci		ncursor = 0;
4764c84f3f3cSopenharmony_ci		break;
4765c84f3f3cSopenharmony_ci
4766c84f3f3cSopenharmony_ci	case ORD('^'):
4767c84f3f3cSopenharmony_ci		ncursor = domovebeg();
4768c84f3f3cSopenharmony_ci		break;
4769c84f3f3cSopenharmony_ci
4770c84f3f3cSopenharmony_ci	case ORD('|'):
4771c84f3f3cSopenharmony_ci		ncursor = argcnt;
4772c84f3f3cSopenharmony_ci		if (ncursor > vs->linelen)
4773c84f3f3cSopenharmony_ci			ncursor = vs->linelen;
4774c84f3f3cSopenharmony_ci		if (ncursor)
4775c84f3f3cSopenharmony_ci			ncursor--;
4776c84f3f3cSopenharmony_ci		break;
4777c84f3f3cSopenharmony_ci
4778c84f3f3cSopenharmony_ci	case ORD('$'):
4779c84f3f3cSopenharmony_ci		if (vs->linelen != 0)
4780c84f3f3cSopenharmony_ci			ncursor = vs->linelen;
4781c84f3f3cSopenharmony_ci		else
4782c84f3f3cSopenharmony_ci			ncursor = 0;
4783c84f3f3cSopenharmony_ci		break;
4784c84f3f3cSopenharmony_ci
4785c84f3f3cSopenharmony_ci	case ORD('%'):
4786c84f3f3cSopenharmony_ci		ncursor = vs->cursor;
4787c84f3f3cSopenharmony_ci		while (ncursor < vs->linelen &&
4788c84f3f3cSopenharmony_ci		    (i = bracktype(vs->cbuf[ncursor])) == 0)
4789c84f3f3cSopenharmony_ci			ncursor++;
4790c84f3f3cSopenharmony_ci		if (ncursor == vs->linelen)
4791c84f3f3cSopenharmony_ci			return (-1);
4792c84f3f3cSopenharmony_ci		bcount = 1;
4793c84f3f3cSopenharmony_ci		do {
4794c84f3f3cSopenharmony_ci			if (i > 0) {
4795c84f3f3cSopenharmony_ci				if (++ncursor >= vs->linelen)
4796c84f3f3cSopenharmony_ci					return (-1);
4797c84f3f3cSopenharmony_ci			} else {
4798c84f3f3cSopenharmony_ci				if (--ncursor < 0)
4799c84f3f3cSopenharmony_ci					return (-1);
4800c84f3f3cSopenharmony_ci			}
4801c84f3f3cSopenharmony_ci			t = bracktype(vs->cbuf[ncursor]);
4802c84f3f3cSopenharmony_ci			if (t == i)
4803c84f3f3cSopenharmony_ci				bcount++;
4804c84f3f3cSopenharmony_ci			else if (t == -i)
4805c84f3f3cSopenharmony_ci				bcount--;
4806c84f3f3cSopenharmony_ci		} while (bcount != 0);
4807c84f3f3cSopenharmony_ci		if (sub && i > 0)
4808c84f3f3cSopenharmony_ci			ncursor++;
4809c84f3f3cSopenharmony_ci		break;
4810c84f3f3cSopenharmony_ci
4811c84f3f3cSopenharmony_ci	default:
4812c84f3f3cSopenharmony_ci		return (-1);
4813c84f3f3cSopenharmony_ci	}
4814c84f3f3cSopenharmony_ci	return (ncursor);
4815c84f3f3cSopenharmony_ci}
4816c84f3f3cSopenharmony_ci
4817c84f3f3cSopenharmony_cistatic int
4818c84f3f3cSopenharmony_cidomovebeg(void)
4819c84f3f3cSopenharmony_ci{
4820c84f3f3cSopenharmony_ci	int ncursor = 0;
4821c84f3f3cSopenharmony_ci
4822c84f3f3cSopenharmony_ci	while (ncursor < vs->linelen - 1 &&
4823c84f3f3cSopenharmony_ci	    ctype(vs->cbuf[ncursor], C_SPACE))
4824c84f3f3cSopenharmony_ci		ncursor++;
4825c84f3f3cSopenharmony_ci	return (ncursor);
4826c84f3f3cSopenharmony_ci}
4827c84f3f3cSopenharmony_ci
4828c84f3f3cSopenharmony_cistatic int
4829c84f3f3cSopenharmony_ciredo_insert(int count)
4830c84f3f3cSopenharmony_ci{
4831c84f3f3cSopenharmony_ci	while (count-- > 0)
4832c84f3f3cSopenharmony_ci		if (putbuf(ibuf, inslen, tobool(insert == REPLACE)) != 0)
4833c84f3f3cSopenharmony_ci			return (-1);
4834c84f3f3cSopenharmony_ci	if (vs->cursor > 0)
4835c84f3f3cSopenharmony_ci		vs->cursor--;
4836c84f3f3cSopenharmony_ci	insert = 0;
4837c84f3f3cSopenharmony_ci	return (0);
4838c84f3f3cSopenharmony_ci}
4839c84f3f3cSopenharmony_ci
4840c84f3f3cSopenharmony_cistatic void
4841c84f3f3cSopenharmony_ciyank_range(int a, int b)
4842c84f3f3cSopenharmony_ci{
4843c84f3f3cSopenharmony_ci	yanklen = b - a;
4844c84f3f3cSopenharmony_ci	if (yanklen != 0)
4845c84f3f3cSopenharmony_ci		memmove(ybuf, &vs->cbuf[a], yanklen);
4846c84f3f3cSopenharmony_ci}
4847c84f3f3cSopenharmony_ci
4848c84f3f3cSopenharmony_cistatic int
4849c84f3f3cSopenharmony_cibracktype(int ch)
4850c84f3f3cSopenharmony_ci{
4851c84f3f3cSopenharmony_ci	switch (ord(ch)) {
4852c84f3f3cSopenharmony_ci
4853c84f3f3cSopenharmony_ci	case ORD('('):
4854c84f3f3cSopenharmony_ci		return (1);
4855c84f3f3cSopenharmony_ci
4856c84f3f3cSopenharmony_ci	case ORD('['):
4857c84f3f3cSopenharmony_ci		return (2);
4858c84f3f3cSopenharmony_ci
4859c84f3f3cSopenharmony_ci	case ORD('{'):
4860c84f3f3cSopenharmony_ci		return (3);
4861c84f3f3cSopenharmony_ci
4862c84f3f3cSopenharmony_ci	case ORD(')'):
4863c84f3f3cSopenharmony_ci		return (-1);
4864c84f3f3cSopenharmony_ci
4865c84f3f3cSopenharmony_ci	case ORD(']'):
4866c84f3f3cSopenharmony_ci		return (-2);
4867c84f3f3cSopenharmony_ci
4868c84f3f3cSopenharmony_ci	case ORD('}'):
4869c84f3f3cSopenharmony_ci		return (-3);
4870c84f3f3cSopenharmony_ci
4871c84f3f3cSopenharmony_ci	default:
4872c84f3f3cSopenharmony_ci		return (0);
4873c84f3f3cSopenharmony_ci	}
4874c84f3f3cSopenharmony_ci}
4875c84f3f3cSopenharmony_ci
4876c84f3f3cSopenharmony_ci/*
4877c84f3f3cSopenharmony_ci *	Non user interface editor routines below here
4878c84f3f3cSopenharmony_ci */
4879c84f3f3cSopenharmony_ci
4880c84f3f3cSopenharmony_cistatic void
4881c84f3f3cSopenharmony_cisave_cbuf(void)
4882c84f3f3cSopenharmony_ci{
4883c84f3f3cSopenharmony_ci	memmove(holdbufp, vs->cbuf, vs->linelen);
4884c84f3f3cSopenharmony_ci	holdlen = vs->linelen;
4885c84f3f3cSopenharmony_ci	holdbufp[holdlen] = '\0';
4886c84f3f3cSopenharmony_ci}
4887c84f3f3cSopenharmony_ci
4888c84f3f3cSopenharmony_cistatic void
4889c84f3f3cSopenharmony_cirestore_cbuf(void)
4890c84f3f3cSopenharmony_ci{
4891c84f3f3cSopenharmony_ci	vs->cursor = 0;
4892c84f3f3cSopenharmony_ci	vs->linelen = holdlen;
4893c84f3f3cSopenharmony_ci	memmove(vs->cbuf, holdbufp, holdlen);
4894c84f3f3cSopenharmony_ci}
4895c84f3f3cSopenharmony_ci
4896c84f3f3cSopenharmony_ci/* return a new edstate */
4897c84f3f3cSopenharmony_cistatic struct edstate *
4898c84f3f3cSopenharmony_cisave_edstate(struct edstate *old)
4899c84f3f3cSopenharmony_ci{
4900c84f3f3cSopenharmony_ci	struct edstate *news;
4901c84f3f3cSopenharmony_ci
4902c84f3f3cSopenharmony_ci	news = alloc(sizeof(struct edstate), AEDIT);
4903c84f3f3cSopenharmony_ci	news->cbuf = alloc(old->cbufsize, AEDIT);
4904c84f3f3cSopenharmony_ci	memcpy(news->cbuf, old->cbuf, old->linelen);
4905c84f3f3cSopenharmony_ci	news->cbufsize = old->cbufsize;
4906c84f3f3cSopenharmony_ci	news->linelen = old->linelen;
4907c84f3f3cSopenharmony_ci	news->cursor = old->cursor;
4908c84f3f3cSopenharmony_ci	news->winleft = old->winleft;
4909c84f3f3cSopenharmony_ci	return (news);
4910c84f3f3cSopenharmony_ci}
4911c84f3f3cSopenharmony_ci
4912c84f3f3cSopenharmony_cistatic void
4913c84f3f3cSopenharmony_cirestore_edstate(struct edstate *news, struct edstate *old)
4914c84f3f3cSopenharmony_ci{
4915c84f3f3cSopenharmony_ci	memcpy(news->cbuf, old->cbuf, old->linelen);
4916c84f3f3cSopenharmony_ci	news->linelen = old->linelen;
4917c84f3f3cSopenharmony_ci	news->cursor = old->cursor;
4918c84f3f3cSopenharmony_ci	news->winleft = old->winleft;
4919c84f3f3cSopenharmony_ci	free_edstate(old);
4920c84f3f3cSopenharmony_ci}
4921c84f3f3cSopenharmony_ci
4922c84f3f3cSopenharmony_cistatic void
4923c84f3f3cSopenharmony_cifree_edstate(struct edstate *old)
4924c84f3f3cSopenharmony_ci{
4925c84f3f3cSopenharmony_ci	afree(old->cbuf, AEDIT);
4926c84f3f3cSopenharmony_ci	afree(old, AEDIT);
4927c84f3f3cSopenharmony_ci}
4928c84f3f3cSopenharmony_ci
4929c84f3f3cSopenharmony_ci/*
4930c84f3f3cSopenharmony_ci * this is used for calling x_escape() in complete_word()
4931c84f3f3cSopenharmony_ci */
4932c84f3f3cSopenharmony_cistatic int
4933c84f3f3cSopenharmony_cix_vi_putbuf(const char *s, size_t len)
4934c84f3f3cSopenharmony_ci{
4935c84f3f3cSopenharmony_ci	return (putbuf(s, len, false));
4936c84f3f3cSopenharmony_ci}
4937c84f3f3cSopenharmony_ci
4938c84f3f3cSopenharmony_cistatic int
4939c84f3f3cSopenharmony_ciputbuf(const char *buf, ssize_t len, bool repl)
4940c84f3f3cSopenharmony_ci{
4941c84f3f3cSopenharmony_ci	if (len == 0)
4942c84f3f3cSopenharmony_ci		return (0);
4943c84f3f3cSopenharmony_ci	if (repl) {
4944c84f3f3cSopenharmony_ci		if (vs->cursor + len >= vs->cbufsize)
4945c84f3f3cSopenharmony_ci			return (-1);
4946c84f3f3cSopenharmony_ci		if (vs->cursor + len > vs->linelen)
4947c84f3f3cSopenharmony_ci			vs->linelen = vs->cursor + len;
4948c84f3f3cSopenharmony_ci	} else {
4949c84f3f3cSopenharmony_ci		if (vs->linelen + len >= vs->cbufsize)
4950c84f3f3cSopenharmony_ci			return (-1);
4951c84f3f3cSopenharmony_ci		memmove(&vs->cbuf[vs->cursor + len], &vs->cbuf[vs->cursor],
4952c84f3f3cSopenharmony_ci		    vs->linelen - vs->cursor);
4953c84f3f3cSopenharmony_ci		vs->linelen += len;
4954c84f3f3cSopenharmony_ci	}
4955c84f3f3cSopenharmony_ci	memmove(&vs->cbuf[vs->cursor], buf, len);
4956c84f3f3cSopenharmony_ci	vs->cursor += len;
4957c84f3f3cSopenharmony_ci	return (0);
4958c84f3f3cSopenharmony_ci}
4959c84f3f3cSopenharmony_ci
4960c84f3f3cSopenharmony_cistatic void
4961c84f3f3cSopenharmony_cidel_range(int a, int b)
4962c84f3f3cSopenharmony_ci{
4963c84f3f3cSopenharmony_ci	if (vs->linelen != b)
4964c84f3f3cSopenharmony_ci		memmove(&vs->cbuf[a], &vs->cbuf[b], vs->linelen - b);
4965c84f3f3cSopenharmony_ci	vs->linelen -= b - a;
4966c84f3f3cSopenharmony_ci}
4967c84f3f3cSopenharmony_ci
4968c84f3f3cSopenharmony_cistatic int
4969c84f3f3cSopenharmony_cifindch(int ch, int cnt, bool forw, bool incl)
4970c84f3f3cSopenharmony_ci{
4971c84f3f3cSopenharmony_ci	int ncursor;
4972c84f3f3cSopenharmony_ci
4973c84f3f3cSopenharmony_ci	if (vs->linelen == 0)
4974c84f3f3cSopenharmony_ci		return (-1);
4975c84f3f3cSopenharmony_ci	ncursor = vs->cursor;
4976c84f3f3cSopenharmony_ci	while (cnt--) {
4977c84f3f3cSopenharmony_ci		do {
4978c84f3f3cSopenharmony_ci			if (forw) {
4979c84f3f3cSopenharmony_ci				if (++ncursor == vs->linelen)
4980c84f3f3cSopenharmony_ci					return (-1);
4981c84f3f3cSopenharmony_ci			} else {
4982c84f3f3cSopenharmony_ci				if (--ncursor < 0)
4983c84f3f3cSopenharmony_ci					return (-1);
4984c84f3f3cSopenharmony_ci			}
4985c84f3f3cSopenharmony_ci		} while (vs->cbuf[ncursor] != ch);
4986c84f3f3cSopenharmony_ci	}
4987c84f3f3cSopenharmony_ci	if (!incl) {
4988c84f3f3cSopenharmony_ci		if (forw)
4989c84f3f3cSopenharmony_ci			ncursor--;
4990c84f3f3cSopenharmony_ci		else
4991c84f3f3cSopenharmony_ci			ncursor++;
4992c84f3f3cSopenharmony_ci	}
4993c84f3f3cSopenharmony_ci	return (ncursor);
4994c84f3f3cSopenharmony_ci}
4995c84f3f3cSopenharmony_ci
4996c84f3f3cSopenharmony_cistatic int
4997c84f3f3cSopenharmony_ciforwword(int argcnt)
4998c84f3f3cSopenharmony_ci{
4999c84f3f3cSopenharmony_ci	int ncursor;
5000c84f3f3cSopenharmony_ci
5001c84f3f3cSopenharmony_ci	ncursor = vs->cursor;
5002c84f3f3cSopenharmony_ci	while (ncursor < vs->linelen && argcnt--) {
5003c84f3f3cSopenharmony_ci		if (ctype(vs->cbuf[ncursor], C_ALNUX))
5004c84f3f3cSopenharmony_ci			while (ncursor < vs->linelen &&
5005c84f3f3cSopenharmony_ci			    ctype(vs->cbuf[ncursor], C_ALNUX))
5006c84f3f3cSopenharmony_ci				ncursor++;
5007c84f3f3cSopenharmony_ci		else if (!ctype(vs->cbuf[ncursor], C_SPACE))
5008c84f3f3cSopenharmony_ci			while (ncursor < vs->linelen &&
5009c84f3f3cSopenharmony_ci			    !ctype(vs->cbuf[ncursor], C_ALNUX | C_SPACE))
5010c84f3f3cSopenharmony_ci				ncursor++;
5011c84f3f3cSopenharmony_ci		while (ncursor < vs->linelen &&
5012c84f3f3cSopenharmony_ci		    ctype(vs->cbuf[ncursor], C_SPACE))
5013c84f3f3cSopenharmony_ci			ncursor++;
5014c84f3f3cSopenharmony_ci	}
5015c84f3f3cSopenharmony_ci	return (ncursor);
5016c84f3f3cSopenharmony_ci}
5017c84f3f3cSopenharmony_ci
5018c84f3f3cSopenharmony_cistatic int
5019c84f3f3cSopenharmony_cibackword(int argcnt)
5020c84f3f3cSopenharmony_ci{
5021c84f3f3cSopenharmony_ci	int ncursor;
5022c84f3f3cSopenharmony_ci
5023c84f3f3cSopenharmony_ci	ncursor = vs->cursor;
5024c84f3f3cSopenharmony_ci	while (ncursor > 0 && argcnt--) {
5025c84f3f3cSopenharmony_ci		while (--ncursor > 0 && ctype(vs->cbuf[ncursor], C_SPACE))
5026c84f3f3cSopenharmony_ci			;
5027c84f3f3cSopenharmony_ci		if (ncursor > 0) {
5028c84f3f3cSopenharmony_ci			if (ctype(vs->cbuf[ncursor], C_ALNUX))
5029c84f3f3cSopenharmony_ci				while (--ncursor >= 0 &&
5030c84f3f3cSopenharmony_ci				    ctype(vs->cbuf[ncursor], C_ALNUX))
5031c84f3f3cSopenharmony_ci					;
5032c84f3f3cSopenharmony_ci			else
5033c84f3f3cSopenharmony_ci				while (--ncursor >= 0 &&
5034c84f3f3cSopenharmony_ci				    !ctype(vs->cbuf[ncursor], C_ALNUX | C_SPACE))
5035c84f3f3cSopenharmony_ci					;
5036c84f3f3cSopenharmony_ci			ncursor++;
5037c84f3f3cSopenharmony_ci		}
5038c84f3f3cSopenharmony_ci	}
5039c84f3f3cSopenharmony_ci	return (ncursor);
5040c84f3f3cSopenharmony_ci}
5041c84f3f3cSopenharmony_ci
5042c84f3f3cSopenharmony_cistatic int
5043c84f3f3cSopenharmony_ciendword(int argcnt)
5044c84f3f3cSopenharmony_ci{
5045c84f3f3cSopenharmony_ci	int ncursor;
5046c84f3f3cSopenharmony_ci
5047c84f3f3cSopenharmony_ci	ncursor = vs->cursor;
5048c84f3f3cSopenharmony_ci	while (ncursor < vs->linelen && argcnt--) {
5049c84f3f3cSopenharmony_ci		while (++ncursor < vs->linelen - 1 &&
5050c84f3f3cSopenharmony_ci		    ctype(vs->cbuf[ncursor], C_SPACE))
5051c84f3f3cSopenharmony_ci			;
5052c84f3f3cSopenharmony_ci		if (ncursor < vs->linelen - 1) {
5053c84f3f3cSopenharmony_ci			if (ctype(vs->cbuf[ncursor], C_ALNUX))
5054c84f3f3cSopenharmony_ci				while (++ncursor < vs->linelen &&
5055c84f3f3cSopenharmony_ci				    ctype(vs->cbuf[ncursor], C_ALNUX))
5056c84f3f3cSopenharmony_ci					;
5057c84f3f3cSopenharmony_ci			else
5058c84f3f3cSopenharmony_ci				while (++ncursor < vs->linelen &&
5059c84f3f3cSopenharmony_ci				    !ctype(vs->cbuf[ncursor], C_ALNUX | C_SPACE))
5060c84f3f3cSopenharmony_ci					;
5061c84f3f3cSopenharmony_ci			ncursor--;
5062c84f3f3cSopenharmony_ci		}
5063c84f3f3cSopenharmony_ci	}
5064c84f3f3cSopenharmony_ci	return (ncursor);
5065c84f3f3cSopenharmony_ci}
5066c84f3f3cSopenharmony_ci
5067c84f3f3cSopenharmony_cistatic int
5068c84f3f3cSopenharmony_ciForwword(int argcnt)
5069c84f3f3cSopenharmony_ci{
5070c84f3f3cSopenharmony_ci	int ncursor;
5071c84f3f3cSopenharmony_ci
5072c84f3f3cSopenharmony_ci	ncursor = vs->cursor;
5073c84f3f3cSopenharmony_ci	while (ncursor < vs->linelen && argcnt--) {
5074c84f3f3cSopenharmony_ci		while (ncursor < vs->linelen &&
5075c84f3f3cSopenharmony_ci		    !ctype(vs->cbuf[ncursor], C_SPACE))
5076c84f3f3cSopenharmony_ci			ncursor++;
5077c84f3f3cSopenharmony_ci		while (ncursor < vs->linelen &&
5078c84f3f3cSopenharmony_ci		    ctype(vs->cbuf[ncursor], C_SPACE))
5079c84f3f3cSopenharmony_ci			ncursor++;
5080c84f3f3cSopenharmony_ci	}
5081c84f3f3cSopenharmony_ci	return (ncursor);
5082c84f3f3cSopenharmony_ci}
5083c84f3f3cSopenharmony_ci
5084c84f3f3cSopenharmony_cistatic int
5085c84f3f3cSopenharmony_ciBackword(int argcnt)
5086c84f3f3cSopenharmony_ci{
5087c84f3f3cSopenharmony_ci	int ncursor;
5088c84f3f3cSopenharmony_ci
5089c84f3f3cSopenharmony_ci	ncursor = vs->cursor;
5090c84f3f3cSopenharmony_ci	while (ncursor > 0 && argcnt--) {
5091c84f3f3cSopenharmony_ci		while (--ncursor >= 0 && ctype(vs->cbuf[ncursor], C_SPACE))
5092c84f3f3cSopenharmony_ci			;
5093c84f3f3cSopenharmony_ci		while (ncursor >= 0 && !ctype(vs->cbuf[ncursor], C_SPACE))
5094c84f3f3cSopenharmony_ci			ncursor--;
5095c84f3f3cSopenharmony_ci		ncursor++;
5096c84f3f3cSopenharmony_ci	}
5097c84f3f3cSopenharmony_ci	return (ncursor);
5098c84f3f3cSopenharmony_ci}
5099c84f3f3cSopenharmony_ci
5100c84f3f3cSopenharmony_cistatic int
5101c84f3f3cSopenharmony_ciEndword(int argcnt)
5102c84f3f3cSopenharmony_ci{
5103c84f3f3cSopenharmony_ci	int ncursor;
5104c84f3f3cSopenharmony_ci
5105c84f3f3cSopenharmony_ci	ncursor = vs->cursor;
5106c84f3f3cSopenharmony_ci	while (ncursor < vs->linelen - 1 && argcnt--) {
5107c84f3f3cSopenharmony_ci		while (++ncursor < vs->linelen - 1 &&
5108c84f3f3cSopenharmony_ci		    ctype(vs->cbuf[ncursor], C_SPACE))
5109c84f3f3cSopenharmony_ci			;
5110c84f3f3cSopenharmony_ci		if (ncursor < vs->linelen - 1) {
5111c84f3f3cSopenharmony_ci			while (++ncursor < vs->linelen &&
5112c84f3f3cSopenharmony_ci			    !ctype(vs->cbuf[ncursor], C_SPACE))
5113c84f3f3cSopenharmony_ci				;
5114c84f3f3cSopenharmony_ci			ncursor--;
5115c84f3f3cSopenharmony_ci		}
5116c84f3f3cSopenharmony_ci	}
5117c84f3f3cSopenharmony_ci	return (ncursor);
5118c84f3f3cSopenharmony_ci}
5119c84f3f3cSopenharmony_ci
5120c84f3f3cSopenharmony_cistatic int
5121c84f3f3cSopenharmony_cigrabhist(int save, int n)
5122c84f3f3cSopenharmony_ci{
5123c84f3f3cSopenharmony_ci	char *hptr;
5124c84f3f3cSopenharmony_ci
5125c84f3f3cSopenharmony_ci	if (n < 0 || n > hlast)
5126c84f3f3cSopenharmony_ci		return (-1);
5127c84f3f3cSopenharmony_ci	if (n == hlast) {
5128c84f3f3cSopenharmony_ci		restore_cbuf();
5129c84f3f3cSopenharmony_ci		ohnum = n;
5130c84f3f3cSopenharmony_ci		return (0);
5131c84f3f3cSopenharmony_ci	}
5132c84f3f3cSopenharmony_ci	(void)histnum(n);
5133c84f3f3cSopenharmony_ci	if ((hptr = *histpos()) == NULL) {
5134c84f3f3cSopenharmony_ci		internal_warningf("grabhist: bad history array");
5135c84f3f3cSopenharmony_ci		return (-1);
5136c84f3f3cSopenharmony_ci	}
5137c84f3f3cSopenharmony_ci	if (save)
5138c84f3f3cSopenharmony_ci		save_cbuf();
5139c84f3f3cSopenharmony_ci	if ((vs->linelen = strlen(hptr)) >= vs->cbufsize)
5140c84f3f3cSopenharmony_ci		vs->linelen = vs->cbufsize - 1;
5141c84f3f3cSopenharmony_ci	memmove(vs->cbuf, hptr, vs->linelen);
5142c84f3f3cSopenharmony_ci	vs->cursor = 0;
5143c84f3f3cSopenharmony_ci	ohnum = n;
5144c84f3f3cSopenharmony_ci	return (0);
5145c84f3f3cSopenharmony_ci}
5146c84f3f3cSopenharmony_ci
5147c84f3f3cSopenharmony_cistatic int
5148c84f3f3cSopenharmony_cigrabsearch(const char *pat, int save, int start, bool fwd)
5149c84f3f3cSopenharmony_ci{
5150c84f3f3cSopenharmony_ci	char *hptr;
5151c84f3f3cSopenharmony_ci	int hist;
5152c84f3f3cSopenharmony_ci	bool anchored;
5153c84f3f3cSopenharmony_ci
5154c84f3f3cSopenharmony_ci	if ((start == 0 && !fwd) || (start >= hlast - 1 && fwd))
5155c84f3f3cSopenharmony_ci		return (-1);
5156c84f3f3cSopenharmony_ci	if (fwd)
5157c84f3f3cSopenharmony_ci		start++;
5158c84f3f3cSopenharmony_ci	else
5159c84f3f3cSopenharmony_ci		start--;
5160c84f3f3cSopenharmony_ci	anchored = *pat == '^' ? (++pat, true) : false;
5161c84f3f3cSopenharmony_ci	if ((hist = findhist(start, pat, fwd, anchored)) < 0) {
5162c84f3f3cSopenharmony_ci		/* (start != 0 && fwd && match(holdbufp, pat) >= 0) */
5163c84f3f3cSopenharmony_ci		if (start != 0 && fwd && strcmp(holdbufp, pat) >= 0) {
5164c84f3f3cSopenharmony_ci			restore_cbuf();
5165c84f3f3cSopenharmony_ci			return (0);
5166c84f3f3cSopenharmony_ci		} else
5167c84f3f3cSopenharmony_ci			return (-1);
5168c84f3f3cSopenharmony_ci	}
5169c84f3f3cSopenharmony_ci	if (save)
5170c84f3f3cSopenharmony_ci		save_cbuf();
5171c84f3f3cSopenharmony_ci	histnum(hist);
5172c84f3f3cSopenharmony_ci	hptr = *histpos();
5173c84f3f3cSopenharmony_ci	if ((vs->linelen = strlen(hptr)) >= vs->cbufsize)
5174c84f3f3cSopenharmony_ci		vs->linelen = vs->cbufsize - 1;
5175c84f3f3cSopenharmony_ci	memmove(vs->cbuf, hptr, vs->linelen);
5176c84f3f3cSopenharmony_ci	vs->cursor = 0;
5177c84f3f3cSopenharmony_ci	return (hist);
5178c84f3f3cSopenharmony_ci}
5179c84f3f3cSopenharmony_ci
5180c84f3f3cSopenharmony_cistatic void
5181c84f3f3cSopenharmony_ciredraw_line(bool newl)
5182c84f3f3cSopenharmony_ci{
5183c84f3f3cSopenharmony_ci	if (wbuf_len)
5184c84f3f3cSopenharmony_ci		memset(wbuf[win], ' ', wbuf_len);
5185c84f3f3cSopenharmony_ci	if (newl) {
5186c84f3f3cSopenharmony_ci		x_putc('\r');
5187c84f3f3cSopenharmony_ci		x_putc('\n');
5188c84f3f3cSopenharmony_ci	}
5189c84f3f3cSopenharmony_ci	x_pprompt();
5190c84f3f3cSopenharmony_ci	morec = ' ';
5191c84f3f3cSopenharmony_ci}
5192c84f3f3cSopenharmony_ci
5193c84f3f3cSopenharmony_cistatic void
5194c84f3f3cSopenharmony_cirefresh(bool leftside)
5195c84f3f3cSopenharmony_ci{
5196c84f3f3cSopenharmony_ci	if (outofwin())
5197c84f3f3cSopenharmony_ci		rewindow();
5198c84f3f3cSopenharmony_ci	display(wbuf[1 - win], wbuf[win], leftside);
5199c84f3f3cSopenharmony_ci	win = 1 - win;
5200c84f3f3cSopenharmony_ci}
5201c84f3f3cSopenharmony_ci
5202c84f3f3cSopenharmony_cistatic int
5203c84f3f3cSopenharmony_cioutofwin(void)
5204c84f3f3cSopenharmony_ci{
5205c84f3f3cSopenharmony_ci	int cur, col;
5206c84f3f3cSopenharmony_ci
5207c84f3f3cSopenharmony_ci	if (vs->cursor < vs->winleft)
5208c84f3f3cSopenharmony_ci		return (1);
5209c84f3f3cSopenharmony_ci	col = 0;
5210c84f3f3cSopenharmony_ci	cur = vs->winleft;
5211c84f3f3cSopenharmony_ci	while (cur < vs->cursor)
5212c84f3f3cSopenharmony_ci		col = newcol((unsigned char)vs->cbuf[cur++], col);
5213c84f3f3cSopenharmony_ci	if (col >= winwidth)
5214c84f3f3cSopenharmony_ci		return (1);
5215c84f3f3cSopenharmony_ci	return (0);
5216c84f3f3cSopenharmony_ci}
5217c84f3f3cSopenharmony_ci
5218c84f3f3cSopenharmony_cistatic void
5219c84f3f3cSopenharmony_cirewindow(void)
5220c84f3f3cSopenharmony_ci{
5221c84f3f3cSopenharmony_ci	int tcur, tcol;
5222c84f3f3cSopenharmony_ci	int holdcur1, holdcol1;
5223c84f3f3cSopenharmony_ci	int holdcur2, holdcol2;
5224c84f3f3cSopenharmony_ci
5225c84f3f3cSopenharmony_ci	holdcur1 = holdcur2 = tcur = 0;
5226c84f3f3cSopenharmony_ci	holdcol1 = holdcol2 = tcol = 0;
5227c84f3f3cSopenharmony_ci	while (tcur < vs->cursor) {
5228c84f3f3cSopenharmony_ci		if (tcol - holdcol2 > winwidth / 2) {
5229c84f3f3cSopenharmony_ci			holdcur1 = holdcur2;
5230c84f3f3cSopenharmony_ci			holdcol1 = holdcol2;
5231c84f3f3cSopenharmony_ci			holdcur2 = tcur;
5232c84f3f3cSopenharmony_ci			holdcol2 = tcol;
5233c84f3f3cSopenharmony_ci		}
5234c84f3f3cSopenharmony_ci		tcol = newcol((unsigned char)vs->cbuf[tcur++], tcol);
5235c84f3f3cSopenharmony_ci	}
5236c84f3f3cSopenharmony_ci	while (tcol - holdcol1 > winwidth / 2)
5237c84f3f3cSopenharmony_ci		holdcol1 = newcol((unsigned char)vs->cbuf[holdcur1++],
5238c84f3f3cSopenharmony_ci		    holdcol1);
5239c84f3f3cSopenharmony_ci	vs->winleft = holdcur1;
5240c84f3f3cSopenharmony_ci}
5241c84f3f3cSopenharmony_ci
5242c84f3f3cSopenharmony_cistatic int
5243c84f3f3cSopenharmony_cinewcol(unsigned char ch, int col)
5244c84f3f3cSopenharmony_ci{
5245c84f3f3cSopenharmony_ci	if (ch == '\t')
5246c84f3f3cSopenharmony_ci		return ((col | 7) + 1);
5247c84f3f3cSopenharmony_ci	return (col + char_len(ch));
5248c84f3f3cSopenharmony_ci}
5249c84f3f3cSopenharmony_ci
5250c84f3f3cSopenharmony_cistatic void
5251c84f3f3cSopenharmony_cidisplay(char *wb1, char *wb2, bool leftside)
5252c84f3f3cSopenharmony_ci{
5253c84f3f3cSopenharmony_ci	unsigned char ch;
5254c84f3f3cSopenharmony_ci	char *twb1, *twb2, mc;
5255c84f3f3cSopenharmony_ci	int cur, col, cnt;
5256c84f3f3cSopenharmony_ci	int ncol = 0;
5257c84f3f3cSopenharmony_ci	int moreright;
5258c84f3f3cSopenharmony_ci
5259c84f3f3cSopenharmony_ci	col = 0;
5260c84f3f3cSopenharmony_ci	cur = vs->winleft;
5261c84f3f3cSopenharmony_ci	moreright = 0;
5262c84f3f3cSopenharmony_ci	twb1 = wb1;
5263c84f3f3cSopenharmony_ci	while (col < winwidth && cur < vs->linelen) {
5264c84f3f3cSopenharmony_ci		if (cur == vs->cursor && leftside)
5265c84f3f3cSopenharmony_ci			ncol = col + pwidth;
5266c84f3f3cSopenharmony_ci		if ((ch = vs->cbuf[cur]) == '\t')
5267c84f3f3cSopenharmony_ci			do {
5268c84f3f3cSopenharmony_ci				*twb1++ = ' ';
5269c84f3f3cSopenharmony_ci			} while (++col < winwidth && (col & 7) != 0);
5270c84f3f3cSopenharmony_ci		else if (col < winwidth) {
5271c84f3f3cSopenharmony_ci			if (ksh_isctrl(ch)) {
5272c84f3f3cSopenharmony_ci				*twb1++ = '^';
5273c84f3f3cSopenharmony_ci				if (++col < winwidth) {
5274c84f3f3cSopenharmony_ci					*twb1++ = ksh_unctrl(ch);
5275c84f3f3cSopenharmony_ci					col++;
5276c84f3f3cSopenharmony_ci				}
5277c84f3f3cSopenharmony_ci			} else {
5278c84f3f3cSopenharmony_ci				*twb1++ = ch;
5279c84f3f3cSopenharmony_ci				col++;
5280c84f3f3cSopenharmony_ci			}
5281c84f3f3cSopenharmony_ci		}
5282c84f3f3cSopenharmony_ci		if (cur == vs->cursor && !leftside)
5283c84f3f3cSopenharmony_ci			ncol = col + pwidth - 1;
5284c84f3f3cSopenharmony_ci		cur++;
5285c84f3f3cSopenharmony_ci	}
5286c84f3f3cSopenharmony_ci	if (cur == vs->cursor)
5287c84f3f3cSopenharmony_ci		ncol = col + pwidth;
5288c84f3f3cSopenharmony_ci	if (col < winwidth) {
5289c84f3f3cSopenharmony_ci		while (col < winwidth) {
5290c84f3f3cSopenharmony_ci			*twb1++ = ' ';
5291c84f3f3cSopenharmony_ci			col++;
5292c84f3f3cSopenharmony_ci		}
5293c84f3f3cSopenharmony_ci	} else
5294c84f3f3cSopenharmony_ci		moreright++;
5295c84f3f3cSopenharmony_ci	*twb1 = ' ';
5296c84f3f3cSopenharmony_ci
5297c84f3f3cSopenharmony_ci	col = pwidth;
5298c84f3f3cSopenharmony_ci	cnt = winwidth;
5299c84f3f3cSopenharmony_ci	twb1 = wb1;
5300c84f3f3cSopenharmony_ci	twb2 = wb2;
5301c84f3f3cSopenharmony_ci	while (cnt--) {
5302c84f3f3cSopenharmony_ci		if (*twb1 != *twb2) {
5303c84f3f3cSopenharmony_ci			if (x_col != col)
5304c84f3f3cSopenharmony_ci				ed_mov_opt(col, wb1);
5305c84f3f3cSopenharmony_ci			x_putc(*twb1);
5306c84f3f3cSopenharmony_ci			x_col++;
5307c84f3f3cSopenharmony_ci		}
5308c84f3f3cSopenharmony_ci		twb1++;
5309c84f3f3cSopenharmony_ci		twb2++;
5310c84f3f3cSopenharmony_ci		col++;
5311c84f3f3cSopenharmony_ci	}
5312c84f3f3cSopenharmony_ci	if (vs->winleft > 0 && moreright)
5313c84f3f3cSopenharmony_ci		/*
5314c84f3f3cSopenharmony_ci		 * POSIX says to use * for this but that is a globbing
5315c84f3f3cSopenharmony_ci		 * character and may confuse people; + is more innocuous
5316c84f3f3cSopenharmony_ci		 */
5317c84f3f3cSopenharmony_ci		mc = '+';
5318c84f3f3cSopenharmony_ci	else if (vs->winleft > 0)
5319c84f3f3cSopenharmony_ci		mc = '<';
5320c84f3f3cSopenharmony_ci	else if (moreright)
5321c84f3f3cSopenharmony_ci		mc = '>';
5322c84f3f3cSopenharmony_ci	else
5323c84f3f3cSopenharmony_ci		mc = ' ';
5324c84f3f3cSopenharmony_ci	if (mc != morec) {
5325c84f3f3cSopenharmony_ci		ed_mov_opt(pwidth + winwidth + 1, wb1);
5326c84f3f3cSopenharmony_ci		x_putc(mc);
5327c84f3f3cSopenharmony_ci		x_col++;
5328c84f3f3cSopenharmony_ci		morec = mc;
5329c84f3f3cSopenharmony_ci	}
5330c84f3f3cSopenharmony_ci	if (x_col != ncol)
5331c84f3f3cSopenharmony_ci		ed_mov_opt(ncol, wb1);
5332c84f3f3cSopenharmony_ci}
5333c84f3f3cSopenharmony_ci
5334c84f3f3cSopenharmony_cistatic void
5335c84f3f3cSopenharmony_cied_mov_opt(int col, char *wb)
5336c84f3f3cSopenharmony_ci{
5337c84f3f3cSopenharmony_ci	if (col < x_col) {
5338c84f3f3cSopenharmony_ci		if (col + 1 < x_col - col) {
5339c84f3f3cSopenharmony_ci			x_putc('\r');
5340c84f3f3cSopenharmony_ci			x_pprompt();
5341c84f3f3cSopenharmony_ci			while (x_col++ < col)
5342c84f3f3cSopenharmony_ci				x_putcf(*wb++);
5343c84f3f3cSopenharmony_ci		} else {
5344c84f3f3cSopenharmony_ci			while (x_col-- > col)
5345c84f3f3cSopenharmony_ci				x_putc('\b');
5346c84f3f3cSopenharmony_ci		}
5347c84f3f3cSopenharmony_ci	} else {
5348c84f3f3cSopenharmony_ci		wb = &wb[x_col - pwidth];
5349c84f3f3cSopenharmony_ci		while (x_col++ < col)
5350c84f3f3cSopenharmony_ci			x_putcf(*wb++);
5351c84f3f3cSopenharmony_ci	}
5352c84f3f3cSopenharmony_ci	x_col = col;
5353c84f3f3cSopenharmony_ci}
5354c84f3f3cSopenharmony_ci
5355c84f3f3cSopenharmony_ci
5356c84f3f3cSopenharmony_ci/* replace word with all expansions (ie, expand word*) */
5357c84f3f3cSopenharmony_cistatic int
5358c84f3f3cSopenharmony_ciexpand_word(int cmd)
5359c84f3f3cSopenharmony_ci{
5360c84f3f3cSopenharmony_ci	static struct edstate *buf;
5361c84f3f3cSopenharmony_ci	int rval = 0, nwords, start, end, i;
5362c84f3f3cSopenharmony_ci	char **words;
5363c84f3f3cSopenharmony_ci
5364c84f3f3cSopenharmony_ci	/* Undo previous expansion */
5365c84f3f3cSopenharmony_ci	if (cmd == 0 && expanded == EXPAND && buf) {
5366c84f3f3cSopenharmony_ci		restore_edstate(vs, buf);
5367c84f3f3cSopenharmony_ci		buf = 0;
5368c84f3f3cSopenharmony_ci		expanded = NONE;
5369c84f3f3cSopenharmony_ci		return (0);
5370c84f3f3cSopenharmony_ci	}
5371c84f3f3cSopenharmony_ci	if (buf) {
5372c84f3f3cSopenharmony_ci		free_edstate(buf);
5373c84f3f3cSopenharmony_ci		buf = 0;
5374c84f3f3cSopenharmony_ci	}
5375c84f3f3cSopenharmony_ci
5376c84f3f3cSopenharmony_ci	i = XCF_COMMAND_FILE | XCF_FULLPATH;
5377c84f3f3cSopenharmony_ci	nwords = x_cf_glob(&i, vs->cbuf, vs->linelen, vs->cursor,
5378c84f3f3cSopenharmony_ci	    &start, &end, &words);
5379c84f3f3cSopenharmony_ci	if (nwords == 0) {
5380c84f3f3cSopenharmony_ci		vi_error();
5381c84f3f3cSopenharmony_ci		return (-1);
5382c84f3f3cSopenharmony_ci	}
5383c84f3f3cSopenharmony_ci
5384c84f3f3cSopenharmony_ci	buf = save_edstate(vs);
5385c84f3f3cSopenharmony_ci	expanded = EXPAND;
5386c84f3f3cSopenharmony_ci	del_range(start, end);
5387c84f3f3cSopenharmony_ci	vs->cursor = start;
5388c84f3f3cSopenharmony_ci	i = 0;
5389c84f3f3cSopenharmony_ci	while (i < nwords) {
5390c84f3f3cSopenharmony_ci		if (x_escape(words[i], strlen(words[i]), x_vi_putbuf) != 0) {
5391c84f3f3cSopenharmony_ci			rval = -1;
5392c84f3f3cSopenharmony_ci			break;
5393c84f3f3cSopenharmony_ci		}
5394c84f3f3cSopenharmony_ci		if (++i < nwords && putbuf(T1space, 1, false) != 0) {
5395c84f3f3cSopenharmony_ci			rval = -1;
5396c84f3f3cSopenharmony_ci			break;
5397c84f3f3cSopenharmony_ci		}
5398c84f3f3cSopenharmony_ci	}
5399c84f3f3cSopenharmony_ci	i = buf->cursor - end;
5400c84f3f3cSopenharmony_ci	if (rval == 0 && i > 0)
5401c84f3f3cSopenharmony_ci		vs->cursor += i;
5402c84f3f3cSopenharmony_ci	modified = 1;
5403c84f3f3cSopenharmony_ci	hnum = hlast;
5404c84f3f3cSopenharmony_ci	insert = INSERT;
5405c84f3f3cSopenharmony_ci	lastac = 0;
5406c84f3f3cSopenharmony_ci	refresh(false);
5407c84f3f3cSopenharmony_ci	return (rval);
5408c84f3f3cSopenharmony_ci}
5409c84f3f3cSopenharmony_ci
5410c84f3f3cSopenharmony_cistatic int
5411c84f3f3cSopenharmony_cicomplete_word(int cmd, int count)
5412c84f3f3cSopenharmony_ci{
5413c84f3f3cSopenharmony_ci	static struct edstate *buf;
5414c84f3f3cSopenharmony_ci	int rval, nwords, start, end, flags;
5415c84f3f3cSopenharmony_ci	size_t match_len;
5416c84f3f3cSopenharmony_ci	char **words;
5417c84f3f3cSopenharmony_ci	char *match;
5418c84f3f3cSopenharmony_ci	bool is_unique;
5419c84f3f3cSopenharmony_ci
5420c84f3f3cSopenharmony_ci	/* Undo previous completion */
5421c84f3f3cSopenharmony_ci	if (cmd == 0 && expanded == COMPLETE && buf) {
5422c84f3f3cSopenharmony_ci		print_expansions(buf, 0);
5423c84f3f3cSopenharmony_ci		expanded = PRINT;
5424c84f3f3cSopenharmony_ci		return (0);
5425c84f3f3cSopenharmony_ci	}
5426c84f3f3cSopenharmony_ci	if (cmd == 0 && expanded == PRINT && buf) {
5427c84f3f3cSopenharmony_ci		restore_edstate(vs, buf);
5428c84f3f3cSopenharmony_ci		buf = 0;
5429c84f3f3cSopenharmony_ci		expanded = NONE;
5430c84f3f3cSopenharmony_ci		return (0);
5431c84f3f3cSopenharmony_ci	}
5432c84f3f3cSopenharmony_ci	if (buf) {
5433c84f3f3cSopenharmony_ci		free_edstate(buf);
5434c84f3f3cSopenharmony_ci		buf = 0;
5435c84f3f3cSopenharmony_ci	}
5436c84f3f3cSopenharmony_ci
5437c84f3f3cSopenharmony_ci	/*
5438c84f3f3cSopenharmony_ci	 * XCF_FULLPATH for count 'cause the menu printed by
5439c84f3f3cSopenharmony_ci	 * print_expansions() was done this way.
5440c84f3f3cSopenharmony_ci	 */
5441c84f3f3cSopenharmony_ci	flags = XCF_COMMAND_FILE;
5442c84f3f3cSopenharmony_ci	if (count)
5443c84f3f3cSopenharmony_ci		flags |= XCF_FULLPATH;
5444c84f3f3cSopenharmony_ci	nwords = x_cf_glob(&flags, vs->cbuf, vs->linelen, vs->cursor,
5445c84f3f3cSopenharmony_ci	    &start, &end, &words);
5446c84f3f3cSopenharmony_ci	if (nwords == 0) {
5447c84f3f3cSopenharmony_ci		vi_error();
5448c84f3f3cSopenharmony_ci		return (-1);
5449c84f3f3cSopenharmony_ci	}
5450c84f3f3cSopenharmony_ci	if (count) {
5451c84f3f3cSopenharmony_ci		int i;
5452c84f3f3cSopenharmony_ci
5453c84f3f3cSopenharmony_ci		count--;
5454c84f3f3cSopenharmony_ci		if (count >= nwords) {
5455c84f3f3cSopenharmony_ci			vi_error();
5456c84f3f3cSopenharmony_ci			x_print_expansions(nwords, words,
5457c84f3f3cSopenharmony_ci			    tobool(flags & XCF_IS_COMMAND));
5458c84f3f3cSopenharmony_ci			x_free_words(nwords, words);
5459c84f3f3cSopenharmony_ci			redraw_line(false);
5460c84f3f3cSopenharmony_ci			return (-1);
5461c84f3f3cSopenharmony_ci		}
5462c84f3f3cSopenharmony_ci		/*
5463c84f3f3cSopenharmony_ci		 * Expand the count'th word to its basename
5464c84f3f3cSopenharmony_ci		 */
5465c84f3f3cSopenharmony_ci		if (flags & XCF_IS_COMMAND) {
5466c84f3f3cSopenharmony_ci			match = words[count] +
5467c84f3f3cSopenharmony_ci			    x_basename(words[count], NULL);
5468c84f3f3cSopenharmony_ci			/* If more than one possible match, use full path */
5469c84f3f3cSopenharmony_ci			for (i = 0; i < nwords; i++)
5470c84f3f3cSopenharmony_ci				if (i != count &&
5471c84f3f3cSopenharmony_ci				    strcmp(words[i] + x_basename(words[i],
5472c84f3f3cSopenharmony_ci				    NULL), match) == 0) {
5473c84f3f3cSopenharmony_ci					match = words[count];
5474c84f3f3cSopenharmony_ci					break;
5475c84f3f3cSopenharmony_ci				}
5476c84f3f3cSopenharmony_ci		} else
5477c84f3f3cSopenharmony_ci			match = words[count];
5478c84f3f3cSopenharmony_ci		match_len = strlen(match);
5479c84f3f3cSopenharmony_ci		is_unique = true;
5480c84f3f3cSopenharmony_ci		/* expanded = PRINT;	next call undo */
5481c84f3f3cSopenharmony_ci	} else {
5482c84f3f3cSopenharmony_ci		match = words[0];
5483c84f3f3cSopenharmony_ci		match_len = x_longest_prefix(nwords, words);
5484c84f3f3cSopenharmony_ci		/* next call will list completions */
5485c84f3f3cSopenharmony_ci		expanded = COMPLETE;
5486c84f3f3cSopenharmony_ci		is_unique = nwords == 1;
5487c84f3f3cSopenharmony_ci	}
5488c84f3f3cSopenharmony_ci
5489c84f3f3cSopenharmony_ci	buf = save_edstate(vs);
5490c84f3f3cSopenharmony_ci	del_range(start, end);
5491c84f3f3cSopenharmony_ci	vs->cursor = start;
5492c84f3f3cSopenharmony_ci
5493c84f3f3cSopenharmony_ci	/*
5494c84f3f3cSopenharmony_ci	 * escape all shell-sensitive characters and put the result into
5495c84f3f3cSopenharmony_ci	 * command buffer
5496c84f3f3cSopenharmony_ci	 */
5497c84f3f3cSopenharmony_ci	rval = x_escape(match, match_len, x_vi_putbuf);
5498c84f3f3cSopenharmony_ci
5499c84f3f3cSopenharmony_ci	if (rval == 0 && is_unique) {
5500c84f3f3cSopenharmony_ci		/*
5501c84f3f3cSopenharmony_ci		 * If exact match, don't undo. Allows directory completions
5502c84f3f3cSopenharmony_ci		 * to be used (ie, complete the next portion of the path).
5503c84f3f3cSopenharmony_ci		 */
5504c84f3f3cSopenharmony_ci		expanded = NONE;
5505c84f3f3cSopenharmony_ci
5506c84f3f3cSopenharmony_ci		/*
5507c84f3f3cSopenharmony_ci		 * append a space if this is a non-directory match
5508c84f3f3cSopenharmony_ci		 * and not a parameter or homedir substitution
5509c84f3f3cSopenharmony_ci		 */
5510c84f3f3cSopenharmony_ci		if (match_len > 0 && !mksh_cdirsep(match[match_len - 1]) &&
5511c84f3f3cSopenharmony_ci		    !(flags & XCF_IS_NOSPACE))
5512c84f3f3cSopenharmony_ci			rval = putbuf(T1space, 1, false);
5513c84f3f3cSopenharmony_ci	}
5514c84f3f3cSopenharmony_ci	x_free_words(nwords, words);
5515c84f3f3cSopenharmony_ci
5516c84f3f3cSopenharmony_ci	modified = 1;
5517c84f3f3cSopenharmony_ci	hnum = hlast;
5518c84f3f3cSopenharmony_ci	insert = INSERT;
5519c84f3f3cSopenharmony_ci	/* prevent this from being redone... */
5520c84f3f3cSopenharmony_ci	lastac = 0;
5521c84f3f3cSopenharmony_ci	refresh(false);
5522c84f3f3cSopenharmony_ci
5523c84f3f3cSopenharmony_ci	return (rval);
5524c84f3f3cSopenharmony_ci}
5525c84f3f3cSopenharmony_ci
5526c84f3f3cSopenharmony_cistatic int
5527c84f3f3cSopenharmony_ciprint_expansions(struct edstate *est, int cmd MKSH_A_UNUSED)
5528c84f3f3cSopenharmony_ci{
5529c84f3f3cSopenharmony_ci	int start, end, nwords, i;
5530c84f3f3cSopenharmony_ci	char **words;
5531c84f3f3cSopenharmony_ci
5532c84f3f3cSopenharmony_ci	i = XCF_COMMAND_FILE | XCF_FULLPATH;
5533c84f3f3cSopenharmony_ci	nwords = x_cf_glob(&i, est->cbuf, est->linelen, est->cursor,
5534c84f3f3cSopenharmony_ci	    &start, &end, &words);
5535c84f3f3cSopenharmony_ci	if (nwords == 0) {
5536c84f3f3cSopenharmony_ci		vi_error();
5537c84f3f3cSopenharmony_ci		return (-1);
5538c84f3f3cSopenharmony_ci	}
5539c84f3f3cSopenharmony_ci	x_print_expansions(nwords, words, tobool(i & XCF_IS_COMMAND));
5540c84f3f3cSopenharmony_ci	x_free_words(nwords, words);
5541c84f3f3cSopenharmony_ci	redraw_line(false);
5542c84f3f3cSopenharmony_ci	return (0);
5543c84f3f3cSopenharmony_ci}
5544c84f3f3cSopenharmony_ci#endif /* !MKSH_S_NOVI */
5545c84f3f3cSopenharmony_ci
5546c84f3f3cSopenharmony_ci/* Similar to x_zotc(emacs.c), but no tab weirdness */
5547c84f3f3cSopenharmony_cistatic void
5548c84f3f3cSopenharmony_cix_vi_zotc(int c)
5549c84f3f3cSopenharmony_ci{
5550c84f3f3cSopenharmony_ci	if (ksh_isctrl(c)) {
5551c84f3f3cSopenharmony_ci		x_putc('^');
5552c84f3f3cSopenharmony_ci		c = ksh_unctrl(c);
5553c84f3f3cSopenharmony_ci	}
5554c84f3f3cSopenharmony_ci	x_putc(c);
5555c84f3f3cSopenharmony_ci}
5556c84f3f3cSopenharmony_ci
5557c84f3f3cSopenharmony_ci#if !MKSH_S_NOVI
5558c84f3f3cSopenharmony_cistatic void
5559c84f3f3cSopenharmony_civi_error(void)
5560c84f3f3cSopenharmony_ci{
5561c84f3f3cSopenharmony_ci	/* Beem out of any macros as soon as an error occurs */
5562c84f3f3cSopenharmony_ci	vi_macro_reset();
5563c84f3f3cSopenharmony_ci	x_putc(KSH_BEL);
5564c84f3f3cSopenharmony_ci	x_flush();
5565c84f3f3cSopenharmony_ci}
5566c84f3f3cSopenharmony_ci
5567c84f3f3cSopenharmony_cistatic void
5568c84f3f3cSopenharmony_civi_macro_reset(void)
5569c84f3f3cSopenharmony_ci{
5570c84f3f3cSopenharmony_ci	if (macro.p) {
5571c84f3f3cSopenharmony_ci		afree(macro.buf, AEDIT);
5572c84f3f3cSopenharmony_ci		memset((char *)&macro, 0, sizeof(macro));
5573c84f3f3cSopenharmony_ci	}
5574c84f3f3cSopenharmony_ci}
5575c84f3f3cSopenharmony_ci#endif /* !MKSH_S_NOVI */
5576c84f3f3cSopenharmony_ci
5577c84f3f3cSopenharmony_ci/* called from main.c */
5578c84f3f3cSopenharmony_civoid
5579c84f3f3cSopenharmony_cix_init(void)
5580c84f3f3cSopenharmony_ci{
5581c84f3f3cSopenharmony_ci	int i, j;
5582c84f3f3cSopenharmony_ci
5583c84f3f3cSopenharmony_ci	/*
5584c84f3f3cSopenharmony_ci	 * set edchars to force initial binding, except we need
5585c84f3f3cSopenharmony_ci	 * default values for ^W for some deficient systems…
5586c84f3f3cSopenharmony_ci	 */
5587c84f3f3cSopenharmony_ci	edchars.erase = edchars.kill = edchars.intr = edchars.quit =
5588c84f3f3cSopenharmony_ci	    edchars.eof = EDCHAR_INITIAL;
5589c84f3f3cSopenharmony_ci	edchars.werase = 027;
5590c84f3f3cSopenharmony_ci
5591c84f3f3cSopenharmony_ci	/* command line editing specific memory allocation */
5592c84f3f3cSopenharmony_ci	ainit(AEDIT);
5593c84f3f3cSopenharmony_ci	holdbufp = alloc(LINE, AEDIT);
5594c84f3f3cSopenharmony_ci
5595c84f3f3cSopenharmony_ci	/* initialise Emacs command line editing mode */
5596c84f3f3cSopenharmony_ci	x_nextcmd = -1;
5597c84f3f3cSopenharmony_ci
5598c84f3f3cSopenharmony_ci	x_tab = alloc2(X_NTABS, sizeof(*x_tab), AEDIT);
5599c84f3f3cSopenharmony_ci	for (j = 0; j < X_TABSZ; j++)
5600c84f3f3cSopenharmony_ci		x_tab[0][j] = XFUNC_insert;
5601c84f3f3cSopenharmony_ci	for (i = 1; i < X_NTABS; i++)
5602c84f3f3cSopenharmony_ci		for (j = 0; j < X_TABSZ; j++)
5603c84f3f3cSopenharmony_ci			x_tab[i][j] = XFUNC_error;
5604c84f3f3cSopenharmony_ci	for (i = 0; i < (int)NELEM(x_defbindings); i++)
5605c84f3f3cSopenharmony_ci		x_tab[x_defbindings[i].xdb_tab][x_defbindings[i].xdb_char]
5606c84f3f3cSopenharmony_ci		    = x_defbindings[i].xdb_func;
5607c84f3f3cSopenharmony_ci
5608c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
5609c84f3f3cSopenharmony_ci	x_atab = alloc2(X_NTABS, sizeof(*x_atab), AEDIT);
5610c84f3f3cSopenharmony_ci	for (i = 1; i < X_NTABS; i++)
5611c84f3f3cSopenharmony_ci		for (j = 0; j < X_TABSZ; j++)
5612c84f3f3cSopenharmony_ci			x_atab[i][j] = NULL;
5613c84f3f3cSopenharmony_ci#endif
5614c84f3f3cSopenharmony_ci}
5615c84f3f3cSopenharmony_ci
5616c84f3f3cSopenharmony_ci#ifdef DEBUG_LEAKS
5617c84f3f3cSopenharmony_civoid
5618c84f3f3cSopenharmony_cix_done(void)
5619c84f3f3cSopenharmony_ci{
5620c84f3f3cSopenharmony_ci	if (x_tab != NULL)
5621c84f3f3cSopenharmony_ci		afreeall(AEDIT);
5622c84f3f3cSopenharmony_ci}
5623c84f3f3cSopenharmony_ci#endif
5624c84f3f3cSopenharmony_ci
5625c84f3f3cSopenharmony_civoid
5626c84f3f3cSopenharmony_cix_initterm(const char *termtype)
5627c84f3f3cSopenharmony_ci{
5628c84f3f3cSopenharmony_ci	/* default must be 0 (bss) */
5629c84f3f3cSopenharmony_ci	x_term_mode = 0;
5630c84f3f3cSopenharmony_ci	/* catch any of the TERM types tmux uses, don’t ask m̲e̲ about it… */
5631c84f3f3cSopenharmony_ci	switch (*termtype) {
5632c84f3f3cSopenharmony_ci	case 's':
5633c84f3f3cSopenharmony_ci		if (!strncmp(termtype, "screen", 6) &&
5634c84f3f3cSopenharmony_ci		    (termtype[6] == '\0' || termtype[6] == '-'))
5635c84f3f3cSopenharmony_ci			x_term_mode = 1;
5636c84f3f3cSopenharmony_ci		break;
5637c84f3f3cSopenharmony_ci	case 't':
5638c84f3f3cSopenharmony_ci		if (!strncmp(termtype, "tmux", 4) &&
5639c84f3f3cSopenharmony_ci		    (termtype[4] == '\0' || termtype[4] == '-'))
5640c84f3f3cSopenharmony_ci			x_term_mode = 1;
5641c84f3f3cSopenharmony_ci		break;
5642c84f3f3cSopenharmony_ci	}
5643c84f3f3cSopenharmony_ci}
5644c84f3f3cSopenharmony_ci
5645c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
5646c84f3f3cSopenharmony_cistatic char *
5647c84f3f3cSopenharmony_cix_eval_region_helper(const char *cmd, size_t len)
5648c84f3f3cSopenharmony_ci{
5649c84f3f3cSopenharmony_ci	char * volatile cp;
5650c84f3f3cSopenharmony_ci	newenv(E_ERRH);
5651c84f3f3cSopenharmony_ci
5652c84f3f3cSopenharmony_ci	if (!kshsetjmp(e->jbuf)) {
5653c84f3f3cSopenharmony_ci		char *wds = alloc(len + 3, ATEMP);
5654c84f3f3cSopenharmony_ci
5655c84f3f3cSopenharmony_ci		wds[0] = FUNASUB;
5656c84f3f3cSopenharmony_ci		memcpy(wds + 1, cmd, len);
5657c84f3f3cSopenharmony_ci		wds[len + 1] = '\0';
5658c84f3f3cSopenharmony_ci		wds[len + 2] = EOS;
5659c84f3f3cSopenharmony_ci
5660c84f3f3cSopenharmony_ci		cp = evalstr(wds, DOSCALAR);
5661c84f3f3cSopenharmony_ci		afree(wds, ATEMP);
5662c84f3f3cSopenharmony_ci		strdupx(cp, cp, AEDIT);
5663c84f3f3cSopenharmony_ci	} else
5664c84f3f3cSopenharmony_ci		/* command cannot be parsed */
5665c84f3f3cSopenharmony_ci		cp = NULL;
5666c84f3f3cSopenharmony_ci	quitenv(NULL);
5667c84f3f3cSopenharmony_ci	return (cp);
5668c84f3f3cSopenharmony_ci}
5669c84f3f3cSopenharmony_ci
5670c84f3f3cSopenharmony_cistatic int
5671c84f3f3cSopenharmony_cix_operate_region(char *(*helper)(const char *, size_t))
5672c84f3f3cSopenharmony_ci{
5673c84f3f3cSopenharmony_ci	char *rgbeg, *rgend, *cp;
5674c84f3f3cSopenharmony_ci	size_t newlen;
5675c84f3f3cSopenharmony_ci	/* only for LINE overflow checking */
5676c84f3f3cSopenharmony_ci	size_t restlen;
5677c84f3f3cSopenharmony_ci
5678c84f3f3cSopenharmony_ci	if (xmp == NULL) {
5679c84f3f3cSopenharmony_ci		rgbeg = xbuf;
5680c84f3f3cSopenharmony_ci		rgend = xep;
5681c84f3f3cSopenharmony_ci	} else if (xmp < xcp) {
5682c84f3f3cSopenharmony_ci		rgbeg = xmp;
5683c84f3f3cSopenharmony_ci		rgend = xcp;
5684c84f3f3cSopenharmony_ci	} else {
5685c84f3f3cSopenharmony_ci		rgbeg = xcp;
5686c84f3f3cSopenharmony_ci		rgend = xmp;
5687c84f3f3cSopenharmony_ci	}
5688c84f3f3cSopenharmony_ci
5689c84f3f3cSopenharmony_ci	x_e_putc2('\r');
5690c84f3f3cSopenharmony_ci	x_clrtoeol(' ', false);
5691c84f3f3cSopenharmony_ci	x_flush();
5692c84f3f3cSopenharmony_ci	x_mode(false);
5693c84f3f3cSopenharmony_ci	cp = helper(rgbeg, rgend - rgbeg);
5694c84f3f3cSopenharmony_ci	x_mode(true);
5695c84f3f3cSopenharmony_ci
5696c84f3f3cSopenharmony_ci	if (cp == NULL) {
5697c84f3f3cSopenharmony_ci		/* error return from helper */
5698c84f3f3cSopenharmony_ci x_eval_region_err:
5699c84f3f3cSopenharmony_ci		x_e_putc2(KSH_BEL);
5700c84f3f3cSopenharmony_ci		x_redraw('\r');
5701c84f3f3cSopenharmony_ci		return (KSTD);
5702c84f3f3cSopenharmony_ci	}
5703c84f3f3cSopenharmony_ci
5704c84f3f3cSopenharmony_ci	newlen = strlen(cp);
5705c84f3f3cSopenharmony_ci	restlen = xep - rgend;
5706c84f3f3cSopenharmony_ci	/* check for LINE overflow, until this is dynamically allocated */
5707c84f3f3cSopenharmony_ci	if (rgbeg + newlen + restlen >= xend)
5708c84f3f3cSopenharmony_ci		goto x_eval_region_err;
5709c84f3f3cSopenharmony_ci
5710c84f3f3cSopenharmony_ci	xmp = rgbeg;
5711c84f3f3cSopenharmony_ci	xcp = rgbeg + newlen;
5712c84f3f3cSopenharmony_ci	xep = xcp + restlen;
5713c84f3f3cSopenharmony_ci	memmove(xcp, rgend, restlen + /* NUL */ 1);
5714c84f3f3cSopenharmony_ci	memcpy(xmp, cp, newlen);
5715c84f3f3cSopenharmony_ci	afree(cp, AEDIT);
5716c84f3f3cSopenharmony_ci	x_adjust();
5717c84f3f3cSopenharmony_ci	x_modified();
5718c84f3f3cSopenharmony_ci	return (KSTD);
5719c84f3f3cSopenharmony_ci}
5720c84f3f3cSopenharmony_ci
5721c84f3f3cSopenharmony_cistatic int
5722c84f3f3cSopenharmony_cix_eval_region(int c MKSH_A_UNUSED)
5723c84f3f3cSopenharmony_ci{
5724c84f3f3cSopenharmony_ci	return (x_operate_region(x_eval_region_helper));
5725c84f3f3cSopenharmony_ci}
5726c84f3f3cSopenharmony_ci
5727c84f3f3cSopenharmony_cistatic char *
5728c84f3f3cSopenharmony_cix_quote_region_helper(const char *cmd, size_t len)
5729c84f3f3cSopenharmony_ci{
5730c84f3f3cSopenharmony_ci	char *s;
5731c84f3f3cSopenharmony_ci	size_t newlen;
5732c84f3f3cSopenharmony_ci	struct shf shf;
5733c84f3f3cSopenharmony_ci
5734c84f3f3cSopenharmony_ci	strndupx(s, cmd, len, ATEMP);
5735c84f3f3cSopenharmony_ci	newlen = len < 256 ? 256 : 4096;
5736c84f3f3cSopenharmony_ci	shf_sopen(alloc(newlen, AEDIT), newlen, SHF_WR | SHF_DYNAMIC, &shf);
5737c84f3f3cSopenharmony_ci	shf.areap = AEDIT;
5738c84f3f3cSopenharmony_ci	shf.flags |= SHF_ALLOCB;
5739c84f3f3cSopenharmony_ci	print_value_quoted(&shf, s);
5740c84f3f3cSopenharmony_ci	afree(s, ATEMP);
5741c84f3f3cSopenharmony_ci	return (shf_sclose(&shf));
5742c84f3f3cSopenharmony_ci}
5743c84f3f3cSopenharmony_ci
5744c84f3f3cSopenharmony_cistatic int
5745c84f3f3cSopenharmony_cix_quote_region(int c MKSH_A_UNUSED)
5746c84f3f3cSopenharmony_ci{
5747c84f3f3cSopenharmony_ci	return (x_operate_region(x_quote_region_helper));
5748c84f3f3cSopenharmony_ci}
5749c84f3f3cSopenharmony_ci#endif /* !MKSH_SMALL */
5750c84f3f3cSopenharmony_ci#endif /* !MKSH_NO_CMDLINE_EDITING */
5751