xref: /minix3/bin/ksh/emacs.c (revision 2718b5688b1550d32bf379153192626eee37752d)
1*2718b568SThomas Cort /*	$NetBSD: emacs.c,v 1.32 2009/04/25 05:11:37 lukem Exp $	*/
2*2718b568SThomas Cort 
3*2718b568SThomas Cort /*
4*2718b568SThomas Cort  *  Emacs-like command line editing and history
5*2718b568SThomas Cort  *
6*2718b568SThomas Cort  *  created by Ron Natalie at BRL
7*2718b568SThomas Cort  *  modified by Doug Kingston, Doug Gwyn, and Lou Salkind
8*2718b568SThomas Cort  *  adapted to PD ksh by Eric Gisin
9*2718b568SThomas Cort  */
10*2718b568SThomas Cort #include <sys/cdefs.h>
11*2718b568SThomas Cort 
12*2718b568SThomas Cort #ifndef lint
13*2718b568SThomas Cort __RCSID("$NetBSD: emacs.c,v 1.32 2009/04/25 05:11:37 lukem Exp $");
14*2718b568SThomas Cort #endif
15*2718b568SThomas Cort 
16*2718b568SThomas Cort 
17*2718b568SThomas Cort #include "config.h"
18*2718b568SThomas Cort #ifdef EMACS
19*2718b568SThomas Cort 
20*2718b568SThomas Cort #include "sh.h"
21*2718b568SThomas Cort #include "ksh_stat.h"
22*2718b568SThomas Cort #include "ksh_dir.h"
23*2718b568SThomas Cort #include <ctype.h>
24*2718b568SThomas Cort #include <locale.h>
25*2718b568SThomas Cort #include "edit.h"
26*2718b568SThomas Cort 
27*2718b568SThomas Cort static	Area	aedit;
28*2718b568SThomas Cort #define	AEDIT	&aedit		/* area for kill ring and macro defns */
29*2718b568SThomas Cort 
30*2718b568SThomas Cort #undef CTRL			/* _BSD brain damage */
31*2718b568SThomas Cort #define	CTRL(x)		((x) == '?' ? 0x7F : (x) & 0x1F)	/* ASCII */
32*2718b568SThomas Cort #define	UNCTRL(x)	((x) == 0x7F ? '?' : (x) | 0x40)	/* ASCII */
33*2718b568SThomas Cort #define	META(x)		((x) & 0x7f)
34*2718b568SThomas Cort #define	ISMETA(x)	(Flag(FEMACSUSEMETA) && ((x) & 0x80))
35*2718b568SThomas Cort 
36*2718b568SThomas Cort 
37*2718b568SThomas Cort /* values returned by keyboard functions */
38*2718b568SThomas Cort #define	KSTD	0
39*2718b568SThomas Cort #define	KEOL	1		/* ^M, ^J */
40*2718b568SThomas Cort #define	KINTR	2		/* ^G, ^C */
41*2718b568SThomas Cort 
42*2718b568SThomas Cort struct	x_ftab  {
43*2718b568SThomas Cort 	int		(*xf_func) ARGS((int c));
44*2718b568SThomas Cort 	const char	*xf_name;
45*2718b568SThomas Cort 	short		xf_flags;
46*2718b568SThomas Cort };
47*2718b568SThomas Cort 
48*2718b568SThomas Cort /* index into struct x_ftab x_ftab[] - small is good */
49*2718b568SThomas Cort typedef unsigned char Findex;
50*2718b568SThomas Cort 
51*2718b568SThomas Cort struct x_defbindings {
52*2718b568SThomas Cort 	Findex		xdb_func;	/* XFUNC_* */
53*2718b568SThomas Cort 	unsigned char	xdb_tab;
54*2718b568SThomas Cort 	unsigned char	xdb_char;
55*2718b568SThomas Cort };
56*2718b568SThomas Cort 
57*2718b568SThomas Cort #define XF_ARG		1	/* command takes number prefix */
58*2718b568SThomas Cort #define	XF_NOBIND	2	/* not allowed to bind to function */
59*2718b568SThomas Cort #define	XF_PREFIX	4	/* function sets prefix */
60*2718b568SThomas Cort 
61*2718b568SThomas Cort /* Separator for completion */
62*2718b568SThomas Cort #define	is_cfs(c)	(c == ' ' || c == '\t' || c == '"' || c == '\'')
63*2718b568SThomas Cort #define	is_mfs(c)	(!(isalnum((unsigned char)c) || c == '_' || c == '$'))  /* Separator for motion */
64*2718b568SThomas Cort 
65*2718b568SThomas Cort #ifdef OS2
66*2718b568SThomas Cort   /* Deal with 8 bit chars & an extra prefix for function key (these two
67*2718b568SThomas Cort    * changes increase memory usage from 9,216 bytes to 24,416 bytes...)
68*2718b568SThomas Cort    */
69*2718b568SThomas Cort # define CHARMASK	0xFF		/* 8-bit ASCII character mask */
70*2718b568SThomas Cort # define X_NTABS	4		/* normal, meta1, meta2, meta3 */
71*2718b568SThomas Cort static int	x_prefix3 = 0xE0;
72*2718b568SThomas Cort #else /* OS2 */
73*2718b568SThomas Cort # define CHARMASK	0xFF		/* 8-bit character mask */
74*2718b568SThomas Cort # define X_NTABS	3		/* normal, meta1, meta2 */
75*2718b568SThomas Cort #endif /* OS2 */
76*2718b568SThomas Cort #define X_TABSZ		(CHARMASK+1)	/* size of keydef tables etc */
77*2718b568SThomas Cort 
78*2718b568SThomas Cort /* Arguments for do_complete()
79*2718b568SThomas Cort  * 0 = enumerate  M-= complete as much as possible and then list
80*2718b568SThomas Cort  * 1 = complete   M-Esc
81*2718b568SThomas Cort  * 2 = list       M-?
82*2718b568SThomas Cort  */
83*2718b568SThomas Cort typedef enum { CT_LIST, 	/* list the possible completions */
84*2718b568SThomas Cort 		 CT_COMPLETE,	/* complete to longest prefix */
85*2718b568SThomas Cort 		 CT_COMPLIST	/* complete and then list (if non-exact) */
86*2718b568SThomas Cort 	} Comp_type;
87*2718b568SThomas Cort 
88*2718b568SThomas Cort /* { from 4.9 edit.h */
89*2718b568SThomas Cort /*
90*2718b568SThomas Cort  * The following are used for my horizontal scrolling stuff
91*2718b568SThomas Cort  */
92*2718b568SThomas Cort static char   *xbuf;		/* beg input buffer */
93*2718b568SThomas Cort static char   *xend;		/* end input buffer */
94*2718b568SThomas Cort static char    *xcp;		/* current position */
95*2718b568SThomas Cort static char    *xep;		/* current end */
96*2718b568SThomas Cort static char    *xbp;		/* start of visible portion of input buffer */
97*2718b568SThomas Cort static char    *xlp;		/* last char visible on screen */
98*2718b568SThomas Cort static int	x_adj_ok;
99*2718b568SThomas Cort /*
100*2718b568SThomas Cort  * we use x_adj_done so that functions can tell
101*2718b568SThomas Cort  * whether x_adjust() has been called while they are active.
102*2718b568SThomas Cort  */
103*2718b568SThomas Cort static int	x_adj_done;
104*2718b568SThomas Cort 
105*2718b568SThomas Cort static int	xx_cols;
106*2718b568SThomas Cort static int	x_col;
107*2718b568SThomas Cort static int	x_displen;
108*2718b568SThomas Cort static int	x_arg;		/* general purpose arg */
109*2718b568SThomas Cort static int	x_arg_defaulted;/* x_arg not explicitly set; defaulted to 1 */
110*2718b568SThomas Cort 
111*2718b568SThomas Cort static int	xlp_valid;
112*2718b568SThomas Cort /* end from 4.9 edit.h } */
113*2718b568SThomas Cort 
114*2718b568SThomas Cort static	int	x_prefix1 = CTRL('['), x_prefix2 = CTRL('X');
115*2718b568SThomas Cort static	char   **x_histp;	/* history position */
116*2718b568SThomas Cort static	int	x_nextcmd;	/* for newline-and-next */
117*2718b568SThomas Cort static	char	*xmp;		/* mark pointer */
118*2718b568SThomas Cort static	Findex   x_last_command;
119*2718b568SThomas Cort static	Findex (*x_tab)[X_TABSZ];	/* key definition */
120*2718b568SThomas Cort static	char    *(*x_atab)[X_TABSZ];	/* macro definitions */
121*2718b568SThomas Cort static	unsigned char	x_bound[(X_TABSZ * X_NTABS + 7) / 8];
122*2718b568SThomas Cort #define	KILLSIZE	20
123*2718b568SThomas Cort static	char    *killstack[KILLSIZE];
124*2718b568SThomas Cort static	int	killsp, killtp;
125*2718b568SThomas Cort static	int	x_curprefix;
126*2718b568SThomas Cort static	char    *macroptr;
127*2718b568SThomas Cort static	int	prompt_trunc;
128*2718b568SThomas Cort static	int	prompt_skip;
129*2718b568SThomas Cort 
130*2718b568SThomas Cort static int      x_ins       ARGS((char *cp));
131*2718b568SThomas Cort static void     x_delete    ARGS((int nc, int push));
132*2718b568SThomas Cort static int	x_bword     ARGS((void));
133*2718b568SThomas Cort static int	x_fword     ARGS((void));
134*2718b568SThomas Cort static void     x_goto      ARGS((char *cp));
135*2718b568SThomas Cort static void     x_bs        ARGS((int c));
136*2718b568SThomas Cort static int      x_size_str  ARGS((char *cp));
137*2718b568SThomas Cort static int      x_size      ARGS((int c));
138*2718b568SThomas Cort static void     x_zots      ARGS((char *str));
139*2718b568SThomas Cort static void     x_zotc      ARGS((int c));
140*2718b568SThomas Cort static void     x_load_hist ARGS((char **hp));
141*2718b568SThomas Cort static int      x_search    ARGS((char *pat, int sameline, int offset));
142*2718b568SThomas Cort static int      x_match     ARGS((char *str, char *pat));
143*2718b568SThomas Cort static void	x_redraw    ARGS((int limit));
144*2718b568SThomas Cort static void     x_push      ARGS((int nchars));
145*2718b568SThomas Cort static char *   x_mapin     ARGS((const char *cp, Area *area));
146*2718b568SThomas Cort static char *   x_mapout    ARGS((int c));
147*2718b568SThomas Cort static void     x_print     ARGS((int prefix, int key));
148*2718b568SThomas Cort static void	x_adjust    ARGS((void));
149*2718b568SThomas Cort static void	x_e_ungetc  ARGS((int c));
150*2718b568SThomas Cort static int	x_e_getc    ARGS((void));
151*2718b568SThomas Cort static void	x_e_putc    ARGS((int c));
152*2718b568SThomas Cort static void	x_e_puts    ARGS((const char *s));
153*2718b568SThomas Cort static int	x_comment   ARGS((int c));
154*2718b568SThomas Cort static int	x_fold_case ARGS((int c));
155*2718b568SThomas Cort static char	*x_lastcp ARGS((void));
156*2718b568SThomas Cort static void	do_complete ARGS((int flags, Comp_type type));
157*2718b568SThomas Cort static int	x_emacs_putbuf	ARGS((const char *s, size_t len));
158*2718b568SThomas Cort 
159*2718b568SThomas Cort 
160*2718b568SThomas Cort /* The lines between START-FUNC-TAB .. END-FUNC-TAB are run through a
161*2718b568SThomas Cort  * script (emacs-gen.sh) that generates emacs.out which contains:
162*2718b568SThomas Cort  *	- function declarations for x_* functions
163*2718b568SThomas Cort  *	- defines of the form XFUNC_<name> where <name> is function
164*2718b568SThomas Cort  *	  name, sans leading x_.
165*2718b568SThomas Cort  * Note that the script treats #ifdef and { 0, 0, 0} specially - use with
166*2718b568SThomas Cort  * caution.
167*2718b568SThomas Cort  */
168*2718b568SThomas Cort #include "emacs.out"
169*2718b568SThomas Cort static const struct x_ftab x_ftab[] = {
170*2718b568SThomas Cort /* @START-FUNC-TAB@ */
171*2718b568SThomas Cort 	{ x_abort,		"abort",			0 },
172*2718b568SThomas Cort 	{ x_beg_hist,		"beginning-of-history",		0 },
173*2718b568SThomas Cort 	{ x_comp_comm,		"complete-command",		0 },
174*2718b568SThomas Cort 	{ x_comp_file,		"complete-file",		0 },
175*2718b568SThomas Cort 	{ x_complete,		"complete",			0 },
176*2718b568SThomas Cort 	{ x_del_back,		"delete-char-backward",		XF_ARG },
177*2718b568SThomas Cort 	{ x_del_bword,		"delete-word-backward",		XF_ARG },
178*2718b568SThomas Cort 	{ x_del_char,		"delete-char-forward",		XF_ARG },
179*2718b568SThomas Cort 	{ x_del_fword,		"delete-word-forward",		XF_ARG },
180*2718b568SThomas Cort 	{ x_del_line,		"kill-line",			0 },
181*2718b568SThomas Cort 	{ x_draw_line,		"redraw",			0 },
182*2718b568SThomas Cort 	{ x_end_hist,		"end-of-history",		0 },
183*2718b568SThomas Cort 	{ x_end_of_text,	"eot",				0 },
184*2718b568SThomas Cort 	{ x_enumerate,		"list",				0 },
185*2718b568SThomas Cort 	{ x_eot_del,		"eot-or-delete",		XF_ARG },
186*2718b568SThomas Cort 	{ x_error,		"error",			0 },
187*2718b568SThomas Cort 	{ x_goto_hist,		"goto-history",			XF_ARG },
188*2718b568SThomas Cort 	{ x_ins_string,		"macro-string",			XF_NOBIND },
189*2718b568SThomas Cort 	{ x_insert,		"auto-insert",			XF_ARG },
190*2718b568SThomas Cort 	{ x_kill,		"kill-to-eol",			XF_ARG },
191*2718b568SThomas Cort 	{ x_kill_region,	"kill-region",			0 },
192*2718b568SThomas Cort 	{ x_list_comm,		"list-command",			0 },
193*2718b568SThomas Cort 	{ x_list_file,		"list-file",			0 },
194*2718b568SThomas Cort 	{ x_literal,		"quote",			0 },
195*2718b568SThomas Cort 	{ x_meta1,		"prefix-1",			XF_PREFIX },
196*2718b568SThomas Cort 	{ x_meta2,		"prefix-2",			XF_PREFIX },
197*2718b568SThomas Cort 	{ x_meta_yank,		"yank-pop",			0 },
198*2718b568SThomas Cort 	{ x_mv_back,		"backward-char",		XF_ARG },
199*2718b568SThomas Cort 	{ x_mv_begin,		"beginning-of-line",		0 },
200*2718b568SThomas Cort 	{ x_mv_bword,		"backward-word",		XF_ARG },
201*2718b568SThomas Cort 	{ x_mv_end,		"end-of-line",			0 },
202*2718b568SThomas Cort 	{ x_mv_forw,		"forward-char",			XF_ARG },
203*2718b568SThomas Cort 	{ x_mv_fword,		"forward-word",			XF_ARG },
204*2718b568SThomas Cort 	{ x_newline,		"newline",			0 },
205*2718b568SThomas Cort 	{ x_next_com,		"down-history",			XF_ARG },
206*2718b568SThomas Cort 	{ x_nl_next_com,	"newline-and-next",		0 },
207*2718b568SThomas Cort 	{ x_noop,		"no-op",			0 },
208*2718b568SThomas Cort 	{ x_prev_com,		"up-history",			XF_ARG },
209*2718b568SThomas Cort 	{ x_prev_histword,	"prev-hist-word",		XF_ARG },
210*2718b568SThomas Cort 	{ x_search_char_forw,	"search-character-forward",	XF_ARG },
211*2718b568SThomas Cort 	{ x_search_char_back,	"search-character-backward",	XF_ARG },
212*2718b568SThomas Cort 	{ x_search_hist,	"search-history",		0 },
213*2718b568SThomas Cort 	{ x_set_mark,		"set-mark-command",		0 },
214*2718b568SThomas Cort 	{ x_stuff,		"stuff",			0 },
215*2718b568SThomas Cort 	{ x_stuffreset,		"stuff-reset",			0 },
216*2718b568SThomas Cort 	{ x_transpose,		"transpose-chars",		0 },
217*2718b568SThomas Cort 	{ x_version,		"version",			0 },
218*2718b568SThomas Cort 	{ x_xchg_point_mark,	"exchange-point-and-mark",	0 },
219*2718b568SThomas Cort 	{ x_yank,		"yank",				0 },
220*2718b568SThomas Cort         { x_comp_list,		"complete-list",		0 },
221*2718b568SThomas Cort         { x_expand,		"expand-file",			0 },
222*2718b568SThomas Cort         { x_fold_capitalize,	"capitalize-word",		XF_ARG },
223*2718b568SThomas Cort         { x_fold_lower,		"downcase-word",		XF_ARG },
224*2718b568SThomas Cort         { x_fold_upper,		"upcase-word",			XF_ARG },
225*2718b568SThomas Cort         { x_set_arg,		"set-arg",			XF_NOBIND },
226*2718b568SThomas Cort         { x_comment,		"comment",			0 },
227*2718b568SThomas Cort #ifdef SILLY
228*2718b568SThomas Cort 	{ x_game_of_life,	"play-game-of-life",		0 },
229*2718b568SThomas Cort #else
230*2718b568SThomas Cort 	{ 0, 0, 0 },
231*2718b568SThomas Cort #endif
232*2718b568SThomas Cort #ifdef DEBUG
233*2718b568SThomas Cort         { x_debug_info,		"debug-info",			0 },
234*2718b568SThomas Cort #else
235*2718b568SThomas Cort 	{ 0, 0, 0 },
236*2718b568SThomas Cort #endif
237*2718b568SThomas Cort #ifdef OS2
238*2718b568SThomas Cort 	{ x_meta3,		"prefix-3",			XF_PREFIX },
239*2718b568SThomas Cort #else
240*2718b568SThomas Cort 	{ 0, 0, 0 },
241*2718b568SThomas Cort #endif
242*2718b568SThomas Cort /* @END-FUNC-TAB@ */
243*2718b568SThomas Cort     };
244*2718b568SThomas Cort 
245*2718b568SThomas Cort static	struct x_defbindings const x_defbindings[] = {
246*2718b568SThomas Cort 	{ XFUNC_del_back,		0, CTRL('?') },
247*2718b568SThomas Cort 	{ XFUNC_del_bword,		1, CTRL('?') },
248*2718b568SThomas Cort 	{ XFUNC_eot_del,		0, CTRL('D') },
249*2718b568SThomas Cort 	{ XFUNC_del_back,		0, CTRL('H') },
250*2718b568SThomas Cort 	{ XFUNC_del_bword,		1, CTRL('H') },
251*2718b568SThomas Cort 	{ XFUNC_del_bword,		1,      'h'  },
252*2718b568SThomas Cort 	{ XFUNC_mv_bword,		1,      'b'  },
253*2718b568SThomas Cort 	{ XFUNC_mv_fword,		1,      'f'  },
254*2718b568SThomas Cort 	{ XFUNC_del_fword,		1,      'd'  },
255*2718b568SThomas Cort 	{ XFUNC_mv_back,		0, CTRL('B') },
256*2718b568SThomas Cort 	{ XFUNC_mv_forw,		0, CTRL('F') },
257*2718b568SThomas Cort 	{ XFUNC_search_char_forw,	0, CTRL(']') },
258*2718b568SThomas Cort 	{ XFUNC_search_char_back,	1, CTRL(']') },
259*2718b568SThomas Cort 	{ XFUNC_newline,		0, CTRL('M') },
260*2718b568SThomas Cort 	{ XFUNC_newline,		0, CTRL('J') },
261*2718b568SThomas Cort 	{ XFUNC_end_of_text,		0, CTRL('_') },
262*2718b568SThomas Cort 	{ XFUNC_abort,			0, CTRL('G') },
263*2718b568SThomas Cort 	{ XFUNC_prev_com,		0, CTRL('P') },
264*2718b568SThomas Cort 	{ XFUNC_next_com,		0, CTRL('N') },
265*2718b568SThomas Cort 	{ XFUNC_nl_next_com,		0, CTRL('O') },
266*2718b568SThomas Cort 	{ XFUNC_search_hist,		0, CTRL('R') },
267*2718b568SThomas Cort 	{ XFUNC_beg_hist,		1,      '<'  },
268*2718b568SThomas Cort 	{ XFUNC_end_hist,		1,      '>'  },
269*2718b568SThomas Cort 	{ XFUNC_goto_hist,		1,      'g'  },
270*2718b568SThomas Cort 	{ XFUNC_mv_end,			0, CTRL('E') },
271*2718b568SThomas Cort 	{ XFUNC_mv_begin,		0, CTRL('A') },
272*2718b568SThomas Cort 	{ XFUNC_draw_line,		0, CTRL('L') },
273*2718b568SThomas Cort 	{ XFUNC_meta1,			0, CTRL('[') },
274*2718b568SThomas Cort 	{ XFUNC_meta2,			0, CTRL('X') },
275*2718b568SThomas Cort 	{ XFUNC_kill,			0, CTRL('K') },
276*2718b568SThomas Cort 	{ XFUNC_yank,			0, CTRL('Y') },
277*2718b568SThomas Cort 	{ XFUNC_meta_yank,		1,      'y'  },
278*2718b568SThomas Cort 	{ XFUNC_literal,		0, CTRL('^') },
279*2718b568SThomas Cort         { XFUNC_comment,		1,	'#'  },
280*2718b568SThomas Cort #if defined(BRL) && defined(TIOCSTI)
281*2718b568SThomas Cort 	{ XFUNC_stuff,			0, CTRL('T') },
282*2718b568SThomas Cort #else
283*2718b568SThomas Cort 	{ XFUNC_transpose,		0, CTRL('T') },
284*2718b568SThomas Cort #endif
285*2718b568SThomas Cort 	{ XFUNC_complete,		1, CTRL('[') },
286*2718b568SThomas Cort 	{ XFUNC_comp_list,		0, CTRL('I') },
287*2718b568SThomas Cort         { XFUNC_comp_list,		1,	'='  },
288*2718b568SThomas Cort 	{ XFUNC_enumerate,		1,	'?'  },
289*2718b568SThomas Cort         { XFUNC_expand,			1,	'*'  },
290*2718b568SThomas Cort 	{ XFUNC_comp_file,		1, CTRL('X') },
291*2718b568SThomas Cort 	{ XFUNC_comp_comm,		2, CTRL('[') },
292*2718b568SThomas Cort 	{ XFUNC_list_comm,		2,	'?'  },
293*2718b568SThomas Cort 	{ XFUNC_list_file,		2, CTRL('Y') },
294*2718b568SThomas Cort 	{ XFUNC_set_mark,		1,	' '  },
295*2718b568SThomas Cort 	{ XFUNC_kill_region,		0, CTRL('W') },
296*2718b568SThomas Cort 	{ XFUNC_xchg_point_mark,	2, CTRL('X') },
297*2718b568SThomas Cort 	{ XFUNC_version,		0, CTRL('V') },
298*2718b568SThomas Cort #ifdef DEBUG
299*2718b568SThomas Cort         { XFUNC_debug_info,		1, CTRL('H') },
300*2718b568SThomas Cort #endif
301*2718b568SThomas Cort 	{ XFUNC_prev_histword,		1,	'.'  },
302*2718b568SThomas Cort 	{ XFUNC_prev_histword,		1,	'_'  },
303*2718b568SThomas Cort         { XFUNC_set_arg,		1,	'0'  },
304*2718b568SThomas Cort         { XFUNC_set_arg,		1,	'1'  },
305*2718b568SThomas Cort         { XFUNC_set_arg,		1,	'2'  },
306*2718b568SThomas Cort         { XFUNC_set_arg,		1,	'3'  },
307*2718b568SThomas Cort         { XFUNC_set_arg,		1,	'4'  },
308*2718b568SThomas Cort         { XFUNC_set_arg,		1,	'5'  },
309*2718b568SThomas Cort         { XFUNC_set_arg,		1,	'6'  },
310*2718b568SThomas Cort         { XFUNC_set_arg,		1,	'7'  },
311*2718b568SThomas Cort         { XFUNC_set_arg,		1,	'8'  },
312*2718b568SThomas Cort         { XFUNC_set_arg,		1,	'9'  },
313*2718b568SThomas Cort         { XFUNC_fold_upper,		1,	'U'  },
314*2718b568SThomas Cort         { XFUNC_fold_upper,		1,	'u'  },
315*2718b568SThomas Cort         { XFUNC_fold_lower,		1,	'L'  },
316*2718b568SThomas Cort         { XFUNC_fold_lower,		1,	'l'  },
317*2718b568SThomas Cort         { XFUNC_fold_capitalize,	1,	'C'  },
318*2718b568SThomas Cort         { XFUNC_fold_capitalize,	1,	'c'  },
319*2718b568SThomas Cort #ifdef OS2
320*2718b568SThomas Cort 	{ XFUNC_meta3,			0,	0xE0 },
321*2718b568SThomas Cort 	{ XFUNC_mv_back,		3,	'K'  },
322*2718b568SThomas Cort 	{ XFUNC_mv_forw,		3,	'M'  },
323*2718b568SThomas Cort 	{ XFUNC_next_com,		3,	'P'  },
324*2718b568SThomas Cort 	{ XFUNC_prev_com,		3,	'H'  },
325*2718b568SThomas Cort #endif /* OS2 */
326*2718b568SThomas Cort 	/* These for ansi arrow keys: arguablely shouldn't be here by
327*2718b568SThomas Cort 	 * default, but its simpler/faster/smaller than using termcap
328*2718b568SThomas Cort 	 * entries.
329*2718b568SThomas Cort 	 */
330*2718b568SThomas Cort         { XFUNC_meta2,			1,	'['  },
331*2718b568SThomas Cort         { XFUNC_meta2,			1,	'O'  },
332*2718b568SThomas Cort 	{ XFUNC_prev_com,		2,	'A'  },
333*2718b568SThomas Cort 	{ XFUNC_next_com,		2,	'B'  },
334*2718b568SThomas Cort 	{ XFUNC_mv_forw,		2,	'C'  },
335*2718b568SThomas Cort 	{ XFUNC_mv_back,		2,	'D'  },
336*2718b568SThomas Cort };
337*2718b568SThomas Cort 
338*2718b568SThomas Cort int
x_emacs(buf,len)339*2718b568SThomas Cort x_emacs(buf, len)
340*2718b568SThomas Cort 	char *buf;
341*2718b568SThomas Cort 	size_t len;
342*2718b568SThomas Cort {
343*2718b568SThomas Cort 	int	c;
344*2718b568SThomas Cort 	const char *p;
345*2718b568SThomas Cort 	int	i;
346*2718b568SThomas Cort 	Findex	f;
347*2718b568SThomas Cort 
348*2718b568SThomas Cort 	xbp = xbuf = buf; xend = buf + len;
349*2718b568SThomas Cort 	xlp = xcp = xep = buf;
350*2718b568SThomas Cort 	*xcp = 0;
351*2718b568SThomas Cort 	xlp_valid = TRUE;
352*2718b568SThomas Cort 	xmp = NULL;
353*2718b568SThomas Cort 	x_curprefix = 0;
354*2718b568SThomas Cort 	macroptr = (char *) 0;
355*2718b568SThomas Cort 	x_histp = histptr + 1;
356*2718b568SThomas Cort 	x_last_command = XFUNC_error;
357*2718b568SThomas Cort 
358*2718b568SThomas Cort 	xx_cols = x_cols;
359*2718b568SThomas Cort 	x_col = promptlen(prompt, &p);
360*2718b568SThomas Cort 	prompt_skip = p - prompt;
361*2718b568SThomas Cort 	prompt_trunc = x_col - (x_cols - 3 - MIN_EDIT_SPACE);
362*2718b568SThomas Cort 	if (prompt_trunc > 0)
363*2718b568SThomas Cort 		x_col -= prompt_trunc;
364*2718b568SThomas Cort 	else
365*2718b568SThomas Cort 		prompt_trunc = 0;
366*2718b568SThomas Cort 	x_adj_ok = 1;
367*2718b568SThomas Cort 	x_displen = xx_cols - 2 - x_col;
368*2718b568SThomas Cort 	x_adj_done = 0;
369*2718b568SThomas Cort 
370*2718b568SThomas Cort 	pprompt(prompt, prompt_trunc);
371*2718b568SThomas Cort 
372*2718b568SThomas Cort 	if (x_nextcmd >= 0) {
373*2718b568SThomas Cort 		int off = source->line - x_nextcmd;
374*2718b568SThomas Cort 		if (histptr - histlist >= off)
375*2718b568SThomas Cort 			x_load_hist(histptr - off);
376*2718b568SThomas Cort 		x_nextcmd = -1;
377*2718b568SThomas Cort 	}
378*2718b568SThomas Cort 
379*2718b568SThomas Cort 	while (1) {
380*2718b568SThomas Cort 		x_flush();
381*2718b568SThomas Cort 		if ((c = x_e_getc()) < 0)
382*2718b568SThomas Cort 			return 0;
383*2718b568SThomas Cort 
384*2718b568SThomas Cort 		if (ISMETA(c)) {
385*2718b568SThomas Cort 			c = META(c);
386*2718b568SThomas Cort 			x_curprefix = 1;
387*2718b568SThomas Cort 		}
388*2718b568SThomas Cort 
389*2718b568SThomas Cort 		f = x_curprefix == -1 ? XFUNC_insert
390*2718b568SThomas Cort 			: x_tab[x_curprefix][c&CHARMASK];
391*2718b568SThomas Cort 
392*2718b568SThomas Cort 		if (!(x_ftab[f].xf_flags & XF_PREFIX)
393*2718b568SThomas Cort 		    && x_last_command != XFUNC_set_arg)
394*2718b568SThomas Cort 		{
395*2718b568SThomas Cort 			x_arg = 1;
396*2718b568SThomas Cort 			x_arg_defaulted = 1;
397*2718b568SThomas Cort 		}
398*2718b568SThomas Cort 		i = c | (x_curprefix << 8);
399*2718b568SThomas Cort 		x_curprefix = 0;
400*2718b568SThomas Cort 		switch (i = (*x_ftab[f].xf_func)(i))  {
401*2718b568SThomas Cort 		  case KSTD:
402*2718b568SThomas Cort 			if (!(x_ftab[f].xf_flags & XF_PREFIX))
403*2718b568SThomas Cort 				x_last_command = f;
404*2718b568SThomas Cort 			break;
405*2718b568SThomas Cort 		  case KEOL:
406*2718b568SThomas Cort 			i = xep - xbuf;
407*2718b568SThomas Cort 			return i;
408*2718b568SThomas Cort 		  case KINTR:	/* special case for interrupt */
409*2718b568SThomas Cort 			trapsig(SIGINT);
410*2718b568SThomas Cort 			x_mode(FALSE);
411*2718b568SThomas Cort 			unwind(LSHELL);
412*2718b568SThomas Cort 		}
413*2718b568SThomas Cort 	}
414*2718b568SThomas Cort }
415*2718b568SThomas Cort 
416*2718b568SThomas Cort static int
x_insert(c)417*2718b568SThomas Cort x_insert(c)
418*2718b568SThomas Cort 	int c;
419*2718b568SThomas Cort {
420*2718b568SThomas Cort 	char	str[2];
421*2718b568SThomas Cort 
422*2718b568SThomas Cort 	/*
423*2718b568SThomas Cort 	 *  Should allow tab and control chars.
424*2718b568SThomas Cort 	 */
425*2718b568SThomas Cort 	if (c == 0)  {
426*2718b568SThomas Cort 		x_e_putc(BEL);
427*2718b568SThomas Cort 		return KSTD;
428*2718b568SThomas Cort 	}
429*2718b568SThomas Cort 	str[0] = c;
430*2718b568SThomas Cort 	str[1] = '\0';
431*2718b568SThomas Cort 	while (x_arg--)
432*2718b568SThomas Cort 		x_ins(str);
433*2718b568SThomas Cort 	return KSTD;
434*2718b568SThomas Cort }
435*2718b568SThomas Cort 
436*2718b568SThomas Cort static int
x_ins_string(c)437*2718b568SThomas Cort x_ins_string(c)
438*2718b568SThomas Cort 	int c;
439*2718b568SThomas Cort {
440*2718b568SThomas Cort 	if (macroptr)   {
441*2718b568SThomas Cort 		x_e_putc(BEL);
442*2718b568SThomas Cort 		return KSTD;
443*2718b568SThomas Cort 	}
444*2718b568SThomas Cort 	macroptr = x_atab[c>>8][c & CHARMASK];
445*2718b568SThomas Cort 	if (macroptr && !*macroptr) {
446*2718b568SThomas Cort 		/* XXX bell? */
447*2718b568SThomas Cort 		macroptr = (char *) 0;
448*2718b568SThomas Cort 	}
449*2718b568SThomas Cort 	return KSTD;
450*2718b568SThomas Cort }
451*2718b568SThomas Cort 
452*2718b568SThomas Cort static int x_do_ins(const char *cp, int len);
453*2718b568SThomas Cort 
454*2718b568SThomas Cort static int
x_do_ins(cp,len)455*2718b568SThomas Cort x_do_ins(cp, len)
456*2718b568SThomas Cort 	const char *cp;
457*2718b568SThomas Cort 	int len;
458*2718b568SThomas Cort {
459*2718b568SThomas Cort 	if (xep+len >= xend) {
460*2718b568SThomas Cort 		x_e_putc(BEL);
461*2718b568SThomas Cort 		return -1;
462*2718b568SThomas Cort 	}
463*2718b568SThomas Cort 
464*2718b568SThomas Cort 	memmove(xcp+len, xcp, xep - xcp + 1);
465*2718b568SThomas Cort 	memmove(xcp, cp, len);
466*2718b568SThomas Cort 	xcp += len;
467*2718b568SThomas Cort 	xep += len;
468*2718b568SThomas Cort 	return 0;
469*2718b568SThomas Cort }
470*2718b568SThomas Cort 
471*2718b568SThomas Cort static int
x_ins(s)472*2718b568SThomas Cort x_ins(s)
473*2718b568SThomas Cort 	char	*s;
474*2718b568SThomas Cort {
475*2718b568SThomas Cort 	char *cp = xcp;
476*2718b568SThomas Cort 	register int	adj = x_adj_done;
477*2718b568SThomas Cort 
478*2718b568SThomas Cort 	if (x_do_ins(s, strlen(s)) < 0)
479*2718b568SThomas Cort 		return -1;
480*2718b568SThomas Cort 	/*
481*2718b568SThomas Cort 	 * x_zots() may result in a call to x_adjust()
482*2718b568SThomas Cort 	 * we want xcp to reflect the new position.
483*2718b568SThomas Cort 	 */
484*2718b568SThomas Cort 	xlp_valid = FALSE;
485*2718b568SThomas Cort 	x_lastcp();
486*2718b568SThomas Cort 	x_adj_ok = (xcp >= xlp);
487*2718b568SThomas Cort 	x_zots(cp);
488*2718b568SThomas Cort 	if (adj == x_adj_done)	/* has x_adjust() been called? */
489*2718b568SThomas Cort 	{
490*2718b568SThomas Cort 	  /* no */
491*2718b568SThomas Cort 	  for (cp = xlp; cp > xcp; )
492*2718b568SThomas Cort 	    x_bs(*--cp);
493*2718b568SThomas Cort 	}
494*2718b568SThomas Cort 
495*2718b568SThomas Cort 	x_adj_ok = 1;
496*2718b568SThomas Cort 	return 0;
497*2718b568SThomas Cort }
498*2718b568SThomas Cort 
499*2718b568SThomas Cort /*
500*2718b568SThomas Cort  * this is used for x_escape() in do_complete()
501*2718b568SThomas Cort  */
502*2718b568SThomas Cort static int
x_emacs_putbuf(s,len)503*2718b568SThomas Cort x_emacs_putbuf(s, len)
504*2718b568SThomas Cort 	const char *s;
505*2718b568SThomas Cort 	size_t len;
506*2718b568SThomas Cort {
507*2718b568SThomas Cort 	int rval;
508*2718b568SThomas Cort 
509*2718b568SThomas Cort 	if ((rval = x_do_ins(s, len)) != 0)
510*2718b568SThomas Cort 		return (rval);
511*2718b568SThomas Cort 	return (rval);
512*2718b568SThomas Cort }
513*2718b568SThomas Cort 
514*2718b568SThomas Cort static int
x_del_back(c)515*2718b568SThomas Cort x_del_back(c)
516*2718b568SThomas Cort 	int c;
517*2718b568SThomas Cort {
518*2718b568SThomas Cort 	int col = xcp - xbuf;
519*2718b568SThomas Cort 
520*2718b568SThomas Cort 	if (col == 0)  {
521*2718b568SThomas Cort 		x_e_putc(BEL);
522*2718b568SThomas Cort 		return KSTD;
523*2718b568SThomas Cort 	}
524*2718b568SThomas Cort 	if (x_arg > col)
525*2718b568SThomas Cort 		x_arg = col;
526*2718b568SThomas Cort 	x_goto(xcp - x_arg);
527*2718b568SThomas Cort 	x_delete(x_arg, FALSE);
528*2718b568SThomas Cort 	return KSTD;
529*2718b568SThomas Cort }
530*2718b568SThomas Cort 
531*2718b568SThomas Cort static int
x_del_char(c)532*2718b568SThomas Cort x_del_char(c)
533*2718b568SThomas Cort 	int c;
534*2718b568SThomas Cort {
535*2718b568SThomas Cort 	int nleft = xep - xcp;
536*2718b568SThomas Cort 
537*2718b568SThomas Cort 	if (!nleft) {
538*2718b568SThomas Cort 		x_e_putc(BEL);
539*2718b568SThomas Cort 		return KSTD;
540*2718b568SThomas Cort 	}
541*2718b568SThomas Cort 	if (x_arg > nleft)
542*2718b568SThomas Cort 		x_arg = nleft;
543*2718b568SThomas Cort 	x_delete(x_arg, FALSE);
544*2718b568SThomas Cort 	return KSTD;
545*2718b568SThomas Cort }
546*2718b568SThomas Cort 
547*2718b568SThomas Cort /* Delete nc chars to the right of the cursor (including cursor position) */
548*2718b568SThomas Cort static void
x_delete(nc,push)549*2718b568SThomas Cort x_delete(nc, push)
550*2718b568SThomas Cort 	int nc;
551*2718b568SThomas Cort 	int push;
552*2718b568SThomas Cort {
553*2718b568SThomas Cort 	int	i,j;
554*2718b568SThomas Cort 	char	*cp;
555*2718b568SThomas Cort 
556*2718b568SThomas Cort 	if (nc == 0)
557*2718b568SThomas Cort 		return;
558*2718b568SThomas Cort 	if (xmp != NULL && xmp > xcp) {
559*2718b568SThomas Cort 		if (xcp + nc > xmp)
560*2718b568SThomas Cort 			xmp = xcp;
561*2718b568SThomas Cort 		else
562*2718b568SThomas Cort 			xmp -= nc;
563*2718b568SThomas Cort 	}
564*2718b568SThomas Cort 
565*2718b568SThomas Cort 	/*
566*2718b568SThomas Cort 	 * This lets us yank a word we have deleted.
567*2718b568SThomas Cort 	 */
568*2718b568SThomas Cort 	if (push)
569*2718b568SThomas Cort 		x_push(nc);
570*2718b568SThomas Cort 
571*2718b568SThomas Cort 	xep -= nc;
572*2718b568SThomas Cort 	cp = xcp;
573*2718b568SThomas Cort 	j = 0;
574*2718b568SThomas Cort 	i = nc;
575*2718b568SThomas Cort 	while (i--)  {
576*2718b568SThomas Cort 		j += x_size(*cp++);
577*2718b568SThomas Cort 	}
578*2718b568SThomas Cort 	memmove(xcp, xcp+nc, xep - xcp + 1);	/* Copies the null */
579*2718b568SThomas Cort 	x_adj_ok = 0;			/* don't redraw */
580*2718b568SThomas Cort 	x_zots(xcp);
581*2718b568SThomas Cort 	/*
582*2718b568SThomas Cort 	 * if we are already filling the line,
583*2718b568SThomas Cort 	 * there is no need to ' ','\b'.
584*2718b568SThomas Cort 	 * But if we must, make sure we do the minimum.
585*2718b568SThomas Cort 	 */
586*2718b568SThomas Cort 	if ((i = x_displen) > 0)
587*2718b568SThomas Cort 	{
588*2718b568SThomas Cort 	  j = (j < i) ? j : i;
589*2718b568SThomas Cort 	  i = j;
590*2718b568SThomas Cort 	  while (i--)
591*2718b568SThomas Cort 	    x_e_putc(' ');
592*2718b568SThomas Cort 	  i = j;
593*2718b568SThomas Cort 	  while (i--)
594*2718b568SThomas Cort 	    x_e_putc('\b');
595*2718b568SThomas Cort 	}
596*2718b568SThomas Cort 	/*x_goto(xcp);*/
597*2718b568SThomas Cort 	x_adj_ok = 1;
598*2718b568SThomas Cort 	xlp_valid = FALSE;
599*2718b568SThomas Cort 	for (cp = x_lastcp(); cp > xcp; )
600*2718b568SThomas Cort 		x_bs(*--cp);
601*2718b568SThomas Cort 
602*2718b568SThomas Cort 	return;
603*2718b568SThomas Cort }
604*2718b568SThomas Cort 
605*2718b568SThomas Cort static int
x_del_bword(c)606*2718b568SThomas Cort x_del_bword(c)
607*2718b568SThomas Cort 	int c;
608*2718b568SThomas Cort {
609*2718b568SThomas Cort 	x_delete(x_bword(), TRUE);
610*2718b568SThomas Cort 	return KSTD;
611*2718b568SThomas Cort }
612*2718b568SThomas Cort 
613*2718b568SThomas Cort static int
x_mv_bword(c)614*2718b568SThomas Cort x_mv_bword(c)
615*2718b568SThomas Cort 	int c;
616*2718b568SThomas Cort {
617*2718b568SThomas Cort 	(void)x_bword();
618*2718b568SThomas Cort 	return KSTD;
619*2718b568SThomas Cort }
620*2718b568SThomas Cort 
621*2718b568SThomas Cort static int
x_mv_fword(c)622*2718b568SThomas Cort x_mv_fword(c)
623*2718b568SThomas Cort 	int c;
624*2718b568SThomas Cort {
625*2718b568SThomas Cort 	x_goto(xcp + x_fword());
626*2718b568SThomas Cort 	return KSTD;
627*2718b568SThomas Cort }
628*2718b568SThomas Cort 
629*2718b568SThomas Cort static int
x_del_fword(c)630*2718b568SThomas Cort x_del_fword(c)
631*2718b568SThomas Cort 	int c;
632*2718b568SThomas Cort {
633*2718b568SThomas Cort 	x_delete(x_fword(), TRUE);
634*2718b568SThomas Cort 	return KSTD;
635*2718b568SThomas Cort }
636*2718b568SThomas Cort 
637*2718b568SThomas Cort static int
x_bword()638*2718b568SThomas Cort x_bword()
639*2718b568SThomas Cort {
640*2718b568SThomas Cort 	int	nc = 0;
641*2718b568SThomas Cort 	register char *cp = xcp;
642*2718b568SThomas Cort 
643*2718b568SThomas Cort 	if (cp == xbuf)  {
644*2718b568SThomas Cort 		x_e_putc(BEL);
645*2718b568SThomas Cort 		return 0;
646*2718b568SThomas Cort 	}
647*2718b568SThomas Cort 	while (x_arg--)
648*2718b568SThomas Cort 	{
649*2718b568SThomas Cort 	  while (cp != xbuf && is_mfs(cp[-1]))
650*2718b568SThomas Cort 	  {
651*2718b568SThomas Cort 	    cp--;
652*2718b568SThomas Cort 	    nc++;
653*2718b568SThomas Cort 	  }
654*2718b568SThomas Cort 	  while (cp != xbuf && !is_mfs(cp[-1]))
655*2718b568SThomas Cort 	  {
656*2718b568SThomas Cort 	    cp--;
657*2718b568SThomas Cort 	    nc++;
658*2718b568SThomas Cort 	  }
659*2718b568SThomas Cort 	}
660*2718b568SThomas Cort 	x_goto(cp);
661*2718b568SThomas Cort 	return nc;
662*2718b568SThomas Cort }
663*2718b568SThomas Cort 
664*2718b568SThomas Cort static int
x_fword()665*2718b568SThomas Cort x_fword()
666*2718b568SThomas Cort {
667*2718b568SThomas Cort 	int	nc = 0;
668*2718b568SThomas Cort 	register char	*cp = xcp;
669*2718b568SThomas Cort 
670*2718b568SThomas Cort 	if (cp == xep)  {
671*2718b568SThomas Cort 		x_e_putc(BEL);
672*2718b568SThomas Cort 		return 0;
673*2718b568SThomas Cort 	}
674*2718b568SThomas Cort 	while (x_arg--)
675*2718b568SThomas Cort 	{
676*2718b568SThomas Cort 	  while (cp != xep && is_mfs(*cp))
677*2718b568SThomas Cort 	  {
678*2718b568SThomas Cort 	    cp++;
679*2718b568SThomas Cort 	    nc++;
680*2718b568SThomas Cort 	  }
681*2718b568SThomas Cort 	  while (cp != xep && !is_mfs(*cp))
682*2718b568SThomas Cort 	  {
683*2718b568SThomas Cort 	    cp++;
684*2718b568SThomas Cort 	    nc++;
685*2718b568SThomas Cort 	  }
686*2718b568SThomas Cort 	}
687*2718b568SThomas Cort 	return nc;
688*2718b568SThomas Cort }
689*2718b568SThomas Cort 
690*2718b568SThomas Cort static void
x_goto(cp)691*2718b568SThomas Cort x_goto(cp)
692*2718b568SThomas Cort 	register char *cp;
693*2718b568SThomas Cort {
694*2718b568SThomas Cort   if (cp < xbp || cp >= (xbp + x_displen))
695*2718b568SThomas Cort   {
696*2718b568SThomas Cort     /* we are heading off screen */
697*2718b568SThomas Cort     xcp = cp;
698*2718b568SThomas Cort     x_adjust();
699*2718b568SThomas Cort   }
700*2718b568SThomas Cort   else
701*2718b568SThomas Cort   {
702*2718b568SThomas Cort     if (cp < xcp)		/* move back */
703*2718b568SThomas Cort     {
704*2718b568SThomas Cort       while (cp < xcp)
705*2718b568SThomas Cort 	x_bs(*--xcp);
706*2718b568SThomas Cort     }
707*2718b568SThomas Cort     else
708*2718b568SThomas Cort     {
709*2718b568SThomas Cort       if (cp > xcp)		/* move forward */
710*2718b568SThomas Cort       {
711*2718b568SThomas Cort 	while (cp > xcp)
712*2718b568SThomas Cort 	  x_zotc(*xcp++);
713*2718b568SThomas Cort       }
714*2718b568SThomas Cort     }
715*2718b568SThomas Cort   }
716*2718b568SThomas Cort }
717*2718b568SThomas Cort 
718*2718b568SThomas Cort static void
x_bs(c)719*2718b568SThomas Cort x_bs(c)
720*2718b568SThomas Cort 	int c;
721*2718b568SThomas Cort {
722*2718b568SThomas Cort 	register int i;
723*2718b568SThomas Cort 	i = x_size(c);
724*2718b568SThomas Cort 	while (i--)
725*2718b568SThomas Cort 		x_e_putc('\b');
726*2718b568SThomas Cort }
727*2718b568SThomas Cort 
728*2718b568SThomas Cort static int
x_size_str(cp)729*2718b568SThomas Cort x_size_str(cp)
730*2718b568SThomas Cort 	register char *cp;
731*2718b568SThomas Cort {
732*2718b568SThomas Cort 	register int size = 0;
733*2718b568SThomas Cort 	while (*cp)
734*2718b568SThomas Cort 		size += x_size(*cp++);
735*2718b568SThomas Cort 	return size;
736*2718b568SThomas Cort }
737*2718b568SThomas Cort 
738*2718b568SThomas Cort static int
x_size(c)739*2718b568SThomas Cort x_size(c)
740*2718b568SThomas Cort 	int c;
741*2718b568SThomas Cort {
742*2718b568SThomas Cort 	if (c=='\t')
743*2718b568SThomas Cort 		return 4;	/* Kludge, tabs are always four spaces. */
744*2718b568SThomas Cort 	if (iscntrl((unsigned char)c))		/* control char */
745*2718b568SThomas Cort 		return 2;
746*2718b568SThomas Cort 	return 1;
747*2718b568SThomas Cort }
748*2718b568SThomas Cort 
749*2718b568SThomas Cort static void
x_zots(str)750*2718b568SThomas Cort x_zots(str)
751*2718b568SThomas Cort 	register char *str;
752*2718b568SThomas Cort {
753*2718b568SThomas Cort   register int	adj = x_adj_done;
754*2718b568SThomas Cort 
755*2718b568SThomas Cort   x_lastcp();
756*2718b568SThomas Cort   while (*str && str < xlp && adj == x_adj_done)
757*2718b568SThomas Cort     x_zotc(*str++);
758*2718b568SThomas Cort }
759*2718b568SThomas Cort 
760*2718b568SThomas Cort static void
x_zotc(c)761*2718b568SThomas Cort x_zotc(c)
762*2718b568SThomas Cort 	int c;
763*2718b568SThomas Cort {
764*2718b568SThomas Cort 	if (c == '\t')  {
765*2718b568SThomas Cort 		/*  Kludge, tabs are always four spaces.  */
766*2718b568SThomas Cort 		x_e_puts("    ");
767*2718b568SThomas Cort 	} else if (iscntrl((unsigned char)c))  {
768*2718b568SThomas Cort 		x_e_putc('^');
769*2718b568SThomas Cort 		x_e_putc(UNCTRL(c));
770*2718b568SThomas Cort 	} else
771*2718b568SThomas Cort 		x_e_putc(c);
772*2718b568SThomas Cort }
773*2718b568SThomas Cort 
774*2718b568SThomas Cort static int
x_mv_back(c)775*2718b568SThomas Cort x_mv_back(c)
776*2718b568SThomas Cort 	int c;
777*2718b568SThomas Cort {
778*2718b568SThomas Cort 	int col = xcp - xbuf;
779*2718b568SThomas Cort 
780*2718b568SThomas Cort 	if (col == 0)  {
781*2718b568SThomas Cort 		x_e_putc(BEL);
782*2718b568SThomas Cort 		return KSTD;
783*2718b568SThomas Cort 	}
784*2718b568SThomas Cort 	if (x_arg > col)
785*2718b568SThomas Cort 		x_arg = col;
786*2718b568SThomas Cort 	x_goto(xcp - x_arg);
787*2718b568SThomas Cort 	return KSTD;
788*2718b568SThomas Cort }
789*2718b568SThomas Cort 
790*2718b568SThomas Cort static int
x_mv_forw(c)791*2718b568SThomas Cort x_mv_forw(c)
792*2718b568SThomas Cort 	int c;
793*2718b568SThomas Cort {
794*2718b568SThomas Cort 	int nleft = xep - xcp;
795*2718b568SThomas Cort 
796*2718b568SThomas Cort 	if (!nleft) {
797*2718b568SThomas Cort 		x_e_putc(BEL);
798*2718b568SThomas Cort 		return KSTD;
799*2718b568SThomas Cort 	}
800*2718b568SThomas Cort 	if (x_arg > nleft)
801*2718b568SThomas Cort 		x_arg = nleft;
802*2718b568SThomas Cort 	x_goto(xcp + x_arg);
803*2718b568SThomas Cort 	return KSTD;
804*2718b568SThomas Cort }
805*2718b568SThomas Cort 
806*2718b568SThomas Cort static int
x_search_char_forw(c)807*2718b568SThomas Cort x_search_char_forw(c)
808*2718b568SThomas Cort 	int c;
809*2718b568SThomas Cort {
810*2718b568SThomas Cort 	char *cp = xcp;
811*2718b568SThomas Cort 
812*2718b568SThomas Cort 	*xep = '\0';
813*2718b568SThomas Cort 	c = x_e_getc();
814*2718b568SThomas Cort 	while (x_arg--) {
815*2718b568SThomas Cort 	    if (c < 0
816*2718b568SThomas Cort 	       || ((cp = (cp == xep) ? NULL : strchr(cp + 1, c)) == NULL
817*2718b568SThomas Cort 		   && (cp = strchr(xbuf, c)) == NULL))
818*2718b568SThomas Cort 	    {
819*2718b568SThomas Cort 		    x_e_putc(BEL);
820*2718b568SThomas Cort 		    return KSTD;
821*2718b568SThomas Cort 	    }
822*2718b568SThomas Cort 	}
823*2718b568SThomas Cort 	x_goto(cp);
824*2718b568SThomas Cort 	return KSTD;
825*2718b568SThomas Cort }
826*2718b568SThomas Cort 
827*2718b568SThomas Cort static int
x_search_char_back(c)828*2718b568SThomas Cort x_search_char_back(c)
829*2718b568SThomas Cort 	int c;
830*2718b568SThomas Cort {
831*2718b568SThomas Cort 	char *cp = xcp, *p;
832*2718b568SThomas Cort 
833*2718b568SThomas Cort 	c = x_e_getc();
834*2718b568SThomas Cort 	for (; x_arg--; cp = p)
835*2718b568SThomas Cort 		for (p = cp; ; ) {
836*2718b568SThomas Cort 			if (p-- == xbuf)
837*2718b568SThomas Cort 				p = xep;
838*2718b568SThomas Cort 			if (c < 0 || p == cp) {
839*2718b568SThomas Cort 				x_e_putc(BEL);
840*2718b568SThomas Cort 				return KSTD;
841*2718b568SThomas Cort 			}
842*2718b568SThomas Cort 			if (*p == c)
843*2718b568SThomas Cort 				break;
844*2718b568SThomas Cort 		}
845*2718b568SThomas Cort 	x_goto(cp);
846*2718b568SThomas Cort 	return KSTD;
847*2718b568SThomas Cort }
848*2718b568SThomas Cort 
849*2718b568SThomas Cort static int
x_newline(c)850*2718b568SThomas Cort x_newline(c)
851*2718b568SThomas Cort 	int c;
852*2718b568SThomas Cort {
853*2718b568SThomas Cort 	x_e_putc('\r');
854*2718b568SThomas Cort 	x_e_putc('\n');
855*2718b568SThomas Cort 	x_flush();
856*2718b568SThomas Cort 	*xep++ = '\n';
857*2718b568SThomas Cort 	return KEOL;
858*2718b568SThomas Cort }
859*2718b568SThomas Cort 
860*2718b568SThomas Cort static int
x_end_of_text(c)861*2718b568SThomas Cort x_end_of_text(c)
862*2718b568SThomas Cort 	int c;
863*2718b568SThomas Cort {
864*2718b568SThomas Cort 	return KEOL;
865*2718b568SThomas Cort }
866*2718b568SThomas Cort 
x_beg_hist(c)867*2718b568SThomas Cort static int x_beg_hist(c) int c; { x_load_hist(histlist); return KSTD;}
868*2718b568SThomas Cort 
x_end_hist(c)869*2718b568SThomas Cort static int x_end_hist(c) int c; { x_load_hist(histptr); return KSTD;}
870*2718b568SThomas Cort 
x_prev_com(c)871*2718b568SThomas Cort static int x_prev_com(c) int c; { x_load_hist(x_histp - x_arg); return KSTD;}
872*2718b568SThomas Cort 
x_next_com(c)873*2718b568SThomas Cort static int x_next_com(c) int c; { x_load_hist(x_histp + x_arg); return KSTD;}
874*2718b568SThomas Cort 
875*2718b568SThomas Cort /* Goto a particular history number obtained from argument.
876*2718b568SThomas Cort  * If no argument is given history 1 is probably not what you
877*2718b568SThomas Cort  * want so we'll simply go to the oldest one.
878*2718b568SThomas Cort  */
879*2718b568SThomas Cort static int
x_goto_hist(c)880*2718b568SThomas Cort x_goto_hist(c)
881*2718b568SThomas Cort 	int c;
882*2718b568SThomas Cort {
883*2718b568SThomas Cort 	if (x_arg_defaulted)
884*2718b568SThomas Cort 		x_load_hist(histlist);
885*2718b568SThomas Cort 	else
886*2718b568SThomas Cort 		x_load_hist(histptr + x_arg - source->line);
887*2718b568SThomas Cort 	return KSTD;
888*2718b568SThomas Cort }
889*2718b568SThomas Cort 
890*2718b568SThomas Cort static void
x_load_hist(hp)891*2718b568SThomas Cort x_load_hist(hp)
892*2718b568SThomas Cort 	register char **hp;
893*2718b568SThomas Cort {
894*2718b568SThomas Cort 	int	oldsize;
895*2718b568SThomas Cort 
896*2718b568SThomas Cort 	if (hp < histlist || hp > histptr) {
897*2718b568SThomas Cort 		x_e_putc(BEL);
898*2718b568SThomas Cort 		return;
899*2718b568SThomas Cort 	}
900*2718b568SThomas Cort 	x_histp = hp;
901*2718b568SThomas Cort 	oldsize = x_size_str(xbuf);
902*2718b568SThomas Cort 	strlcpy(xbuf, *hp, xend - xbuf);
903*2718b568SThomas Cort 	xbp = xbuf;
904*2718b568SThomas Cort 	xep = xcp = xbuf + strlen(xbuf);
905*2718b568SThomas Cort 	xlp_valid = FALSE;
906*2718b568SThomas Cort 	if (xep > x_lastcp())
907*2718b568SThomas Cort 	  x_goto(xep);
908*2718b568SThomas Cort 	else
909*2718b568SThomas Cort 	  x_redraw(oldsize);
910*2718b568SThomas Cort }
911*2718b568SThomas Cort 
912*2718b568SThomas Cort static int
x_nl_next_com(c)913*2718b568SThomas Cort x_nl_next_com(c)
914*2718b568SThomas Cort 	int	c;
915*2718b568SThomas Cort {
916*2718b568SThomas Cort 	x_nextcmd = source->line - (histptr - x_histp) + 1;
917*2718b568SThomas Cort 	return (x_newline(c));
918*2718b568SThomas Cort }
919*2718b568SThomas Cort 
920*2718b568SThomas Cort static int
x_eot_del(c)921*2718b568SThomas Cort x_eot_del(c)
922*2718b568SThomas Cort 	int	c;
923*2718b568SThomas Cort {
924*2718b568SThomas Cort 	if (xep == xbuf && x_arg_defaulted)
925*2718b568SThomas Cort 		return (x_end_of_text(c));
926*2718b568SThomas Cort 	else
927*2718b568SThomas Cort 		return (x_del_char(c));
928*2718b568SThomas Cort }
929*2718b568SThomas Cort 
930*2718b568SThomas Cort /* reverse incremental history search */
931*2718b568SThomas Cort static int
x_search_hist(c)932*2718b568SThomas Cort x_search_hist(c)
933*2718b568SThomas Cort 	int c;
934*2718b568SThomas Cort {
935*2718b568SThomas Cort 	int offset = -1;	/* offset of match in xbuf, else -1 */
936*2718b568SThomas Cort 	char pat [256+1];	/* pattern buffer */
937*2718b568SThomas Cort 	register char *p = pat;
938*2718b568SThomas Cort 	Findex f;
939*2718b568SThomas Cort 
940*2718b568SThomas Cort 	*p = '\0';
941*2718b568SThomas Cort 	while (1) {
942*2718b568SThomas Cort 		if (offset < 0) {
943*2718b568SThomas Cort 			x_e_puts("\nI-search: ");
944*2718b568SThomas Cort 			x_e_puts(pat);
945*2718b568SThomas Cort 		}
946*2718b568SThomas Cort 		x_flush();
947*2718b568SThomas Cort 		if ((c = x_e_getc()) < 0)
948*2718b568SThomas Cort 			return KSTD;
949*2718b568SThomas Cort 		f = x_tab[0][c&CHARMASK];
950*2718b568SThomas Cort 		if (c == CTRL('['))
951*2718b568SThomas Cort 			break;
952*2718b568SThomas Cort 		else if (f == XFUNC_search_hist)
953*2718b568SThomas Cort 			offset = x_search(pat, 0, offset);
954*2718b568SThomas Cort 		else if (f == XFUNC_del_back) {
955*2718b568SThomas Cort 			if (p == pat) {
956*2718b568SThomas Cort 				offset = -1;
957*2718b568SThomas Cort 				break;
958*2718b568SThomas Cort 			}
959*2718b568SThomas Cort 			if (p > pat)
960*2718b568SThomas Cort 				*--p = '\0';
961*2718b568SThomas Cort 			if (p == pat)
962*2718b568SThomas Cort 				offset = -1;
963*2718b568SThomas Cort 			else
964*2718b568SThomas Cort 				offset = x_search(pat, 1, offset);
965*2718b568SThomas Cort 			continue;
966*2718b568SThomas Cort 		} else if (f == XFUNC_insert) {
967*2718b568SThomas Cort 			/* add char to pattern */
968*2718b568SThomas Cort 			/* overflow check... */
969*2718b568SThomas Cort 			if (p >= &pat[sizeof(pat) - 1]) {
970*2718b568SThomas Cort 				x_e_putc(BEL);
971*2718b568SThomas Cort 				continue;
972*2718b568SThomas Cort 			}
973*2718b568SThomas Cort 			*p++ = c, *p = '\0';
974*2718b568SThomas Cort 			if (offset >= 0) {
975*2718b568SThomas Cort 				/* already have partial match */
976*2718b568SThomas Cort 				offset = x_match(xbuf, pat);
977*2718b568SThomas Cort 				if (offset >= 0) {
978*2718b568SThomas Cort 					x_goto(xbuf + offset + (p - pat) - (*pat == '^'));
979*2718b568SThomas Cort 					continue;
980*2718b568SThomas Cort 				}
981*2718b568SThomas Cort 			}
982*2718b568SThomas Cort 			offset = x_search(pat, 0, offset);
983*2718b568SThomas Cort 		} else { /* other command */
984*2718b568SThomas Cort 			x_e_ungetc(c);
985*2718b568SThomas Cort 			break;
986*2718b568SThomas Cort 		}
987*2718b568SThomas Cort 	}
988*2718b568SThomas Cort 	if (offset < 0)
989*2718b568SThomas Cort 		x_redraw(-1);
990*2718b568SThomas Cort 	return KSTD;
991*2718b568SThomas Cort }
992*2718b568SThomas Cort 
993*2718b568SThomas Cort /* search backward from current line */
994*2718b568SThomas Cort static int
x_search(pat,sameline,offset)995*2718b568SThomas Cort x_search(pat, sameline, offset)
996*2718b568SThomas Cort 	char *pat;
997*2718b568SThomas Cort 	int sameline;
998*2718b568SThomas Cort 	int offset;
999*2718b568SThomas Cort {
1000*2718b568SThomas Cort 	register char **hp;
1001*2718b568SThomas Cort 	int i;
1002*2718b568SThomas Cort 
1003*2718b568SThomas Cort 	for (hp = x_histp - (sameline ? 0 : 1) ; hp >= histlist; --hp) {
1004*2718b568SThomas Cort 		i = x_match(*hp, pat);
1005*2718b568SThomas Cort 		if (i >= 0) {
1006*2718b568SThomas Cort 			if (offset < 0)
1007*2718b568SThomas Cort 				x_e_putc('\n');
1008*2718b568SThomas Cort 			x_load_hist(hp);
1009*2718b568SThomas Cort 			x_goto(xbuf + i + strlen(pat) - (*pat == '^'));
1010*2718b568SThomas Cort 			return i;
1011*2718b568SThomas Cort 		}
1012*2718b568SThomas Cort 	}
1013*2718b568SThomas Cort 	x_e_putc(BEL);
1014*2718b568SThomas Cort 	x_histp = histptr;
1015*2718b568SThomas Cort 	return -1;
1016*2718b568SThomas Cort }
1017*2718b568SThomas Cort 
1018*2718b568SThomas Cort /* return position of first match of pattern in string, else -1 */
1019*2718b568SThomas Cort static int
x_match(str,pat)1020*2718b568SThomas Cort x_match(str, pat)
1021*2718b568SThomas Cort 	char *str, *pat;
1022*2718b568SThomas Cort {
1023*2718b568SThomas Cort 	if (*pat == '^') {
1024*2718b568SThomas Cort 		return (strncmp(str, pat+1, strlen(pat+1)) == 0) ? 0 : -1;
1025*2718b568SThomas Cort 	} else {
1026*2718b568SThomas Cort 		char *q = strstr(str, pat);
1027*2718b568SThomas Cort 		return (q == NULL) ? -1 : q - str;
1028*2718b568SThomas Cort 	}
1029*2718b568SThomas Cort }
1030*2718b568SThomas Cort 
1031*2718b568SThomas Cort static int
x_del_line(c)1032*2718b568SThomas Cort x_del_line(c)
1033*2718b568SThomas Cort 	int c;
1034*2718b568SThomas Cort {
1035*2718b568SThomas Cort 	int	i, j;
1036*2718b568SThomas Cort 
1037*2718b568SThomas Cort 	*xep = 0;
1038*2718b568SThomas Cort 	i = xep - xbuf;
1039*2718b568SThomas Cort 	j = x_size_str(xbuf);
1040*2718b568SThomas Cort 	xcp = xbuf;
1041*2718b568SThomas Cort 	x_push(i);
1042*2718b568SThomas Cort 	xlp = xbp = xep = xbuf;
1043*2718b568SThomas Cort 	xlp_valid = TRUE;
1044*2718b568SThomas Cort 	*xcp = 0;
1045*2718b568SThomas Cort 	xmp = NULL;
1046*2718b568SThomas Cort 	x_redraw(j);
1047*2718b568SThomas Cort 	return KSTD;
1048*2718b568SThomas Cort }
1049*2718b568SThomas Cort 
1050*2718b568SThomas Cort static int
x_mv_end(c)1051*2718b568SThomas Cort x_mv_end(c)
1052*2718b568SThomas Cort 	int c;
1053*2718b568SThomas Cort {
1054*2718b568SThomas Cort 	x_goto(xep);
1055*2718b568SThomas Cort 	return KSTD;
1056*2718b568SThomas Cort }
1057*2718b568SThomas Cort 
1058*2718b568SThomas Cort static int
x_mv_begin(c)1059*2718b568SThomas Cort x_mv_begin(c)
1060*2718b568SThomas Cort 	int c;
1061*2718b568SThomas Cort {
1062*2718b568SThomas Cort 	x_goto(xbuf);
1063*2718b568SThomas Cort 	return KSTD;
1064*2718b568SThomas Cort }
1065*2718b568SThomas Cort 
1066*2718b568SThomas Cort static int
x_draw_line(c)1067*2718b568SThomas Cort x_draw_line(c)
1068*2718b568SThomas Cort 	int c;
1069*2718b568SThomas Cort {
1070*2718b568SThomas Cort 	x_redraw(-1);
1071*2718b568SThomas Cort 	return KSTD;
1072*2718b568SThomas Cort 
1073*2718b568SThomas Cort }
1074*2718b568SThomas Cort 
1075*2718b568SThomas Cort /* Redraw (part of) the line.  If limit is < 0, the everything is redrawn
1076*2718b568SThomas Cort  * on a NEW line, otherwise limit is the screen column up to which needs
1077*2718b568SThomas Cort  * redrawing.
1078*2718b568SThomas Cort  */
1079*2718b568SThomas Cort static void
x_redraw(limit)1080*2718b568SThomas Cort x_redraw(limit)
1081*2718b568SThomas Cort   int limit;
1082*2718b568SThomas Cort {
1083*2718b568SThomas Cort 	int	i, j;
1084*2718b568SThomas Cort 	char	*cp;
1085*2718b568SThomas Cort 
1086*2718b568SThomas Cort 	x_adj_ok = 0;
1087*2718b568SThomas Cort 	if (limit == -1)
1088*2718b568SThomas Cort 		x_e_putc('\n');
1089*2718b568SThomas Cort 	else
1090*2718b568SThomas Cort 		x_e_putc('\r');
1091*2718b568SThomas Cort 	x_flush();
1092*2718b568SThomas Cort 	if (xbp == xbuf)
1093*2718b568SThomas Cort 	{
1094*2718b568SThomas Cort 	  pprompt(prompt + prompt_skip, 0);
1095*2718b568SThomas Cort 	  x_col = promptlen(prompt, (const char **) 0);
1096*2718b568SThomas Cort 	}
1097*2718b568SThomas Cort 	x_displen = xx_cols - 2 - x_col;
1098*2718b568SThomas Cort 	xlp_valid = FALSE;
1099*2718b568SThomas Cort 	cp = x_lastcp();
1100*2718b568SThomas Cort 	x_zots(xbp);
1101*2718b568SThomas Cort 	if (xbp != xbuf || xep > xlp)
1102*2718b568SThomas Cort 	  limit = xx_cols;
1103*2718b568SThomas Cort 	if (limit >= 0)
1104*2718b568SThomas Cort 	{
1105*2718b568SThomas Cort 	  if (xep > xlp)
1106*2718b568SThomas Cort 	    i = 0;			/* we fill the line */
1107*2718b568SThomas Cort 	  else
1108*2718b568SThomas Cort 	    i = limit - (xlp - xbp);
1109*2718b568SThomas Cort 
1110*2718b568SThomas Cort 	  for (j = 0; j < i && x_col < (xx_cols - 2); j++)
1111*2718b568SThomas Cort 	    x_e_putc(' ');
1112*2718b568SThomas Cort 	  i = ' ';
1113*2718b568SThomas Cort 	  if (xep > xlp)		/* more off screen */
1114*2718b568SThomas Cort 	  {
1115*2718b568SThomas Cort 	    if (xbp > xbuf)
1116*2718b568SThomas Cort 	      i = '*';
1117*2718b568SThomas Cort 	    else
1118*2718b568SThomas Cort 	      i = '>';
1119*2718b568SThomas Cort 	  }
1120*2718b568SThomas Cort 	  else
1121*2718b568SThomas Cort 	    if (xbp > xbuf)
1122*2718b568SThomas Cort 	      i = '<';
1123*2718b568SThomas Cort 	  x_e_putc(i);
1124*2718b568SThomas Cort 	  j++;
1125*2718b568SThomas Cort 	  while (j--)
1126*2718b568SThomas Cort 	    x_e_putc('\b');
1127*2718b568SThomas Cort 	}
1128*2718b568SThomas Cort 	for (cp = xlp; cp > xcp; )
1129*2718b568SThomas Cort 	  x_bs(*--cp);
1130*2718b568SThomas Cort 	x_adj_ok = 1;
1131*2718b568SThomas Cort 	D__(x_flush();)
1132*2718b568SThomas Cort 	return;
1133*2718b568SThomas Cort }
1134*2718b568SThomas Cort 
1135*2718b568SThomas Cort static int
x_transpose(c)1136*2718b568SThomas Cort x_transpose(c)
1137*2718b568SThomas Cort 	int c;
1138*2718b568SThomas Cort {
1139*2718b568SThomas Cort 	char	tmp;
1140*2718b568SThomas Cort 
1141*2718b568SThomas Cort 	/* What transpose is meant to do seems to be up for debate. This
1142*2718b568SThomas Cort 	 * is a general summary of the options; the text is abcd with the
1143*2718b568SThomas Cort 	 * upper case character or underscore indicating the cursor position:
1144*2718b568SThomas Cort 	 *     Who			Before	After  Before	After
1145*2718b568SThomas Cort 	 *     at&t ksh in emacs mode:	abCd	abdC   abcd_	(bell)
1146*2718b568SThomas Cort 	 *     at&t ksh in gmacs mode:	abCd	baCd   abcd_	abdc_
1147*2718b568SThomas Cort 	 *     gnu emacs:		abCd	acbD   abcd_	abdc_
1148*2718b568SThomas Cort 	 * Pdksh currently goes with GNU behavior since I believe this is the
1149*2718b568SThomas Cort 	 * most common version of emacs, unless in gmacs mode, in which case
1150*2718b568SThomas Cort 	 * it does the at&t ksh gmacs mode.
1151*2718b568SThomas Cort 	 * This should really be broken up into 3 functions so users can bind
1152*2718b568SThomas Cort 	 * to the one they want.
1153*2718b568SThomas Cort 	 */
1154*2718b568SThomas Cort 	if (xcp == xbuf) {
1155*2718b568SThomas Cort 		x_e_putc(BEL);
1156*2718b568SThomas Cort 		return KSTD;
1157*2718b568SThomas Cort 	} else if (xcp == xep || Flag(FGMACS)) {
1158*2718b568SThomas Cort 		if (xcp - xbuf == 1) {
1159*2718b568SThomas Cort 			x_e_putc(BEL);
1160*2718b568SThomas Cort 			return KSTD;
1161*2718b568SThomas Cort 		}
1162*2718b568SThomas Cort 		/* Gosling/Unipress emacs style: Swap two characters before the
1163*2718b568SThomas Cort 		 * cursor, do not change cursor position
1164*2718b568SThomas Cort 		 */
1165*2718b568SThomas Cort 		x_bs(xcp[-1]);
1166*2718b568SThomas Cort 		x_bs(xcp[-2]);
1167*2718b568SThomas Cort 		x_zotc(xcp[-1]);
1168*2718b568SThomas Cort 		x_zotc(xcp[-2]);
1169*2718b568SThomas Cort 		tmp = xcp[-1];
1170*2718b568SThomas Cort 		xcp[-1] = xcp[-2];
1171*2718b568SThomas Cort 		xcp[-2] = tmp;
1172*2718b568SThomas Cort 	} else {
1173*2718b568SThomas Cort 		/* GNU emacs style: Swap the characters before and under the
1174*2718b568SThomas Cort 		 * cursor, move cursor position along one.
1175*2718b568SThomas Cort 		 */
1176*2718b568SThomas Cort 		x_bs(xcp[-1]);
1177*2718b568SThomas Cort 		x_zotc(xcp[0]);
1178*2718b568SThomas Cort 		x_zotc(xcp[-1]);
1179*2718b568SThomas Cort 		tmp = xcp[-1];
1180*2718b568SThomas Cort 		xcp[-1] = xcp[0];
1181*2718b568SThomas Cort 		xcp[0] = tmp;
1182*2718b568SThomas Cort 		x_bs(xcp[0]);
1183*2718b568SThomas Cort 		x_goto(xcp + 1);
1184*2718b568SThomas Cort 	}
1185*2718b568SThomas Cort 	return KSTD;
1186*2718b568SThomas Cort }
1187*2718b568SThomas Cort 
1188*2718b568SThomas Cort static int
x_literal(c)1189*2718b568SThomas Cort x_literal(c)
1190*2718b568SThomas Cort 	int c;
1191*2718b568SThomas Cort {
1192*2718b568SThomas Cort 	x_curprefix = -1;
1193*2718b568SThomas Cort 	return KSTD;
1194*2718b568SThomas Cort }
1195*2718b568SThomas Cort 
1196*2718b568SThomas Cort static int
x_meta1(c)1197*2718b568SThomas Cort x_meta1(c)
1198*2718b568SThomas Cort 	int c;
1199*2718b568SThomas Cort {
1200*2718b568SThomas Cort 	x_curprefix = 1;
1201*2718b568SThomas Cort 	return KSTD;
1202*2718b568SThomas Cort }
1203*2718b568SThomas Cort 
1204*2718b568SThomas Cort static int
x_meta2(c)1205*2718b568SThomas Cort x_meta2(c)
1206*2718b568SThomas Cort 	int c;
1207*2718b568SThomas Cort {
1208*2718b568SThomas Cort 	x_curprefix = 2;
1209*2718b568SThomas Cort 	return KSTD;
1210*2718b568SThomas Cort }
1211*2718b568SThomas Cort 
1212*2718b568SThomas Cort #ifdef OS2
1213*2718b568SThomas Cort static int
x_meta3(c)1214*2718b568SThomas Cort x_meta3(c)
1215*2718b568SThomas Cort 	int c;
1216*2718b568SThomas Cort {
1217*2718b568SThomas Cort 	x_curprefix = 3;
1218*2718b568SThomas Cort 	return KSTD;
1219*2718b568SThomas Cort }
1220*2718b568SThomas Cort #endif /* OS2 */
1221*2718b568SThomas Cort 
1222*2718b568SThomas Cort static int
x_kill(c)1223*2718b568SThomas Cort x_kill(c)
1224*2718b568SThomas Cort 	int c;
1225*2718b568SThomas Cort {
1226*2718b568SThomas Cort 	int col = xcp - xbuf;
1227*2718b568SThomas Cort 	int lastcol = xep - xbuf;
1228*2718b568SThomas Cort 	int ndel;
1229*2718b568SThomas Cort 
1230*2718b568SThomas Cort 	if (x_arg_defaulted)
1231*2718b568SThomas Cort 		x_arg = lastcol;
1232*2718b568SThomas Cort 	else if (x_arg > lastcol)
1233*2718b568SThomas Cort 		x_arg = lastcol;
1234*2718b568SThomas Cort 	ndel = x_arg - col;
1235*2718b568SThomas Cort 	if (ndel < 0) {
1236*2718b568SThomas Cort 		x_goto(xbuf + x_arg);
1237*2718b568SThomas Cort 		ndel = -ndel;
1238*2718b568SThomas Cort 	}
1239*2718b568SThomas Cort 	x_delete(ndel, TRUE);
1240*2718b568SThomas Cort 	return KSTD;
1241*2718b568SThomas Cort }
1242*2718b568SThomas Cort 
1243*2718b568SThomas Cort static void
x_push(nchars)1244*2718b568SThomas Cort x_push(nchars)
1245*2718b568SThomas Cort 	int nchars;
1246*2718b568SThomas Cort {
1247*2718b568SThomas Cort 	char	*cp = str_nsave(xcp, nchars, AEDIT);
1248*2718b568SThomas Cort 	if (killstack[killsp])
1249*2718b568SThomas Cort 		afree((void *)killstack[killsp], AEDIT);
1250*2718b568SThomas Cort 	killstack[killsp] = cp;
1251*2718b568SThomas Cort 	killsp = (killsp + 1) % KILLSIZE;
1252*2718b568SThomas Cort }
1253*2718b568SThomas Cort 
1254*2718b568SThomas Cort static int
x_yank(c)1255*2718b568SThomas Cort x_yank(c)
1256*2718b568SThomas Cort 	int c;
1257*2718b568SThomas Cort {
1258*2718b568SThomas Cort 	if (killsp == 0)
1259*2718b568SThomas Cort 		killtp = KILLSIZE;
1260*2718b568SThomas Cort 	else
1261*2718b568SThomas Cort 		killtp = killsp;
1262*2718b568SThomas Cort 	killtp--;
1263*2718b568SThomas Cort 	if (killstack[killtp] == 0)  {
1264*2718b568SThomas Cort 		x_e_puts("\nnothing to yank");
1265*2718b568SThomas Cort 		x_redraw(-1);
1266*2718b568SThomas Cort 		return KSTD;
1267*2718b568SThomas Cort 	}
1268*2718b568SThomas Cort 	xmp = xcp;
1269*2718b568SThomas Cort 	x_ins(killstack[killtp]);
1270*2718b568SThomas Cort 	return KSTD;
1271*2718b568SThomas Cort }
1272*2718b568SThomas Cort 
1273*2718b568SThomas Cort static int
x_meta_yank(c)1274*2718b568SThomas Cort x_meta_yank(c)
1275*2718b568SThomas Cort 	int c;
1276*2718b568SThomas Cort {
1277*2718b568SThomas Cort 	int	len;
1278*2718b568SThomas Cort 	if ((x_last_command != XFUNC_yank && x_last_command != XFUNC_meta_yank)
1279*2718b568SThomas Cort 	    || killstack[killtp] == 0) {
1280*2718b568SThomas Cort 		killtp = killsp;
1281*2718b568SThomas Cort 		x_e_puts("\nyank something first");
1282*2718b568SThomas Cort 		x_redraw(-1);
1283*2718b568SThomas Cort 		return KSTD;
1284*2718b568SThomas Cort 	}
1285*2718b568SThomas Cort 	len = strlen(killstack[killtp]);
1286*2718b568SThomas Cort 	x_goto(xcp - len);
1287*2718b568SThomas Cort 	x_delete(len, FALSE);
1288*2718b568SThomas Cort 	do {
1289*2718b568SThomas Cort 		if (killtp == 0)
1290*2718b568SThomas Cort 			killtp = KILLSIZE - 1;
1291*2718b568SThomas Cort 		else
1292*2718b568SThomas Cort 			killtp--;
1293*2718b568SThomas Cort 	} while (killstack[killtp] == 0);
1294*2718b568SThomas Cort 	x_ins(killstack[killtp]);
1295*2718b568SThomas Cort 	return KSTD;
1296*2718b568SThomas Cort }
1297*2718b568SThomas Cort 
1298*2718b568SThomas Cort static int
x_abort(c)1299*2718b568SThomas Cort x_abort(c)
1300*2718b568SThomas Cort 	int c;
1301*2718b568SThomas Cort {
1302*2718b568SThomas Cort 	/* x_zotc(c); */
1303*2718b568SThomas Cort 	xlp = xep = xcp = xbp = xbuf;
1304*2718b568SThomas Cort 	xlp_valid = TRUE;
1305*2718b568SThomas Cort 	*xcp = 0;
1306*2718b568SThomas Cort 	return KINTR;
1307*2718b568SThomas Cort }
1308*2718b568SThomas Cort 
1309*2718b568SThomas Cort static int
x_error(c)1310*2718b568SThomas Cort x_error(c)
1311*2718b568SThomas Cort 	int c;
1312*2718b568SThomas Cort {
1313*2718b568SThomas Cort 	x_e_putc(BEL);
1314*2718b568SThomas Cort 	return KSTD;
1315*2718b568SThomas Cort }
1316*2718b568SThomas Cort 
1317*2718b568SThomas Cort static int
x_stuffreset(c)1318*2718b568SThomas Cort x_stuffreset(c)
1319*2718b568SThomas Cort 	int c;
1320*2718b568SThomas Cort {
1321*2718b568SThomas Cort #ifdef TIOCSTI
1322*2718b568SThomas Cort 	(void)x_stuff(c);
1323*2718b568SThomas Cort 	return KINTR;
1324*2718b568SThomas Cort #else
1325*2718b568SThomas Cort 	x_zotc(c);
1326*2718b568SThomas Cort 	xlp = xcp = xep = xbp = xbuf;
1327*2718b568SThomas Cort 	xlp_valid = TRUE;
1328*2718b568SThomas Cort 	*xcp = 0;
1329*2718b568SThomas Cort 	x_redraw(-1);
1330*2718b568SThomas Cort 	return KSTD;
1331*2718b568SThomas Cort #endif
1332*2718b568SThomas Cort }
1333*2718b568SThomas Cort 
1334*2718b568SThomas Cort static int
x_stuff(c)1335*2718b568SThomas Cort x_stuff(c)
1336*2718b568SThomas Cort 	int c;
1337*2718b568SThomas Cort {
1338*2718b568SThomas Cort #if 0 || defined TIOCSTI
1339*2718b568SThomas Cort 	char	ch = c;
1340*2718b568SThomas Cort 	bool_t	savmode = x_mode(FALSE);
1341*2718b568SThomas Cort 
1342*2718b568SThomas Cort 	(void)ioctl(TTY, TIOCSTI, &ch);
1343*2718b568SThomas Cort 	(void)x_mode(savmode);
1344*2718b568SThomas Cort 	x_redraw(-1);
1345*2718b568SThomas Cort #endif
1346*2718b568SThomas Cort 	return KSTD;
1347*2718b568SThomas Cort }
1348*2718b568SThomas Cort 
1349*2718b568SThomas Cort static char *
x_mapin(cp,area)1350*2718b568SThomas Cort x_mapin(cp, area)
1351*2718b568SThomas Cort 	const char *cp;
1352*2718b568SThomas Cort 	Area *area;
1353*2718b568SThomas Cort {
1354*2718b568SThomas Cort 	char *new, *op;
1355*2718b568SThomas Cort 
1356*2718b568SThomas Cort 	op = new = str_save(cp, area);
1357*2718b568SThomas Cort 	while (*cp)  {
1358*2718b568SThomas Cort 		/* XXX -- should handle \^ escape? */
1359*2718b568SThomas Cort 		if (*cp == '^')  {
1360*2718b568SThomas Cort 			cp++;
1361*2718b568SThomas Cort #ifdef OS2
1362*2718b568SThomas Cort 			if (*cp == '0')	/* To define function keys */
1363*2718b568SThomas Cort 				*op++ = 0xE0;
1364*2718b568SThomas Cort 			else
1365*2718b568SThomas Cort #endif /* OS2 */
1366*2718b568SThomas Cort 			if (*cp >= '?')	/* includes '?'; ASCII */
1367*2718b568SThomas Cort 				*op++ = CTRL(*cp);
1368*2718b568SThomas Cort 			else  {
1369*2718b568SThomas Cort 				*op++ = '^';
1370*2718b568SThomas Cort 				cp--;
1371*2718b568SThomas Cort 			}
1372*2718b568SThomas Cort 		} else
1373*2718b568SThomas Cort 			*op++ = *cp;
1374*2718b568SThomas Cort 		cp++;
1375*2718b568SThomas Cort 	}
1376*2718b568SThomas Cort 	*op = '\0';
1377*2718b568SThomas Cort 
1378*2718b568SThomas Cort 	return new;
1379*2718b568SThomas Cort }
1380*2718b568SThomas Cort 
1381*2718b568SThomas Cort static char *
x_mapout(c)1382*2718b568SThomas Cort x_mapout(c)
1383*2718b568SThomas Cort 	int c;
1384*2718b568SThomas Cort {
1385*2718b568SThomas Cort 	static char buf[8];
1386*2718b568SThomas Cort 	register char *p = buf;
1387*2718b568SThomas Cort 
1388*2718b568SThomas Cort #ifdef OS2
1389*2718b568SThomas Cort 	if (c == 0xE0) {
1390*2718b568SThomas Cort 		*p++ = '^';
1391*2718b568SThomas Cort 		*p++ = '0';
1392*2718b568SThomas Cort 	} else
1393*2718b568SThomas Cort #endif /* OS2 */
1394*2718b568SThomas Cort 	if (iscntrl((unsigned char)c))  {
1395*2718b568SThomas Cort 		*p++ = '^';
1396*2718b568SThomas Cort 		*p++ = UNCTRL(c);
1397*2718b568SThomas Cort 	} else
1398*2718b568SThomas Cort 		*p++ = c;
1399*2718b568SThomas Cort 	*p = 0;
1400*2718b568SThomas Cort 	return buf;
1401*2718b568SThomas Cort }
1402*2718b568SThomas Cort 
1403*2718b568SThomas Cort static void
x_print(prefix,key)1404*2718b568SThomas Cort x_print(prefix, key)
1405*2718b568SThomas Cort 	int prefix, key;
1406*2718b568SThomas Cort {
1407*2718b568SThomas Cort 	if (prefix == 1)
1408*2718b568SThomas Cort 		shprintf("%s", x_mapout(x_prefix1));
1409*2718b568SThomas Cort 	if (prefix == 2)
1410*2718b568SThomas Cort 		shprintf("%s", x_mapout(x_prefix2));
1411*2718b568SThomas Cort #ifdef OS2
1412*2718b568SThomas Cort 	if (prefix == 3)
1413*2718b568SThomas Cort 		shprintf("%s", x_mapout(x_prefix3));
1414*2718b568SThomas Cort #endif /* OS2 */
1415*2718b568SThomas Cort 	shprintf("%s = ", x_mapout(key));
1416*2718b568SThomas Cort 	if (x_tab[prefix][key] != XFUNC_ins_string)
1417*2718b568SThomas Cort 		shprintf("%s\n", x_ftab[x_tab[prefix][key]].xf_name);
1418*2718b568SThomas Cort 	else
1419*2718b568SThomas Cort 		shprintf("'%s'\n", x_atab[prefix][key]);
1420*2718b568SThomas Cort }
1421*2718b568SThomas Cort 
1422*2718b568SThomas Cort int
x_bind(a1,a2,macro,list)1423*2718b568SThomas Cort x_bind(a1, a2, macro, list)
1424*2718b568SThomas Cort 	const char *a1, *a2;
1425*2718b568SThomas Cort 	int macro;		/* bind -m */
1426*2718b568SThomas Cort 	int list;		/* bind -l */
1427*2718b568SThomas Cort {
1428*2718b568SThomas Cort 	Findex f;
1429*2718b568SThomas Cort 	int prefix, key;
1430*2718b568SThomas Cort 	char *sp = NULL;
1431*2718b568SThomas Cort 	char *m1, *m2;
1432*2718b568SThomas Cort 
1433*2718b568SThomas Cort 	if (x_tab == NULL) {
1434*2718b568SThomas Cort 		bi_errorf("cannot bind, not a tty");
1435*2718b568SThomas Cort 		return 1;
1436*2718b568SThomas Cort 	}
1437*2718b568SThomas Cort 
1438*2718b568SThomas Cort 	/* List function names */
1439*2718b568SThomas Cort 	if (list) {
1440*2718b568SThomas Cort 		for (f = 0; f < NELEM(x_ftab); f++)
1441*2718b568SThomas Cort 			if (x_ftab[f].xf_name
1442*2718b568SThomas Cort 			    && !(x_ftab[f].xf_flags & XF_NOBIND))
1443*2718b568SThomas Cort 				shprintf("%s\n", x_ftab[f].xf_name);
1444*2718b568SThomas Cort 		return 0;
1445*2718b568SThomas Cort 	}
1446*2718b568SThomas Cort 
1447*2718b568SThomas Cort 	if (a1 == NULL) {
1448*2718b568SThomas Cort 		for (prefix = 0; prefix < X_NTABS; prefix++)
1449*2718b568SThomas Cort 			for (key = 0; key < X_TABSZ; key++) {
1450*2718b568SThomas Cort 				f = x_tab[prefix][key];
1451*2718b568SThomas Cort 				if (f == XFUNC_insert || f == XFUNC_error
1452*2718b568SThomas Cort 				    || (macro && f != XFUNC_ins_string))
1453*2718b568SThomas Cort 					continue;
1454*2718b568SThomas Cort 				x_print(prefix, key);
1455*2718b568SThomas Cort 			}
1456*2718b568SThomas Cort 		return 0;
1457*2718b568SThomas Cort 	}
1458*2718b568SThomas Cort 
1459*2718b568SThomas Cort 	m2 = m1 = x_mapin(a1, ATEMP);
1460*2718b568SThomas Cort 	prefix = key = 0;
1461*2718b568SThomas Cort 	for (;; m1++) {
1462*2718b568SThomas Cort 		key = *m1 & CHARMASK;
1463*2718b568SThomas Cort 		if (x_tab[prefix][key] == XFUNC_meta1)
1464*2718b568SThomas Cort 			prefix = 1;
1465*2718b568SThomas Cort 		else if (x_tab[prefix][key] == XFUNC_meta2)
1466*2718b568SThomas Cort 			prefix = 2;
1467*2718b568SThomas Cort #ifdef OS2
1468*2718b568SThomas Cort 		else if (x_tab[prefix][key] == XFUNC_meta3)
1469*2718b568SThomas Cort 			prefix = 3;
1470*2718b568SThomas Cort #endif /* OS2 */
1471*2718b568SThomas Cort 		else
1472*2718b568SThomas Cort 			break;
1473*2718b568SThomas Cort 	}
1474*2718b568SThomas Cort 	afree(m2, ATEMP);
1475*2718b568SThomas Cort 
1476*2718b568SThomas Cort 	if (a2 == NULL) {
1477*2718b568SThomas Cort 		x_print(prefix, key);
1478*2718b568SThomas Cort 		return 0;
1479*2718b568SThomas Cort 	}
1480*2718b568SThomas Cort 
1481*2718b568SThomas Cort 	if (*a2 == 0)
1482*2718b568SThomas Cort 		f = XFUNC_insert;
1483*2718b568SThomas Cort 	else if (!macro) {
1484*2718b568SThomas Cort 		for (f = 0; f < NELEM(x_ftab); f++)
1485*2718b568SThomas Cort 			if (x_ftab[f].xf_name
1486*2718b568SThomas Cort 			    && strcmp(x_ftab[f].xf_name, a2) == 0)
1487*2718b568SThomas Cort 				break;
1488*2718b568SThomas Cort 		if (f == NELEM(x_ftab) || x_ftab[f].xf_flags & XF_NOBIND) {
1489*2718b568SThomas Cort 			bi_errorf("%s: no such function", a2);
1490*2718b568SThomas Cort 			return 1;
1491*2718b568SThomas Cort 		}
1492*2718b568SThomas Cort #if 0		/* This breaks the bind commands that map arrow keys */
1493*2718b568SThomas Cort 		if (f == XFUNC_meta1)
1494*2718b568SThomas Cort 			x_prefix1 = key;
1495*2718b568SThomas Cort 		if (f == XFUNC_meta2)
1496*2718b568SThomas Cort 			x_prefix2 = key;
1497*2718b568SThomas Cort #endif /* 0 */
1498*2718b568SThomas Cort 	} else {
1499*2718b568SThomas Cort 		f = XFUNC_ins_string;
1500*2718b568SThomas Cort 		sp = x_mapin(a2, AEDIT);
1501*2718b568SThomas Cort 	}
1502*2718b568SThomas Cort 
1503*2718b568SThomas Cort 	if (x_tab[prefix][key] == XFUNC_ins_string && x_atab[prefix][key])
1504*2718b568SThomas Cort 		afree((void *)x_atab[prefix][key], AEDIT);
1505*2718b568SThomas Cort 	x_tab[prefix][key] = f;
1506*2718b568SThomas Cort 	x_atab[prefix][key] = sp;
1507*2718b568SThomas Cort 
1508*2718b568SThomas Cort 	/* Track what the user has bound so x_emacs_keys() won't toast things */
1509*2718b568SThomas Cort 	if (f == XFUNC_insert)
1510*2718b568SThomas Cort 		x_bound[(prefix * X_TABSZ + key) / 8] &=
1511*2718b568SThomas Cort 			~(1 << ((prefix * X_TABSZ + key) % 8));
1512*2718b568SThomas Cort 	else
1513*2718b568SThomas Cort 		x_bound[(prefix * X_TABSZ + key) / 8] |=
1514*2718b568SThomas Cort 			(1 << ((prefix * X_TABSZ + key) % 8));
1515*2718b568SThomas Cort 
1516*2718b568SThomas Cort 	return 0;
1517*2718b568SThomas Cort }
1518*2718b568SThomas Cort 
1519*2718b568SThomas Cort void
x_init_emacs()1520*2718b568SThomas Cort x_init_emacs()
1521*2718b568SThomas Cort {
1522*2718b568SThomas Cort 	size_t i;
1523*2718b568SThomas Cort 	register int j;
1524*2718b568SThomas Cort 	char *locale;
1525*2718b568SThomas Cort 
1526*2718b568SThomas Cort 	ainit(AEDIT);
1527*2718b568SThomas Cort 	x_nextcmd = -1;
1528*2718b568SThomas Cort 
1529*2718b568SThomas Cort 	x_tab = (Findex (*)[X_TABSZ]) alloc(sizeofN(*x_tab, X_NTABS), AEDIT);
1530*2718b568SThomas Cort 	for (j = 0; j < X_TABSZ; j++)
1531*2718b568SThomas Cort 		x_tab[0][j] = XFUNC_insert;
1532*2718b568SThomas Cort 	for (i = 1; i < X_NTABS; i++)
1533*2718b568SThomas Cort 		for (j = 0; j < X_TABSZ; j++)
1534*2718b568SThomas Cort 			x_tab[i][j] = XFUNC_error;
1535*2718b568SThomas Cort 	for (i = 0; i < NELEM(x_defbindings); i++)
1536*2718b568SThomas Cort 		x_tab[(unsigned char)x_defbindings[i].xdb_tab][x_defbindings[i].xdb_char]
1537*2718b568SThomas Cort 			= x_defbindings[i].xdb_func;
1538*2718b568SThomas Cort 
1539*2718b568SThomas Cort 	x_atab = (char *(*)[X_TABSZ]) alloc(sizeofN(*x_atab, X_NTABS), AEDIT);
1540*2718b568SThomas Cort 	for (i = 1; i < X_NTABS; i++)
1541*2718b568SThomas Cort 		for (j = 0; j < X_TABSZ; j++)
1542*2718b568SThomas Cort 			x_atab[i][j] = NULL;
1543*2718b568SThomas Cort 
1544*2718b568SThomas Cort 	/* Determine if we can translate meta key or use 8-bit AscII
1545*2718b568SThomas Cort 	 * XXX - It would be nice if there was a locale attribute to
1546*2718b568SThomas Cort 	 * determine if the locale is 7-bit or not.
1547*2718b568SThomas Cort 	 */
1548*2718b568SThomas Cort 	locale = setlocale(LC_CTYPE, NULL);
1549*2718b568SThomas Cort 	if (locale == NULL || !strcmp(locale, "C") || !strcmp(locale, "POSIX"))
1550*2718b568SThomas Cort 		Flag(FEMACSUSEMETA) = 0;
1551*2718b568SThomas Cort }
1552*2718b568SThomas Cort 
1553*2718b568SThomas Cort static void bind_if_not_bound(int p, int k, int func);
1554*2718b568SThomas Cort 
1555*2718b568SThomas Cort static void
bind_if_not_bound(p,k,func)1556*2718b568SThomas Cort bind_if_not_bound(p, k, func)
1557*2718b568SThomas Cort 	int p, k;
1558*2718b568SThomas Cort 	int func;
1559*2718b568SThomas Cort {
1560*2718b568SThomas Cort 	/* Has user already bound this key?  If so, don't override it */
1561*2718b568SThomas Cort 	if (x_bound[((p) * X_TABSZ + (k)) / 8]
1562*2718b568SThomas Cort 	    & (1 << (((p) * X_TABSZ + (k)) % 8)))
1563*2718b568SThomas Cort 		return;
1564*2718b568SThomas Cort 
1565*2718b568SThomas Cort 	x_tab[p][k] = func;
1566*2718b568SThomas Cort }
1567*2718b568SThomas Cort 
1568*2718b568SThomas Cort void
x_emacs_keys(ec)1569*2718b568SThomas Cort x_emacs_keys(ec)
1570*2718b568SThomas Cort 	X_chars *ec;
1571*2718b568SThomas Cort {
1572*2718b568SThomas Cort 	if (ec->erase >= 0) {
1573*2718b568SThomas Cort 		bind_if_not_bound(0, ec->erase, XFUNC_del_back);
1574*2718b568SThomas Cort 		bind_if_not_bound(1, ec->erase, XFUNC_del_bword);
1575*2718b568SThomas Cort 	}
1576*2718b568SThomas Cort 	if (ec->kill >= 0)
1577*2718b568SThomas Cort 		bind_if_not_bound(0, ec->kill, XFUNC_del_line);
1578*2718b568SThomas Cort 	if (ec->werase >= 0)
1579*2718b568SThomas Cort 		bind_if_not_bound(0, ec->werase, XFUNC_del_bword);
1580*2718b568SThomas Cort 	if (ec->intr >= 0)
1581*2718b568SThomas Cort 		bind_if_not_bound(0, ec->intr, XFUNC_abort);
1582*2718b568SThomas Cort 	if (ec->quit >= 0)
1583*2718b568SThomas Cort 		bind_if_not_bound(0, ec->quit, XFUNC_noop);
1584*2718b568SThomas Cort }
1585*2718b568SThomas Cort 
1586*2718b568SThomas Cort static int
x_set_mark(c)1587*2718b568SThomas Cort x_set_mark(c)
1588*2718b568SThomas Cort 	int c;
1589*2718b568SThomas Cort {
1590*2718b568SThomas Cort 	xmp = xcp;
1591*2718b568SThomas Cort 	return KSTD;
1592*2718b568SThomas Cort }
1593*2718b568SThomas Cort 
1594*2718b568SThomas Cort static int
x_kill_region(c)1595*2718b568SThomas Cort x_kill_region(c)
1596*2718b568SThomas Cort 	int c;
1597*2718b568SThomas Cort {
1598*2718b568SThomas Cort 	int	rsize;
1599*2718b568SThomas Cort 	char	*xr;
1600*2718b568SThomas Cort 
1601*2718b568SThomas Cort 	if (xmp == NULL) {
1602*2718b568SThomas Cort 		x_e_putc(BEL);
1603*2718b568SThomas Cort 		return KSTD;
1604*2718b568SThomas Cort 	}
1605*2718b568SThomas Cort 	if (xmp > xcp) {
1606*2718b568SThomas Cort 		rsize = xmp - xcp;
1607*2718b568SThomas Cort 		xr = xcp;
1608*2718b568SThomas Cort 	} else {
1609*2718b568SThomas Cort 		rsize = xcp - xmp;
1610*2718b568SThomas Cort 		xr = xmp;
1611*2718b568SThomas Cort 	}
1612*2718b568SThomas Cort 	x_goto(xr);
1613*2718b568SThomas Cort 	x_delete(rsize, TRUE);
1614*2718b568SThomas Cort 	xmp = xr;
1615*2718b568SThomas Cort 	return KSTD;
1616*2718b568SThomas Cort }
1617*2718b568SThomas Cort 
1618*2718b568SThomas Cort static int
x_xchg_point_mark(c)1619*2718b568SThomas Cort x_xchg_point_mark(c)
1620*2718b568SThomas Cort 	int c;
1621*2718b568SThomas Cort {
1622*2718b568SThomas Cort 	char	*tmp;
1623*2718b568SThomas Cort 
1624*2718b568SThomas Cort 	if (xmp == NULL) {
1625*2718b568SThomas Cort 		x_e_putc(BEL);
1626*2718b568SThomas Cort 		return KSTD;
1627*2718b568SThomas Cort 	}
1628*2718b568SThomas Cort 	tmp = xmp;
1629*2718b568SThomas Cort 	xmp = xcp;
1630*2718b568SThomas Cort 	x_goto( tmp );
1631*2718b568SThomas Cort 	return KSTD;
1632*2718b568SThomas Cort }
1633*2718b568SThomas Cort 
1634*2718b568SThomas Cort static int
x_version(c)1635*2718b568SThomas Cort x_version(c)
1636*2718b568SThomas Cort 	int c;
1637*2718b568SThomas Cort {
1638*2718b568SThomas Cort 	char *o_xbuf = xbuf, *o_xend = xend;
1639*2718b568SThomas Cort 	char *o_xbp = xbp, *o_xep = xep, *o_xcp = xcp;
1640*2718b568SThomas Cort 	int lim = x_lastcp() - xbp;
1641*2718b568SThomas Cort 
1642*2718b568SThomas Cort 	xbuf = xbp = xcp = ksh_version + 4;
1643*2718b568SThomas Cort 	xend = xep = ksh_version + 4 + strlen(ksh_version + 4);
1644*2718b568SThomas Cort 	x_redraw(lim);
1645*2718b568SThomas Cort 	x_flush();
1646*2718b568SThomas Cort 
1647*2718b568SThomas Cort 	c = x_e_getc();
1648*2718b568SThomas Cort 	xbuf = o_xbuf;
1649*2718b568SThomas Cort 	xend = o_xend;
1650*2718b568SThomas Cort 	xbp = o_xbp;
1651*2718b568SThomas Cort 	xep = o_xep;
1652*2718b568SThomas Cort 	xcp = o_xcp;
1653*2718b568SThomas Cort 	x_redraw(strlen(ksh_version));
1654*2718b568SThomas Cort 
1655*2718b568SThomas Cort 	if (c < 0)
1656*2718b568SThomas Cort 		return KSTD;
1657*2718b568SThomas Cort 	/* This is what at&t ksh seems to do...  Very bizarre */
1658*2718b568SThomas Cort 	if (c != ' ')
1659*2718b568SThomas Cort 		x_e_ungetc(c);
1660*2718b568SThomas Cort 
1661*2718b568SThomas Cort 	return KSTD;
1662*2718b568SThomas Cort }
1663*2718b568SThomas Cort 
1664*2718b568SThomas Cort static int
x_noop(c)1665*2718b568SThomas Cort x_noop(c)
1666*2718b568SThomas Cort 	int c;
1667*2718b568SThomas Cort {
1668*2718b568SThomas Cort 	return KSTD;
1669*2718b568SThomas Cort }
1670*2718b568SThomas Cort 
1671*2718b568SThomas Cort #ifdef SILLY
1672*2718b568SThomas Cort static int
x_game_of_life(c)1673*2718b568SThomas Cort x_game_of_life(c)
1674*2718b568SThomas Cort 	int c;
1675*2718b568SThomas Cort {
1676*2718b568SThomas Cort 	char	newbuf [256+1];
1677*2718b568SThomas Cort 	register char *ip, *op;
1678*2718b568SThomas Cort 	int	i, len;
1679*2718b568SThomas Cort 
1680*2718b568SThomas Cort 	i = xep - xbuf;
1681*2718b568SThomas Cort 	*xep = 0;
1682*2718b568SThomas Cort 	len = x_size_str(xbuf);
1683*2718b568SThomas Cort 	xcp = xbp = xbuf;
1684*2718b568SThomas Cort 	memmove(newbuf+1, xbuf, i);
1685*2718b568SThomas Cort 	newbuf[0] = 'A';
1686*2718b568SThomas Cort 	newbuf[i] = 'A';
1687*2718b568SThomas Cort 	for (ip = newbuf+1, op = xbuf; --i >= 0; ip++, op++)  {
1688*2718b568SThomas Cort 		/*  Empty space  */
1689*2718b568SThomas Cort 		if (*ip < '@' || *ip == '_' || *ip == 0x7F)  {
1690*2718b568SThomas Cort 			/*  Two adults, make whoopee */
1691*2718b568SThomas Cort 			if (ip[-1] < '_' && ip[1] < '_')  {
1692*2718b568SThomas Cort 				/*  Make kid look like parents.  */
1693*2718b568SThomas Cort 				*op = '`' + ((ip[-1] + ip[1])/2)%32;
1694*2718b568SThomas Cort 				if (*op == 0x7F) /* Birth defect */
1695*2718b568SThomas Cort 					*op = '`';
1696*2718b568SThomas Cort 			}
1697*2718b568SThomas Cort 			else
1698*2718b568SThomas Cort 				*op = ' ';	/* nothing happens */
1699*2718b568SThomas Cort 			continue;
1700*2718b568SThomas Cort 		}
1701*2718b568SThomas Cort 		/*  Child */
1702*2718b568SThomas Cort 		if (*ip > '`')  {
1703*2718b568SThomas Cort 			/*  All alone, dies  */
1704*2718b568SThomas Cort 			if (ip[-1] == ' ' && ip[1] == ' ')
1705*2718b568SThomas Cort 				*op = ' ';
1706*2718b568SThomas Cort 			else	/*  Gets older */
1707*2718b568SThomas Cort 				*op = *ip-'`'+'@';
1708*2718b568SThomas Cort 			continue;
1709*2718b568SThomas Cort 		}
1710*2718b568SThomas Cort 		/*  Adult  */
1711*2718b568SThomas Cort 		/*  Overcrowded, dies */
1712*2718b568SThomas Cort 		if (ip[-1] >= '@' && ip[1] >= '@')  {
1713*2718b568SThomas Cort 			*op = ' ';
1714*2718b568SThomas Cort 			continue;
1715*2718b568SThomas Cort 		}
1716*2718b568SThomas Cort 		*op = *ip;
1717*2718b568SThomas Cort 	}
1718*2718b568SThomas Cort 	*op = 0;
1719*2718b568SThomas Cort 	x_redraw(len);
1720*2718b568SThomas Cort 	return KSTD;
1721*2718b568SThomas Cort }
1722*2718b568SThomas Cort #endif
1723*2718b568SThomas Cort 
1724*2718b568SThomas Cort /*
1725*2718b568SThomas Cort  *	File/command name completion routines
1726*2718b568SThomas Cort  */
1727*2718b568SThomas Cort 
1728*2718b568SThomas Cort 
1729*2718b568SThomas Cort static int
x_comp_comm(c)1730*2718b568SThomas Cort x_comp_comm(c)
1731*2718b568SThomas Cort 	int c;
1732*2718b568SThomas Cort {
1733*2718b568SThomas Cort 	do_complete(XCF_COMMAND, CT_COMPLETE);
1734*2718b568SThomas Cort 	return KSTD;
1735*2718b568SThomas Cort }
1736*2718b568SThomas Cort static int
x_list_comm(c)1737*2718b568SThomas Cort x_list_comm(c)
1738*2718b568SThomas Cort 	int c;
1739*2718b568SThomas Cort {
1740*2718b568SThomas Cort 	do_complete(XCF_COMMAND, CT_LIST);
1741*2718b568SThomas Cort 	return KSTD;
1742*2718b568SThomas Cort }
1743*2718b568SThomas Cort static int
x_complete(c)1744*2718b568SThomas Cort x_complete(c)
1745*2718b568SThomas Cort 	int c;
1746*2718b568SThomas Cort {
1747*2718b568SThomas Cort 	do_complete(XCF_COMMAND_FILE, CT_COMPLETE);
1748*2718b568SThomas Cort 	return KSTD;
1749*2718b568SThomas Cort }
1750*2718b568SThomas Cort static int
x_enumerate(c)1751*2718b568SThomas Cort x_enumerate(c)
1752*2718b568SThomas Cort 	int c;
1753*2718b568SThomas Cort {
1754*2718b568SThomas Cort 	do_complete(XCF_COMMAND_FILE, CT_LIST);
1755*2718b568SThomas Cort 	return KSTD;
1756*2718b568SThomas Cort }
1757*2718b568SThomas Cort static int
x_comp_file(c)1758*2718b568SThomas Cort x_comp_file(c)
1759*2718b568SThomas Cort 	int c;
1760*2718b568SThomas Cort {
1761*2718b568SThomas Cort 	do_complete(XCF_FILE, CT_COMPLETE);
1762*2718b568SThomas Cort 	return KSTD;
1763*2718b568SThomas Cort }
1764*2718b568SThomas Cort static int
x_list_file(c)1765*2718b568SThomas Cort x_list_file(c)
1766*2718b568SThomas Cort 	int c;
1767*2718b568SThomas Cort {
1768*2718b568SThomas Cort 	do_complete(XCF_FILE, CT_LIST);
1769*2718b568SThomas Cort 	return KSTD;
1770*2718b568SThomas Cort }
1771*2718b568SThomas Cort static int
x_comp_list(c)1772*2718b568SThomas Cort x_comp_list(c)
1773*2718b568SThomas Cort 	int c;
1774*2718b568SThomas Cort {
1775*2718b568SThomas Cort 	do_complete(XCF_COMMAND_FILE, CT_COMPLIST);
1776*2718b568SThomas Cort 	return KSTD;
1777*2718b568SThomas Cort }
1778*2718b568SThomas Cort static int
x_expand(c)1779*2718b568SThomas Cort x_expand(c)
1780*2718b568SThomas Cort 	int c;
1781*2718b568SThomas Cort {
1782*2718b568SThomas Cort 	char **words;
1783*2718b568SThomas Cort 	int nwords = 0;
1784*2718b568SThomas Cort 	int start, end;
1785*2718b568SThomas Cort 	int is_command;
1786*2718b568SThomas Cort 	int i;
1787*2718b568SThomas Cort 
1788*2718b568SThomas Cort 	nwords = x_cf_glob(XCF_FILE,
1789*2718b568SThomas Cort 		xbuf, xep - xbuf, xcp - xbuf,
1790*2718b568SThomas Cort 		&start, &end, &words, &is_command);
1791*2718b568SThomas Cort 
1792*2718b568SThomas Cort 	if (nwords == 0) {
1793*2718b568SThomas Cort 		x_e_putc(BEL);
1794*2718b568SThomas Cort 		return KSTD;
1795*2718b568SThomas Cort 	}
1796*2718b568SThomas Cort 
1797*2718b568SThomas Cort 	x_goto(xbuf + start);
1798*2718b568SThomas Cort 	x_delete(end - start, FALSE);
1799*2718b568SThomas Cort 	for (i = 0; i < nwords;) {
1800*2718b568SThomas Cort 		if (x_escape(words[i], strlen(words[i]), x_emacs_putbuf) < 0 ||
1801*2718b568SThomas Cort 		    (++i < nwords && x_ins(space) < 0))
1802*2718b568SThomas Cort 		{
1803*2718b568SThomas Cort 			x_e_putc(BEL);
1804*2718b568SThomas Cort 			return KSTD;
1805*2718b568SThomas Cort 		}
1806*2718b568SThomas Cort 	}
1807*2718b568SThomas Cort 	x_adjust();
1808*2718b568SThomas Cort 
1809*2718b568SThomas Cort 	return KSTD;
1810*2718b568SThomas Cort }
1811*2718b568SThomas Cort 
1812*2718b568SThomas Cort /* type == 0 for list, 1 for complete and 2 for complete-list */
1813*2718b568SThomas Cort static void
do_complete(flags,type)1814*2718b568SThomas Cort do_complete(flags, type)
1815*2718b568SThomas Cort 	int flags;	/* XCF_{COMMAND,FILE,COMMAND_FILE} */
1816*2718b568SThomas Cort 	Comp_type type;
1817*2718b568SThomas Cort {
1818*2718b568SThomas Cort 	char **words;
1819*2718b568SThomas Cort 	int nwords;
1820*2718b568SThomas Cort 	int start, end, nlen, olen;
1821*2718b568SThomas Cort 	int is_command;
1822*2718b568SThomas Cort 	int completed = 0;
1823*2718b568SThomas Cort 
1824*2718b568SThomas Cort 	nwords = x_cf_glob(flags, xbuf, xep - xbuf, xcp - xbuf,
1825*2718b568SThomas Cort 			    &start, &end, &words, &is_command);
1826*2718b568SThomas Cort 	/* no match */
1827*2718b568SThomas Cort 	if (nwords == 0) {
1828*2718b568SThomas Cort 		x_e_putc(BEL);
1829*2718b568SThomas Cort 		return;
1830*2718b568SThomas Cort 	}
1831*2718b568SThomas Cort 
1832*2718b568SThomas Cort 	if (type == CT_LIST) {
1833*2718b568SThomas Cort 		x_print_expansions(nwords, words, is_command);
1834*2718b568SThomas Cort 		x_redraw(0);
1835*2718b568SThomas Cort 		x_free_words(nwords, words);
1836*2718b568SThomas Cort 		return;
1837*2718b568SThomas Cort 	}
1838*2718b568SThomas Cort 
1839*2718b568SThomas Cort 	olen = end - start;
1840*2718b568SThomas Cort 	nlen = x_longest_prefix(nwords, words);
1841*2718b568SThomas Cort 	/* complete */
1842*2718b568SThomas Cort 	if (nwords == 1 || nlen > olen) {
1843*2718b568SThomas Cort 		x_goto(xbuf + start);
1844*2718b568SThomas Cort 		x_delete(olen, FALSE);
1845*2718b568SThomas Cort 		x_escape(words[0], nlen, x_emacs_putbuf);
1846*2718b568SThomas Cort 		x_adjust();
1847*2718b568SThomas Cort 		completed = 1;
1848*2718b568SThomas Cort 	}
1849*2718b568SThomas Cort 	/* add space if single non-dir match */
1850*2718b568SThomas Cort 	if ((nwords == 1) && (!ISDIRSEP(words[0][nlen - 1]))) {
1851*2718b568SThomas Cort 		x_ins(space);
1852*2718b568SThomas Cort 		completed = 1;
1853*2718b568SThomas Cort 	}
1854*2718b568SThomas Cort 
1855*2718b568SThomas Cort 	if (type == CT_COMPLIST && !completed) {
1856*2718b568SThomas Cort 		x_print_expansions(nwords, words, is_command);
1857*2718b568SThomas Cort 		completed = 1;
1858*2718b568SThomas Cort 	}
1859*2718b568SThomas Cort 
1860*2718b568SThomas Cort 	if (completed)
1861*2718b568SThomas Cort 		x_redraw(0);
1862*2718b568SThomas Cort 
1863*2718b568SThomas Cort 	x_free_words(nwords, words);
1864*2718b568SThomas Cort }
1865*2718b568SThomas Cort 
1866*2718b568SThomas Cort /* NAME:
1867*2718b568SThomas Cort  *      x_adjust - redraw the line adjusting starting point etc.
1868*2718b568SThomas Cort  *
1869*2718b568SThomas Cort  * DESCRIPTION:
1870*2718b568SThomas Cort  *      This function is called when we have exceeded the bounds
1871*2718b568SThomas Cort  *      of the edit window.  It increments x_adj_done so that
1872*2718b568SThomas Cort  *      functions like x_ins and x_delete know that we have been
1873*2718b568SThomas Cort  *      called and can skip the x_bs() stuff which has already
1874*2718b568SThomas Cort  *      been done by x_redraw.
1875*2718b568SThomas Cort  *
1876*2718b568SThomas Cort  * RETURN VALUE:
1877*2718b568SThomas Cort  *      None
1878*2718b568SThomas Cort  */
1879*2718b568SThomas Cort 
1880*2718b568SThomas Cort static void
x_adjust()1881*2718b568SThomas Cort x_adjust()
1882*2718b568SThomas Cort {
1883*2718b568SThomas Cort   x_adj_done++;			/* flag the fact that we were called. */
1884*2718b568SThomas Cort   /*
1885*2718b568SThomas Cort    * we had a problem if the prompt length > xx_cols / 2
1886*2718b568SThomas Cort    */
1887*2718b568SThomas Cort   if ((xbp = xcp - (x_displen / 2)) < xbuf)
1888*2718b568SThomas Cort     xbp = xbuf;
1889*2718b568SThomas Cort   xlp_valid = FALSE;
1890*2718b568SThomas Cort   x_redraw(xx_cols);
1891*2718b568SThomas Cort   x_flush();
1892*2718b568SThomas Cort }
1893*2718b568SThomas Cort 
1894*2718b568SThomas Cort static int unget_char = -1;
1895*2718b568SThomas Cort 
1896*2718b568SThomas Cort static void
x_e_ungetc(c)1897*2718b568SThomas Cort x_e_ungetc(c)
1898*2718b568SThomas Cort 	int c;
1899*2718b568SThomas Cort {
1900*2718b568SThomas Cort 	unget_char = c;
1901*2718b568SThomas Cort }
1902*2718b568SThomas Cort 
1903*2718b568SThomas Cort static int
x_e_getc()1904*2718b568SThomas Cort x_e_getc()
1905*2718b568SThomas Cort {
1906*2718b568SThomas Cort 	int c;
1907*2718b568SThomas Cort 
1908*2718b568SThomas Cort 	if (unget_char >= 0) {
1909*2718b568SThomas Cort 		c = unget_char;
1910*2718b568SThomas Cort 		unget_char = -1;
1911*2718b568SThomas Cort 	} else {
1912*2718b568SThomas Cort 		if (macroptr)  {
1913*2718b568SThomas Cort 			c = (unsigned char) *macroptr++;
1914*2718b568SThomas Cort 			if (!*macroptr)
1915*2718b568SThomas Cort 				macroptr = (char *) 0;
1916*2718b568SThomas Cort 		} else
1917*2718b568SThomas Cort 			c = x_getc();
1918*2718b568SThomas Cort 	}
1919*2718b568SThomas Cort 
1920*2718b568SThomas Cort 	return c <= CHARMASK ? c : (c & CHARMASK);
1921*2718b568SThomas Cort }
1922*2718b568SThomas Cort 
1923*2718b568SThomas Cort static void
x_e_putc(c)1924*2718b568SThomas Cort x_e_putc(c)
1925*2718b568SThomas Cort 	int c;
1926*2718b568SThomas Cort {
1927*2718b568SThomas Cort   if (c == '\r' || c == '\n')
1928*2718b568SThomas Cort     x_col = 0;
1929*2718b568SThomas Cort   if (x_col < xx_cols)
1930*2718b568SThomas Cort   {
1931*2718b568SThomas Cort     x_putc(c);
1932*2718b568SThomas Cort     switch(c)
1933*2718b568SThomas Cort     {
1934*2718b568SThomas Cort     case BEL:
1935*2718b568SThomas Cort       break;
1936*2718b568SThomas Cort     case '\r':
1937*2718b568SThomas Cort     case '\n':
1938*2718b568SThomas Cort     break;
1939*2718b568SThomas Cort     case '\b':
1940*2718b568SThomas Cort       x_col--;
1941*2718b568SThomas Cort       break;
1942*2718b568SThomas Cort     default:
1943*2718b568SThomas Cort       x_col++;
1944*2718b568SThomas Cort       break;
1945*2718b568SThomas Cort     }
1946*2718b568SThomas Cort   }
1947*2718b568SThomas Cort   if (x_adj_ok && (x_col < 0 || x_col >= (xx_cols - 2)))
1948*2718b568SThomas Cort   {
1949*2718b568SThomas Cort     x_adjust();
1950*2718b568SThomas Cort   }
1951*2718b568SThomas Cort }
1952*2718b568SThomas Cort 
1953*2718b568SThomas Cort #ifdef DEBUG
1954*2718b568SThomas Cort static int
x_debug_info(c)1955*2718b568SThomas Cort x_debug_info(c)
1956*2718b568SThomas Cort 	int c;
1957*2718b568SThomas Cort {
1958*2718b568SThomas Cort 	x_flush();
1959*2718b568SThomas Cort 	shellf("\nksh debug:\n");
1960*2718b568SThomas Cort 	shellf("\tx_col == %d,\t\tx_cols == %d,\tx_displen == %d\n",
1961*2718b568SThomas Cort 		 x_col, xx_cols, x_displen);
1962*2718b568SThomas Cort 	shellf("\txcp == 0x%lx,\txep == 0x%lx\n", (long) xcp, (long) xep);
1963*2718b568SThomas Cort 	shellf("\txbp == 0x%lx,\txbuf == 0x%lx\n", (long) xbp, (long) xbuf);
1964*2718b568SThomas Cort 	shellf("\txlp == 0x%lx\n", (long) xlp);
1965*2718b568SThomas Cort 	shellf("\txlp == 0x%lx\n", (long) x_lastcp());
1966*2718b568SThomas Cort 	shellf(newline);
1967*2718b568SThomas Cort 	x_redraw(-1);
1968*2718b568SThomas Cort 	return 0;
1969*2718b568SThomas Cort }
1970*2718b568SThomas Cort #endif
1971*2718b568SThomas Cort 
1972*2718b568SThomas Cort static void
x_e_puts(s)1973*2718b568SThomas Cort x_e_puts(s)
1974*2718b568SThomas Cort 	const char *s;
1975*2718b568SThomas Cort {
1976*2718b568SThomas Cort   register int	adj = x_adj_done;
1977*2718b568SThomas Cort 
1978*2718b568SThomas Cort   while (*s && adj == x_adj_done)
1979*2718b568SThomas Cort     x_e_putc(*s++);
1980*2718b568SThomas Cort }
1981*2718b568SThomas Cort 
1982*2718b568SThomas Cort /* NAME:
1983*2718b568SThomas Cort  *      x_set_arg - set an arg value for next function
1984*2718b568SThomas Cort  *
1985*2718b568SThomas Cort  * DESCRIPTION:
1986*2718b568SThomas Cort  *      This is a simple implementation of M-[0-9].
1987*2718b568SThomas Cort  *
1988*2718b568SThomas Cort  * RETURN VALUE:
1989*2718b568SThomas Cort  *      KSTD
1990*2718b568SThomas Cort  */
1991*2718b568SThomas Cort 
1992*2718b568SThomas Cort static int
x_set_arg(c)1993*2718b568SThomas Cort x_set_arg(c)
1994*2718b568SThomas Cort 	int c;
1995*2718b568SThomas Cort {
1996*2718b568SThomas Cort 	int n = 0;
1997*2718b568SThomas Cort 	int first = 1;
1998*2718b568SThomas Cort 
1999*2718b568SThomas Cort 	c &= CHARMASK;	/* strip command prefix */
2000*2718b568SThomas Cort 	for (; c >= 0 && isdigit(c); c = x_e_getc(), first = 0)
2001*2718b568SThomas Cort 		n = n * 10 + (c - '0');
2002*2718b568SThomas Cort 	if (c < 0 || first) {
2003*2718b568SThomas Cort 		x_e_putc(BEL);
2004*2718b568SThomas Cort 		x_arg = 1;
2005*2718b568SThomas Cort 		x_arg_defaulted = 1;
2006*2718b568SThomas Cort 	} else {
2007*2718b568SThomas Cort 		x_e_ungetc(c);
2008*2718b568SThomas Cort 		x_arg = n;
2009*2718b568SThomas Cort 		x_arg_defaulted = 0;
2010*2718b568SThomas Cort 	}
2011*2718b568SThomas Cort 	return KSTD;
2012*2718b568SThomas Cort }
2013*2718b568SThomas Cort 
2014*2718b568SThomas Cort 
2015*2718b568SThomas Cort /* Comment or uncomment the current line. */
2016*2718b568SThomas Cort static int
x_comment(c)2017*2718b568SThomas Cort x_comment(c)
2018*2718b568SThomas Cort 	int c;
2019*2718b568SThomas Cort {
2020*2718b568SThomas Cort 	int oldsize = x_size_str(xbuf);
2021*2718b568SThomas Cort 	int len = xep - xbuf;
2022*2718b568SThomas Cort 	int ret = x_do_comment(xbuf, xend - xbuf, &len);
2023*2718b568SThomas Cort 
2024*2718b568SThomas Cort 	if (ret < 0)
2025*2718b568SThomas Cort 		x_e_putc(BEL);
2026*2718b568SThomas Cort 	else {
2027*2718b568SThomas Cort 		xep = xbuf + len;
2028*2718b568SThomas Cort 		*xep = '\0';
2029*2718b568SThomas Cort 		xcp = xbp = xbuf;
2030*2718b568SThomas Cort 		x_redraw(oldsize);
2031*2718b568SThomas Cort 		if (ret > 0)
2032*2718b568SThomas Cort 			return x_newline('\n');
2033*2718b568SThomas Cort 	}
2034*2718b568SThomas Cort 	return KSTD;
2035*2718b568SThomas Cort }
2036*2718b568SThomas Cort 
2037*2718b568SThomas Cort 
2038*2718b568SThomas Cort /* NAME:
2039*2718b568SThomas Cort  *      x_prev_histword - recover word from prev command
2040*2718b568SThomas Cort  *
2041*2718b568SThomas Cort  * DESCRIPTION:
2042*2718b568SThomas Cort  *      This function recovers the last word from the previous
2043*2718b568SThomas Cort  *      command and inserts it into the current edit line.  If a
2044*2718b568SThomas Cort  *      numeric arg is supplied then the n'th word from the
2045*2718b568SThomas Cort  *      start of the previous command is used.
2046*2718b568SThomas Cort  *
2047*2718b568SThomas Cort  *      Bound to M-.
2048*2718b568SThomas Cort  *
2049*2718b568SThomas Cort  * RETURN VALUE:
2050*2718b568SThomas Cort  *      KSTD
2051*2718b568SThomas Cort  */
2052*2718b568SThomas Cort 
2053*2718b568SThomas Cort static int
x_prev_histword(c)2054*2718b568SThomas Cort x_prev_histword(c)
2055*2718b568SThomas Cort 	int c;
2056*2718b568SThomas Cort {
2057*2718b568SThomas Cort   register char *rcp;
2058*2718b568SThomas Cort   char *cp;
2059*2718b568SThomas Cort 
2060*2718b568SThomas Cort   cp = *histptr;
2061*2718b568SThomas Cort   if (!cp)
2062*2718b568SThomas Cort     x_e_putc(BEL);
2063*2718b568SThomas Cort   else if (x_arg_defaulted) {
2064*2718b568SThomas Cort     rcp = &cp[strlen(cp) - 1];
2065*2718b568SThomas Cort     /*
2066*2718b568SThomas Cort      * ignore white-space after the last word
2067*2718b568SThomas Cort      */
2068*2718b568SThomas Cort     while (rcp > cp && is_cfs(*rcp))
2069*2718b568SThomas Cort       rcp--;
2070*2718b568SThomas Cort     while (rcp > cp && !is_cfs(*rcp))
2071*2718b568SThomas Cort       rcp--;
2072*2718b568SThomas Cort     if (is_cfs(*rcp))
2073*2718b568SThomas Cort       rcp++;
2074*2718b568SThomas Cort     x_ins(rcp);
2075*2718b568SThomas Cort   } else {
2076*2718b568SThomas Cort     int i;
2077*2718b568SThomas Cort 
2078*2718b568SThomas Cort     rcp = cp;
2079*2718b568SThomas Cort     /*
2080*2718b568SThomas Cort      * ignore white-space at start of line
2081*2718b568SThomas Cort      */
2082*2718b568SThomas Cort     while (*rcp && is_cfs(*rcp))
2083*2718b568SThomas Cort       rcp++;
2084*2718b568SThomas Cort     while (x_arg-- > 1)
2085*2718b568SThomas Cort     {
2086*2718b568SThomas Cort       while (*rcp && !is_cfs(*rcp))
2087*2718b568SThomas Cort 	rcp++;
2088*2718b568SThomas Cort       while (*rcp && is_cfs(*rcp))
2089*2718b568SThomas Cort 	rcp++;
2090*2718b568SThomas Cort     }
2091*2718b568SThomas Cort     cp = rcp;
2092*2718b568SThomas Cort     while (*rcp && !is_cfs(*rcp))
2093*2718b568SThomas Cort       rcp++;
2094*2718b568SThomas Cort     i = *rcp;
2095*2718b568SThomas Cort     *rcp = '\0';
2096*2718b568SThomas Cort     x_ins(cp);
2097*2718b568SThomas Cort     *rcp = i;
2098*2718b568SThomas Cort   }
2099*2718b568SThomas Cort   return KSTD;
2100*2718b568SThomas Cort }
2101*2718b568SThomas Cort 
2102*2718b568SThomas Cort /* Uppercase N(1) words */
2103*2718b568SThomas Cort static int
x_fold_upper(c)2104*2718b568SThomas Cort x_fold_upper(c)
2105*2718b568SThomas Cort   int c;
2106*2718b568SThomas Cort {
2107*2718b568SThomas Cort 	return x_fold_case('U');
2108*2718b568SThomas Cort }
2109*2718b568SThomas Cort 
2110*2718b568SThomas Cort /* Lowercase N(1) words */
2111*2718b568SThomas Cort static int
x_fold_lower(c)2112*2718b568SThomas Cort x_fold_lower(c)
2113*2718b568SThomas Cort   int c;
2114*2718b568SThomas Cort {
2115*2718b568SThomas Cort 	return x_fold_case('L');
2116*2718b568SThomas Cort }
2117*2718b568SThomas Cort 
2118*2718b568SThomas Cort /* Lowercase N(1) words */
2119*2718b568SThomas Cort static int
x_fold_capitalize(c)2120*2718b568SThomas Cort x_fold_capitalize(c)
2121*2718b568SThomas Cort   int c;
2122*2718b568SThomas Cort {
2123*2718b568SThomas Cort 	return x_fold_case('C');
2124*2718b568SThomas Cort }
2125*2718b568SThomas Cort 
2126*2718b568SThomas Cort /* NAME:
2127*2718b568SThomas Cort  *      x_fold_case - convert word to UPPER/lower/Capital case
2128*2718b568SThomas Cort  *
2129*2718b568SThomas Cort  * DESCRIPTION:
2130*2718b568SThomas Cort  *      This function is used to implement M-U,M-u,M-L,M-l,M-C and M-c
2131*2718b568SThomas Cort  *      to UPPER case, lower case or Capitalize words.
2132*2718b568SThomas Cort  *
2133*2718b568SThomas Cort  * RETURN VALUE:
2134*2718b568SThomas Cort  *      None
2135*2718b568SThomas Cort  */
2136*2718b568SThomas Cort 
2137*2718b568SThomas Cort static int
x_fold_case(c)2138*2718b568SThomas Cort x_fold_case(c)
2139*2718b568SThomas Cort 	int c;
2140*2718b568SThomas Cort {
2141*2718b568SThomas Cort 	char *cp = xcp;
2142*2718b568SThomas Cort 
2143*2718b568SThomas Cort 	if (cp == xep) {
2144*2718b568SThomas Cort 		x_e_putc(BEL);
2145*2718b568SThomas Cort 		return KSTD;
2146*2718b568SThomas Cort 	}
2147*2718b568SThomas Cort 	while (x_arg--) {
2148*2718b568SThomas Cort 		/*
2149*2718b568SThomas Cort 		 * first skip over any white-space
2150*2718b568SThomas Cort 		 */
2151*2718b568SThomas Cort 		while (cp != xep && is_mfs(*cp))
2152*2718b568SThomas Cort 			cp++;
2153*2718b568SThomas Cort 		/*
2154*2718b568SThomas Cort 		 * do the first char on its own since it may be
2155*2718b568SThomas Cort 		 * a different action than for the rest.
2156*2718b568SThomas Cort 		 */
2157*2718b568SThomas Cort 		if (cp != xep) {
2158*2718b568SThomas Cort 			if (c == 'L') {		/* lowercase */
2159*2718b568SThomas Cort 				if (isupper((unsigned char)*cp))
2160*2718b568SThomas Cort 					*cp = tolower((unsigned char)*cp);
2161*2718b568SThomas Cort 			} else {		/* uppercase, capitialize */
2162*2718b568SThomas Cort 				if (islower((unsigned char)*cp))
2163*2718b568SThomas Cort 					*cp = toupper((unsigned char)*cp);
2164*2718b568SThomas Cort 			}
2165*2718b568SThomas Cort 			cp++;
2166*2718b568SThomas Cort 		}
2167*2718b568SThomas Cort 		/*
2168*2718b568SThomas Cort 		 * now for the rest of the word
2169*2718b568SThomas Cort 		 */
2170*2718b568SThomas Cort 		while (cp != xep && !is_mfs((unsigned char)*cp)) {
2171*2718b568SThomas Cort 			if (c == 'U') {		/* uppercase */
2172*2718b568SThomas Cort 				if (islower((unsigned char)*cp))
2173*2718b568SThomas Cort 					*cp = toupper((unsigned char)*cp);
2174*2718b568SThomas Cort 			} else {		/* lowercase, capitialize */
2175*2718b568SThomas Cort 				if (isupper((unsigned char)*cp))
2176*2718b568SThomas Cort 					*cp = tolower((unsigned char)*cp);
2177*2718b568SThomas Cort 			}
2178*2718b568SThomas Cort 			cp++;
2179*2718b568SThomas Cort 		}
2180*2718b568SThomas Cort 	}
2181*2718b568SThomas Cort 	x_goto(cp);
2182*2718b568SThomas Cort 	return KSTD;
2183*2718b568SThomas Cort }
2184*2718b568SThomas Cort 
2185*2718b568SThomas Cort /* NAME:
2186*2718b568SThomas Cort  *      x_lastcp - last visible char
2187*2718b568SThomas Cort  *
2188*2718b568SThomas Cort  * SYNOPSIS:
2189*2718b568SThomas Cort  *      x_lastcp()
2190*2718b568SThomas Cort  *
2191*2718b568SThomas Cort  * DESCRIPTION:
2192*2718b568SThomas Cort  *      This function returns a pointer to that  char in the
2193*2718b568SThomas Cort  *      edit buffer that will be the last displayed on the
2194*2718b568SThomas Cort  *      screen.  The sequence:
2195*2718b568SThomas Cort  *
2196*2718b568SThomas Cort  *      for (cp = x_lastcp(); cp > xcp; cp)
2197*2718b568SThomas Cort  *        x_bs(*--cp);
2198*2718b568SThomas Cort  *
2199*2718b568SThomas Cort  *      Will position the cursor correctly on the screen.
2200*2718b568SThomas Cort  *
2201*2718b568SThomas Cort  * RETURN VALUE:
2202*2718b568SThomas Cort  *      cp or NULL
2203*2718b568SThomas Cort  */
2204*2718b568SThomas Cort 
2205*2718b568SThomas Cort static char *
x_lastcp()2206*2718b568SThomas Cort x_lastcp()
2207*2718b568SThomas Cort {
2208*2718b568SThomas Cort   register char *rcp;
2209*2718b568SThomas Cort   register int i;
2210*2718b568SThomas Cort 
2211*2718b568SThomas Cort   if (!xlp_valid)
2212*2718b568SThomas Cort   {
2213*2718b568SThomas Cort     for (i = 0, rcp = xbp; rcp < xep && i < x_displen; rcp++)
2214*2718b568SThomas Cort       i += x_size(*rcp);
2215*2718b568SThomas Cort     xlp = rcp;
2216*2718b568SThomas Cort   }
2217*2718b568SThomas Cort   xlp_valid = TRUE;
2218*2718b568SThomas Cort   return (xlp);
2219*2718b568SThomas Cort }
2220*2718b568SThomas Cort 
2221*2718b568SThomas Cort #endif /* EDIT */
2222