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