xref: /freebsd/contrib/less/command.c (revision 2235c7feac959bcc9ddfd6a2bc6be32102b1f84c)
1a8f92a7cSPaul Saab /* $FreeBSD$ */
2a5f0fb15SPaul Saab /*
3*2235c7feSXin LI  * Copyright (C) 1984-2021  Mark Nudelman
4a5f0fb15SPaul Saab  *
5a5f0fb15SPaul Saab  * You may distribute under the terms of either the GNU General Public
6a5f0fb15SPaul Saab  * License or the Less License, as specified in the README file.
7a5f0fb15SPaul Saab  *
896e55cc7SXin LI  * For more information, see the README file.
9a5f0fb15SPaul Saab  */
10a5f0fb15SPaul Saab 
11a5f0fb15SPaul Saab 
12a5f0fb15SPaul Saab /*
13a5f0fb15SPaul Saab  * User-level command processor.
14a5f0fb15SPaul Saab  */
15a5f0fb15SPaul Saab 
16a5f0fb15SPaul Saab #include "less.h"
178fd4165cSPaul Saab #if MSDOS_COMPILER==WIN32C
188fd4165cSPaul Saab #include <windows.h>
198fd4165cSPaul Saab #endif
20a5f0fb15SPaul Saab #include "position.h"
21a5f0fb15SPaul Saab #include "option.h"
22a5f0fb15SPaul Saab #include "cmd.h"
23a5f0fb15SPaul Saab 
2489dd99dcSXin LI extern int erase_char, erase2_char, kill_char;
25a5f0fb15SPaul Saab extern int sigs;
26a5f0fb15SPaul Saab extern int quit_if_one_screen;
27a5f0fb15SPaul Saab extern int squished;
28a5f0fb15SPaul Saab extern int sc_width;
29a5f0fb15SPaul Saab extern int sc_height;
30b2ea2440SXin LI extern char *kent;
31a5f0fb15SPaul Saab extern int swindow;
32a5f0fb15SPaul Saab extern int jump_sline;
33a5f0fb15SPaul Saab extern int quitting;
34a5f0fb15SPaul Saab extern int wscroll;
35a5f0fb15SPaul Saab extern int top_scroll;
36a5f0fb15SPaul Saab extern int ignore_eoi;
37a5f0fb15SPaul Saab extern int secure;
38a5f0fb15SPaul Saab extern int hshift;
39a15691bfSXin LI extern int bs_mode;
40a5f0fb15SPaul Saab extern int show_attn;
41720c436cSXin LI extern int less_is_more;
42b2ea2440SXin LI extern int status_col;
4396e55cc7SXin LI extern POSITION highest_hilite;
44b2ea2440SXin LI extern POSITION start_attnpos;
45b2ea2440SXin LI extern POSITION end_attnpos;
46a5f0fb15SPaul Saab extern char *every_first_cmd;
47a5f0fb15SPaul Saab extern char version[];
48a5f0fb15SPaul Saab extern struct scrpos initial_scrpos;
49a5f0fb15SPaul Saab extern IFILE curr_ifile;
50f6b74a7dSXin LI extern void *ml_search;
51f6b74a7dSXin LI extern void *ml_examine;
52b7780dbeSXin LI extern int wheel_lines;
53a5f0fb15SPaul Saab #if SHELL_ESCAPE || PIPEC
54f6b74a7dSXin LI extern void *ml_shell;
55a5f0fb15SPaul Saab #endif
56a5f0fb15SPaul Saab #if EDITOR
57a5f0fb15SPaul Saab extern char *editor;
58a5f0fb15SPaul Saab extern char *editproto;
59a5f0fb15SPaul Saab #endif
60a5f0fb15SPaul Saab extern int screen_trashed;      /* The screen has been overwritten */
6115596da4SPaul Saab extern int shift_count;
62720c436cSXin LI extern int oldbot;
63720c436cSXin LI extern int forw_prompt;
64*2235c7feSXin LI extern int incr_search;
65b7780dbeSXin LI #if MSDOS_COMPILER==WIN32C
66b7780dbeSXin LI extern int utf_mode;
67b7780dbeSXin LI #endif
68a5f0fb15SPaul Saab 
69a5f0fb15SPaul Saab #if SHELL_ESCAPE
70a5f0fb15SPaul Saab static char *shellcmd = NULL;   /* For holding last shell command for "!!" */
71a5f0fb15SPaul Saab #endif
72a5f0fb15SPaul Saab static int mca;                 /* The multicharacter command (action) */
73a5f0fb15SPaul Saab static int search_type;         /* The previous type of search */
741ede1615STim J. Robbins static LINENUM number;          /* The number typed by the user */
75720c436cSXin LI static long fraction;           /* The fractional part of the number */
7633096f16SXin LI static struct loption *curropt;
7733096f16SXin LI static int opt_lower;
78a5f0fb15SPaul Saab static int optflag;
79a5f0fb15SPaul Saab static int optgetname;
80a5f0fb15SPaul Saab static POSITION bottompos;
8189dd99dcSXin LI static int save_hshift;
82a15691bfSXin LI static int save_bs_mode;
83a5f0fb15SPaul Saab #if PIPEC
84a5f0fb15SPaul Saab static char pipec;
85a5f0fb15SPaul Saab #endif
86a5f0fb15SPaul Saab 
87b2ea2440SXin LI /* Stack of ungotten chars (via ungetcc) */
8833096f16SXin LI struct ungot {
8933096f16SXin LI 	struct ungot *ug_next;
90b2ea2440SXin LI 	LWCHAR ug_char;
9133096f16SXin LI };
9233096f16SXin LI static struct ungot* ungot = NULL;
9333096f16SXin LI 
946f26c71dSXin LI static void multi_search LESSPARAMS((char *pattern, int n, int silent));
95a5f0fb15SPaul Saab 
96a5f0fb15SPaul Saab /*
97720c436cSXin LI  * Move the cursor to start of prompt line before executing a command.
98a5f0fb15SPaul Saab  * This looks nicer if the command takes a long time before
99a5f0fb15SPaul Saab  * updating the screen.
100a5f0fb15SPaul Saab  */
101a5f0fb15SPaul Saab 	static void
102b7780dbeSXin LI cmd_exec(VOID_PARAM)
103a5f0fb15SPaul Saab {
104a5f0fb15SPaul Saab 	clear_attn();
105aa22b8b6SXin LI 	clear_bot();
106a5f0fb15SPaul Saab 	flush();
107a5f0fb15SPaul Saab }
108a5f0fb15SPaul Saab 
109a5f0fb15SPaul Saab /*
110b7780dbeSXin LI  * Indicate we are reading a multi-character command.
111b7780dbeSXin LI  */
112b7780dbeSXin LI 	static void
113b7780dbeSXin LI set_mca(action)
114b7780dbeSXin LI 	int action;
115b7780dbeSXin LI {
116b7780dbeSXin LI 	mca = action;
117b7780dbeSXin LI 	clear_bot();
118b7780dbeSXin LI 	clear_cmd();
119b7780dbeSXin LI }
120b7780dbeSXin LI 
121b7780dbeSXin LI /*
122b7780dbeSXin LI  * Indicate we are not reading a multi-character command.
123b7780dbeSXin LI  */
124b7780dbeSXin LI 	static void
125b7780dbeSXin LI clear_mca(VOID_PARAM)
126b7780dbeSXin LI {
127b7780dbeSXin LI 	if (mca == 0)
128b7780dbeSXin LI 		return;
129b7780dbeSXin LI 	mca = 0;
130b7780dbeSXin LI }
131b7780dbeSXin LI 
132b7780dbeSXin LI /*
133a5f0fb15SPaul Saab  * Set up the display to start a new multi-character command.
134a5f0fb15SPaul Saab  */
135a5f0fb15SPaul Saab 	static void
136f6b74a7dSXin LI start_mca(action, prompt, mlist, cmdflags)
137f6b74a7dSXin LI 	int action;
138f6b74a7dSXin LI 	constant char *prompt;
139f6b74a7dSXin LI 	void *mlist;
140f6b74a7dSXin LI 	int cmdflags;
141a5f0fb15SPaul Saab {
142b7780dbeSXin LI 	set_mca(action);
143a5f0fb15SPaul Saab 	cmd_putstr(prompt);
144a5f0fb15SPaul Saab 	set_mlist(mlist, cmdflags);
145a5f0fb15SPaul Saab }
146a5f0fb15SPaul Saab 
147a5f0fb15SPaul Saab 	public int
148b7780dbeSXin LI in_mca(VOID_PARAM)
149a5f0fb15SPaul Saab {
150a5f0fb15SPaul Saab 	return (mca != 0 && mca != A_PREFIX);
151a5f0fb15SPaul Saab }
152a5f0fb15SPaul Saab 
153a5f0fb15SPaul Saab /*
154a5f0fb15SPaul Saab  * Set up the display to start a new search command.
155a5f0fb15SPaul Saab  */
156a5f0fb15SPaul Saab 	static void
157b7780dbeSXin LI mca_search(VOID_PARAM)
158a5f0fb15SPaul Saab {
1597374caaaSXin LI #if HILITE_SEARCH
1607374caaaSXin LI 	if (search_type & SRCH_FILTER)
161b7780dbeSXin LI 		set_mca(A_FILTER);
1627374caaaSXin LI 	else
1637374caaaSXin LI #endif
164a5f0fb15SPaul Saab 	if (search_type & SRCH_FORW)
165b7780dbeSXin LI 		set_mca(A_F_SEARCH);
166a5f0fb15SPaul Saab 	else
167b7780dbeSXin LI 		set_mca(A_B_SEARCH);
168a5f0fb15SPaul Saab 
169a5f0fb15SPaul Saab 	if (search_type & SRCH_NO_MATCH)
170a5f0fb15SPaul Saab 		cmd_putstr("Non-match ");
171a5f0fb15SPaul Saab 	if (search_type & SRCH_FIRST_FILE)
172a5f0fb15SPaul Saab 		cmd_putstr("First-file ");
173a5f0fb15SPaul Saab 	if (search_type & SRCH_PAST_EOF)
174a5f0fb15SPaul Saab 		cmd_putstr("EOF-ignore ");
175a5f0fb15SPaul Saab 	if (search_type & SRCH_NO_MOVE)
176a5f0fb15SPaul Saab 		cmd_putstr("Keep-pos ");
177a5f0fb15SPaul Saab 	if (search_type & SRCH_NO_REGEX)
178a5f0fb15SPaul Saab 		cmd_putstr("Regex-off ");
179*2235c7feSXin LI 	if (search_type & SRCH_WRAP)
180*2235c7feSXin LI 		cmd_putstr("Wrap ");
181a5f0fb15SPaul Saab 
1827374caaaSXin LI #if HILITE_SEARCH
1837374caaaSXin LI 	if (search_type & SRCH_FILTER)
1847374caaaSXin LI 		cmd_putstr("&/");
1857374caaaSXin LI 	else
1867374caaaSXin LI #endif
187a5f0fb15SPaul Saab 	if (search_type & SRCH_FORW)
188a5f0fb15SPaul Saab 		cmd_putstr("/");
189a5f0fb15SPaul Saab 	else
190a5f0fb15SPaul Saab 		cmd_putstr("?");
191a15691bfSXin LI 	forw_prompt = 0;
192a5f0fb15SPaul Saab 	set_mlist(ml_search, 0);
193a5f0fb15SPaul Saab }
194a5f0fb15SPaul Saab 
195a5f0fb15SPaul Saab /*
196a5f0fb15SPaul Saab  * Set up the display to start a new toggle-option command.
197a5f0fb15SPaul Saab  */
198a5f0fb15SPaul Saab 	static void
199b7780dbeSXin LI mca_opt_toggle(VOID_PARAM)
200a5f0fb15SPaul Saab {
201a5f0fb15SPaul Saab 	int no_prompt;
202a5f0fb15SPaul Saab 	int flag;
203a5f0fb15SPaul Saab 	char *dash;
204a5f0fb15SPaul Saab 
205a5f0fb15SPaul Saab 	no_prompt = (optflag & OPT_NO_PROMPT);
206a5f0fb15SPaul Saab 	flag = (optflag & ~OPT_NO_PROMPT);
207a5f0fb15SPaul Saab 	dash = (flag == OPT_NO_TOGGLE) ? "_" : "-";
208a5f0fb15SPaul Saab 
209b7780dbeSXin LI 	set_mca(A_OPT_TOGGLE);
210a5f0fb15SPaul Saab 	cmd_putstr(dash);
211a5f0fb15SPaul Saab 	if (optgetname)
212a5f0fb15SPaul Saab 		cmd_putstr(dash);
213a5f0fb15SPaul Saab 	if (no_prompt)
214a5f0fb15SPaul Saab 		cmd_putstr("(P)");
215a5f0fb15SPaul Saab 	switch (flag)
216a5f0fb15SPaul Saab 	{
217a5f0fb15SPaul Saab 	case OPT_UNSET:
218a5f0fb15SPaul Saab 		cmd_putstr("+");
219a5f0fb15SPaul Saab 		break;
220a5f0fb15SPaul Saab 	case OPT_SET:
221a5f0fb15SPaul Saab 		cmd_putstr("!");
222a5f0fb15SPaul Saab 		break;
223a5f0fb15SPaul Saab 	}
224a15691bfSXin LI 	forw_prompt = 0;
225a5f0fb15SPaul Saab 	set_mlist(NULL, 0);
226a5f0fb15SPaul Saab }
227a5f0fb15SPaul Saab 
228a5f0fb15SPaul Saab /*
229a5f0fb15SPaul Saab  * Execute a multicharacter command.
230a5f0fb15SPaul Saab  */
231a5f0fb15SPaul Saab 	static void
232b7780dbeSXin LI exec_mca(VOID_PARAM)
233a5f0fb15SPaul Saab {
2341ea31627SRobert Watson 	char *cbuf;
235a5f0fb15SPaul Saab 
236a5f0fb15SPaul Saab 	cmd_exec();
237a5f0fb15SPaul Saab 	cbuf = get_cmdbuf();
238a5f0fb15SPaul Saab 
239a5f0fb15SPaul Saab 	switch (mca)
240a5f0fb15SPaul Saab 	{
241a5f0fb15SPaul Saab 	case A_F_SEARCH:
242a5f0fb15SPaul Saab 	case A_B_SEARCH:
243a15691bfSXin LI 		multi_search(cbuf, (int) number, 0);
244a5f0fb15SPaul Saab 		break;
2457374caaaSXin LI #if HILITE_SEARCH
2467374caaaSXin LI 	case A_FILTER:
2477374caaaSXin LI 		search_type ^= SRCH_NO_MATCH;
2487374caaaSXin LI 		set_filter_pattern(cbuf, search_type);
2497374caaaSXin LI 		break;
2507374caaaSXin LI #endif
251a5f0fb15SPaul Saab 	case A_FIRSTCMD:
252a5f0fb15SPaul Saab 		/*
253a5f0fb15SPaul Saab 		 * Skip leading spaces or + signs in the string.
254a5f0fb15SPaul Saab 		 */
255a5f0fb15SPaul Saab 		while (*cbuf == '+' || *cbuf == ' ')
256a5f0fb15SPaul Saab 			cbuf++;
257a5f0fb15SPaul Saab 		if (every_first_cmd != NULL)
258a5f0fb15SPaul Saab 			free(every_first_cmd);
259a5f0fb15SPaul Saab 		if (*cbuf == '\0')
260a5f0fb15SPaul Saab 			every_first_cmd = NULL;
261a5f0fb15SPaul Saab 		else
262a5f0fb15SPaul Saab 			every_first_cmd = save(cbuf);
263a5f0fb15SPaul Saab 		break;
264a5f0fb15SPaul Saab 	case A_OPT_TOGGLE:
26533096f16SXin LI 		toggle_option(curropt, opt_lower, cbuf, optflag);
26633096f16SXin LI 		curropt = NULL;
267a5f0fb15SPaul Saab 		break;
268a5f0fb15SPaul Saab 	case A_F_BRACKET:
2691ede1615STim J. Robbins 		match_brac(cbuf[0], cbuf[1], 1, (int) number);
270a5f0fb15SPaul Saab 		break;
271a5f0fb15SPaul Saab 	case A_B_BRACKET:
2721ede1615STim J. Robbins 		match_brac(cbuf[1], cbuf[0], 0, (int) number);
273a5f0fb15SPaul Saab 		break;
274a5f0fb15SPaul Saab #if EXAMINE
275a5f0fb15SPaul Saab 	case A_EXAMINE:
276a5f0fb15SPaul Saab 		if (secure)
277a5f0fb15SPaul Saab 			break;
278a5f0fb15SPaul Saab 		edit_list(cbuf);
2791ede1615STim J. Robbins #if TAGS
2808fd4165cSPaul Saab 		/* If tag structure is loaded then clean it up. */
2818fd4165cSPaul Saab 		cleantags();
2821ede1615STim J. Robbins #endif
283a5f0fb15SPaul Saab 		break;
284a5f0fb15SPaul Saab #endif
285a5f0fb15SPaul Saab #if SHELL_ESCAPE
286a5f0fb15SPaul Saab 	case A_SHELL:
287a5f0fb15SPaul Saab 		/*
288a5f0fb15SPaul Saab 		 * !! just uses whatever is in shellcmd.
289a5f0fb15SPaul Saab 		 * Otherwise, copy cmdbuf to shellcmd,
290a5f0fb15SPaul Saab 		 * expanding any special characters ("%" or "#").
291a5f0fb15SPaul Saab 		 */
292a5f0fb15SPaul Saab 		if (*cbuf != '!')
293a5f0fb15SPaul Saab 		{
294a5f0fb15SPaul Saab 			if (shellcmd != NULL)
295a5f0fb15SPaul Saab 				free(shellcmd);
296a5f0fb15SPaul Saab 			shellcmd = fexpand(cbuf);
297a5f0fb15SPaul Saab 		}
298a5f0fb15SPaul Saab 
299a5f0fb15SPaul Saab 		if (secure)
300a5f0fb15SPaul Saab 			break;
301a5f0fb15SPaul Saab 		if (shellcmd == NULL)
302a5f0fb15SPaul Saab 			lsystem("", "!done");
303a5f0fb15SPaul Saab 		else
304a5f0fb15SPaul Saab 			lsystem(shellcmd, "!done");
305a5f0fb15SPaul Saab 		break;
306a5f0fb15SPaul Saab #endif
307a5f0fb15SPaul Saab #if PIPEC
308a5f0fb15SPaul Saab 	case A_PIPE:
309a5f0fb15SPaul Saab 		if (secure)
310a5f0fb15SPaul Saab 			break;
311a5f0fb15SPaul Saab 		(void) pipe_mark(pipec, cbuf);
312a5f0fb15SPaul Saab 		error("|done", NULL_PARG);
313a5f0fb15SPaul Saab 		break;
314a5f0fb15SPaul Saab #endif
315a5f0fb15SPaul Saab 	}
316a5f0fb15SPaul Saab }
317a5f0fb15SPaul Saab 
318a5f0fb15SPaul Saab /*
31933096f16SXin LI  * Is a character an erase or kill char?
320a5f0fb15SPaul Saab  */
321a5f0fb15SPaul Saab 	static int
322f6b74a7dSXin LI is_erase_char(c)
323f6b74a7dSXin LI 	int c;
324a5f0fb15SPaul Saab {
32533096f16SXin LI 	return (c == erase_char || c == erase2_char || c == kill_char);
326a5f0fb15SPaul Saab }
327a5f0fb15SPaul Saab 
328a5f0fb15SPaul Saab /*
329b2ea2440SXin LI  * Is a character a carriage return or newline?
330b2ea2440SXin LI  */
331b2ea2440SXin LI 	static int
332b2ea2440SXin LI is_newline_char(c)
333b2ea2440SXin LI 	int c;
334b2ea2440SXin LI {
335b2ea2440SXin LI 	return (c == '\n' || c == '\r');
336b2ea2440SXin LI }
337b2ea2440SXin LI 
338b2ea2440SXin LI /*
33933096f16SXin LI  * Handle the first char of an option (after the initial dash).
340a5f0fb15SPaul Saab  */
34133096f16SXin LI 	static int
342f6b74a7dSXin LI mca_opt_first_char(c)
343f6b74a7dSXin LI 	int c;
344a5f0fb15SPaul Saab {
34533096f16SXin LI 	int flag = (optflag & ~OPT_NO_PROMPT);
346a5f0fb15SPaul Saab 	if (flag == OPT_NO_TOGGLE)
347a5f0fb15SPaul Saab 	{
348a5f0fb15SPaul Saab 		switch (c)
349a5f0fb15SPaul Saab 		{
350a5f0fb15SPaul Saab 		case '_':
351a5f0fb15SPaul Saab 			/* "__" = long option name. */
352a5f0fb15SPaul Saab 			optgetname = TRUE;
353a5f0fb15SPaul Saab 			mca_opt_toggle();
354a5f0fb15SPaul Saab 			return (MCA_MORE);
355a5f0fb15SPaul Saab 		}
356a5f0fb15SPaul Saab 	} else
357a5f0fb15SPaul Saab 	{
358a5f0fb15SPaul Saab 		switch (c)
359a5f0fb15SPaul Saab 		{
360a5f0fb15SPaul Saab 		case '+':
361a5f0fb15SPaul Saab 			/* "-+" = UNSET. */
362a5f0fb15SPaul Saab 			optflag = (flag == OPT_UNSET) ?
363a5f0fb15SPaul Saab 				OPT_TOGGLE : OPT_UNSET;
364a5f0fb15SPaul Saab 			mca_opt_toggle();
365a5f0fb15SPaul Saab 			return (MCA_MORE);
366a5f0fb15SPaul Saab 		case '!':
367a5f0fb15SPaul Saab 			/* "-!" = SET */
368a5f0fb15SPaul Saab 			optflag = (flag == OPT_SET) ?
369a5f0fb15SPaul Saab 				OPT_TOGGLE : OPT_SET;
370a5f0fb15SPaul Saab 			mca_opt_toggle();
371a5f0fb15SPaul Saab 			return (MCA_MORE);
372a5f0fb15SPaul Saab 		case CONTROL('P'):
373a5f0fb15SPaul Saab 			optflag ^= OPT_NO_PROMPT;
374a5f0fb15SPaul Saab 			mca_opt_toggle();
375a5f0fb15SPaul Saab 			return (MCA_MORE);
376a5f0fb15SPaul Saab 		case '-':
377a5f0fb15SPaul Saab 			/* "--" = long option name. */
378a5f0fb15SPaul Saab 			optgetname = TRUE;
379a5f0fb15SPaul Saab 			mca_opt_toggle();
380a5f0fb15SPaul Saab 			return (MCA_MORE);
381a5f0fb15SPaul Saab 		}
382a5f0fb15SPaul Saab 	}
38333096f16SXin LI 	/* Char was not handled here. */
38433096f16SXin LI 	return (NO_MCA);
385a5f0fb15SPaul Saab }
38633096f16SXin LI 
387a5f0fb15SPaul Saab /*
38833096f16SXin LI  * Add a char to a long option name.
38933096f16SXin LI  * See if we've got a match for an option name yet.
390a5f0fb15SPaul Saab  * If so, display the complete name and stop
391a5f0fb15SPaul Saab  * accepting chars until user hits RETURN.
392a5f0fb15SPaul Saab  */
39333096f16SXin LI 	static int
394f6b74a7dSXin LI mca_opt_nonfirst_char(c)
395f6b74a7dSXin LI 	int c;
39633096f16SXin LI {
39733096f16SXin LI 	char *p;
398a5f0fb15SPaul Saab 	char *oname;
399b7780dbeSXin LI 	int err;
400a5f0fb15SPaul Saab 
40133096f16SXin LI 	if (curropt != NULL)
402a5f0fb15SPaul Saab 	{
403a5f0fb15SPaul Saab 		/*
404a5f0fb15SPaul Saab 		 * Already have a match for the name.
405a5f0fb15SPaul Saab 		 * Don't accept anything but erase/kill.
406a5f0fb15SPaul Saab 		 */
40733096f16SXin LI 		if (is_erase_char(c))
408a5f0fb15SPaul Saab 			return (MCA_DONE);
409a5f0fb15SPaul Saab 		return (MCA_MORE);
410a5f0fb15SPaul Saab 	}
411a5f0fb15SPaul Saab 	/*
412a5f0fb15SPaul Saab 	 * Add char to cmd buffer and try to match
413a5f0fb15SPaul Saab 	 * the option name.
414a5f0fb15SPaul Saab 	 */
415a5f0fb15SPaul Saab 	if (cmd_char(c) == CC_QUIT)
416a5f0fb15SPaul Saab 		return (MCA_DONE);
417a5f0fb15SPaul Saab 	p = get_cmdbuf();
41833096f16SXin LI 	opt_lower = ASCII_IS_LOWER(p[0]);
419b7780dbeSXin LI 	err = 0;
420b7780dbeSXin LI 	curropt = findopt_name(&p, &oname, &err);
42133096f16SXin LI 	if (curropt != NULL)
422a5f0fb15SPaul Saab 	{
423a5f0fb15SPaul Saab 		/*
424a5f0fb15SPaul Saab 		 * Got a match.
42533096f16SXin LI 		 * Remember the option and
426a5f0fb15SPaul Saab 		 * display the full option name.
427a5f0fb15SPaul Saab 		 */
428a5f0fb15SPaul Saab 		cmd_reset();
429a5f0fb15SPaul Saab 		mca_opt_toggle();
430a5f0fb15SPaul Saab 		for (p = oname;  *p != '\0';  p++)
431a5f0fb15SPaul Saab 		{
432a5f0fb15SPaul Saab 			c = *p;
43333096f16SXin LI 			if (!opt_lower && ASCII_IS_LOWER(c))
43489dd99dcSXin LI 				c = ASCII_TO_UPPER(c);
435a5f0fb15SPaul Saab 			if (cmd_char(c) != CC_OK)
436a5f0fb15SPaul Saab 				return (MCA_DONE);
437a5f0fb15SPaul Saab 		}
438b7780dbeSXin LI 	} else if (err != OPT_AMBIG)
439b7780dbeSXin LI 	{
440b7780dbeSXin LI 		bell();
441a5f0fb15SPaul Saab 	}
442a5f0fb15SPaul Saab 	return (MCA_MORE);
443a5f0fb15SPaul Saab }
44433096f16SXin LI 
44533096f16SXin LI /*
44633096f16SXin LI  * Handle a char of an option toggle command.
44733096f16SXin LI  */
44833096f16SXin LI 	static int
449f6b74a7dSXin LI mca_opt_char(c)
450f6b74a7dSXin LI 	int c;
45133096f16SXin LI {
45233096f16SXin LI 	PARG parg;
45333096f16SXin LI 
45433096f16SXin LI 	/*
45533096f16SXin LI 	 * This may be a short option (single char),
45633096f16SXin LI 	 * or one char of a long option name,
45733096f16SXin LI 	 * or one char of the option parameter.
45833096f16SXin LI 	 */
45933096f16SXin LI 	if (curropt == NULL && len_cmdbuf() == 0)
46033096f16SXin LI 	{
46133096f16SXin LI 		int ret = mca_opt_first_char(c);
46233096f16SXin LI 		if (ret != NO_MCA)
46333096f16SXin LI 			return (ret);
46433096f16SXin LI 	}
46533096f16SXin LI 	if (optgetname)
46633096f16SXin LI 	{
46733096f16SXin LI 		/* We're getting a long option name.  */
468b2ea2440SXin LI 		if (!is_newline_char(c))
46933096f16SXin LI 			return (mca_opt_nonfirst_char(c));
47033096f16SXin LI 		if (curropt == NULL)
47133096f16SXin LI 		{
47233096f16SXin LI 			parg.p_string = get_cmdbuf();
47333096f16SXin LI 			error("There is no --%s option", &parg);
47433096f16SXin LI 			return (MCA_DONE);
47533096f16SXin LI 		}
47633096f16SXin LI 		optgetname = FALSE;
47733096f16SXin LI 		cmd_reset();
478a5f0fb15SPaul Saab 	} else
479a5f0fb15SPaul Saab 	{
48033096f16SXin LI 		if (is_erase_char(c))
48133096f16SXin LI 			return (NO_MCA);
48233096f16SXin LI 		if (curropt != NULL)
48333096f16SXin LI 			/* We're getting the option parameter. */
48433096f16SXin LI 			return (NO_MCA);
48533096f16SXin LI 		curropt = findopt(c);
48633096f16SXin LI 		if (curropt == NULL)
487a5f0fb15SPaul Saab 		{
48833096f16SXin LI 			parg.p_string = propt(c);
48933096f16SXin LI 			error("There is no %s option", &parg);
49033096f16SXin LI 			return (MCA_DONE);
49133096f16SXin LI 		}
492b7780dbeSXin LI 		opt_lower = ASCII_IS_LOWER(c);
49333096f16SXin LI 	}
49433096f16SXin LI 	/*
49533096f16SXin LI 	 * If the option which was entered does not take a
49633096f16SXin LI 	 * parameter, toggle the option immediately,
49733096f16SXin LI 	 * so user doesn't have to hit RETURN.
49833096f16SXin LI 	 */
49933096f16SXin LI 	if ((optflag & ~OPT_NO_PROMPT) != OPT_TOGGLE ||
50033096f16SXin LI 	    !opt_has_param(curropt))
50133096f16SXin LI 	{
502b7780dbeSXin LI 		toggle_option(curropt, opt_lower, "", optflag);
503a5f0fb15SPaul Saab 		return (MCA_DONE);
504a5f0fb15SPaul Saab 	}
505a5f0fb15SPaul Saab 	/*
50633096f16SXin LI 	 * Display a prompt appropriate for the option parameter.
507a5f0fb15SPaul Saab 	 */
50833096f16SXin LI 	start_mca(A_OPT_TOGGLE, opt_prompt(curropt), (void*)NULL, 0);
509a5f0fb15SPaul Saab 	return (MCA_MORE);
51033096f16SXin LI }
511a5f0fb15SPaul Saab 
512a5f0fb15SPaul Saab /*
51333096f16SXin LI  * Handle a char of a search command.
51433096f16SXin LI  */
51533096f16SXin LI 	static int
516f6b74a7dSXin LI mca_search_char(c)
517f6b74a7dSXin LI 	int c;
51833096f16SXin LI {
51933096f16SXin LI 	int flag = 0;
52033096f16SXin LI 
52133096f16SXin LI 	/*
522a5f0fb15SPaul Saab 	 * Certain characters as the first char of
523a5f0fb15SPaul Saab 	 * the pattern have special meaning:
524a5f0fb15SPaul Saab 	 *      !  Toggle the NO_MATCH flag
525a5f0fb15SPaul Saab 	 *      *  Toggle the PAST_EOF flag
526a5f0fb15SPaul Saab 	 *      @  Toggle the FIRST_FILE flag
527a5f0fb15SPaul Saab 	 */
528a5f0fb15SPaul Saab 	if (len_cmdbuf() > 0)
52933096f16SXin LI 		return (NO_MCA);
530a5f0fb15SPaul Saab 
531a5f0fb15SPaul Saab 	switch (c)
532a5f0fb15SPaul Saab 	{
533a5f0fb15SPaul Saab 	case '*':
534720c436cSXin LI 		if (less_is_more)
535a8f92a7cSPaul Saab 			break;
536a8f92a7cSPaul Saab 	case CONTROL('E'): /* ignore END of file */
5377374caaaSXin LI 		if (mca != A_FILTER)
538a5f0fb15SPaul Saab 			flag = SRCH_PAST_EOF;
539a5f0fb15SPaul Saab 		break;
540a5f0fb15SPaul Saab 	case '@':
541720c436cSXin LI 		if (less_is_more)
542a8f92a7cSPaul Saab 			break;
543a8f92a7cSPaul Saab 	case CONTROL('F'): /* FIRST file */
5447374caaaSXin LI 		if (mca != A_FILTER)
545a5f0fb15SPaul Saab 			flag = SRCH_FIRST_FILE;
546a5f0fb15SPaul Saab 		break;
547a5f0fb15SPaul Saab 	case CONTROL('K'): /* KEEP position */
5487374caaaSXin LI 		if (mca != A_FILTER)
549a5f0fb15SPaul Saab 			flag = SRCH_NO_MOVE;
550a5f0fb15SPaul Saab 		break;
551*2235c7feSXin LI 	case CONTROL('W'): /* WRAP around */
552*2235c7feSXin LI 		if (mca != A_FILTER)
553*2235c7feSXin LI 			flag = SRCH_WRAP;
554*2235c7feSXin LI 		break;
555a5f0fb15SPaul Saab 	case CONTROL('R'): /* Don't use REGULAR EXPRESSIONS */
556a5f0fb15SPaul Saab 		flag = SRCH_NO_REGEX;
557a5f0fb15SPaul Saab 		break;
558a5f0fb15SPaul Saab 	case CONTROL('N'): /* NOT match */
559a5f0fb15SPaul Saab 	case '!':
560a5f0fb15SPaul Saab 		flag = SRCH_NO_MATCH;
561a5f0fb15SPaul Saab 		break;
562a5f0fb15SPaul Saab 	}
56333096f16SXin LI 
564a5f0fb15SPaul Saab 	if (flag != 0)
565a5f0fb15SPaul Saab 	{
566*2235c7feSXin LI 		/* Toggle flag, but keep PAST_EOF and WRAP mutually exclusive. */
567*2235c7feSXin LI 		search_type ^= flag | (search_type & (SRCH_PAST_EOF|SRCH_WRAP));
568a5f0fb15SPaul Saab 		mca_search();
569a5f0fb15SPaul Saab 		return (MCA_MORE);
570a5f0fb15SPaul Saab 	}
57133096f16SXin LI 	return (NO_MCA);
57233096f16SXin LI }
57333096f16SXin LI 
57433096f16SXin LI /*
57533096f16SXin LI  * Handle a character of a multi-character command.
57633096f16SXin LI  */
57733096f16SXin LI 	static int
578f6b74a7dSXin LI mca_char(c)
579f6b74a7dSXin LI 	int c;
58033096f16SXin LI {
58133096f16SXin LI 	int ret;
58233096f16SXin LI 
58333096f16SXin LI 	switch (mca)
58433096f16SXin LI 	{
58533096f16SXin LI 	case 0:
58633096f16SXin LI 		/*
58733096f16SXin LI 		 * We're not in a multicharacter command.
58833096f16SXin LI 		 */
58933096f16SXin LI 		return (NO_MCA);
59033096f16SXin LI 
59133096f16SXin LI 	case A_PREFIX:
59233096f16SXin LI 		/*
59333096f16SXin LI 		 * In the prefix of a command.
59433096f16SXin LI 		 * This not considered a multichar command
59533096f16SXin LI 		 * (even tho it uses cmdbuf, etc.).
59633096f16SXin LI 		 * It is handled in the commands() switch.
59733096f16SXin LI 		 */
59833096f16SXin LI 		return (NO_MCA);
59933096f16SXin LI 
60033096f16SXin LI 	case A_DIGIT:
60133096f16SXin LI 		/*
60233096f16SXin LI 		 * Entering digits of a number.
60333096f16SXin LI 		 * Terminated by a non-digit.
60433096f16SXin LI 		 */
605*2235c7feSXin LI 		if ((c >= '0' && c <= '9') || c == '.')
606*2235c7feSXin LI 			break;
607*2235c7feSXin LI 		switch (editchar(c, ECF_PEEK|ECF_NOHISTORY|ECF_NOCOMPLETE|ECF_NORIGHTLEFT))
60833096f16SXin LI 		{
609*2235c7feSXin LI 		case A_NOACTION:
610*2235c7feSXin LI 			/*
611*2235c7feSXin LI 			 * Ignore this char and get another one.
612*2235c7feSXin LI 			 */
613*2235c7feSXin LI 			return (MCA_MORE);
614*2235c7feSXin LI 		case A_INVALID:
61533096f16SXin LI 			/*
61633096f16SXin LI 			 * Not part of the number.
61733096f16SXin LI 			 * End the number and treat this char
61833096f16SXin LI 			 * as a normal command character.
61933096f16SXin LI 			 */
62033096f16SXin LI 			number = cmd_int(&fraction);
621b7780dbeSXin LI 			clear_mca();
62233096f16SXin LI 			cmd_accept();
62333096f16SXin LI 			return (NO_MCA);
62433096f16SXin LI 		}
62533096f16SXin LI 		break;
62633096f16SXin LI 
62733096f16SXin LI 	case A_OPT_TOGGLE:
62833096f16SXin LI 		ret = mca_opt_char(c);
62933096f16SXin LI 		if (ret != NO_MCA)
63033096f16SXin LI 			return (ret);
63133096f16SXin LI 		break;
63233096f16SXin LI 
63333096f16SXin LI 	case A_F_SEARCH:
63433096f16SXin LI 	case A_B_SEARCH:
63533096f16SXin LI 	case A_FILTER:
63633096f16SXin LI 		ret = mca_search_char(c);
63733096f16SXin LI 		if (ret != NO_MCA)
63833096f16SXin LI 			return (ret);
63933096f16SXin LI 		break;
64033096f16SXin LI 
64133096f16SXin LI 	default:
64233096f16SXin LI 		/* Other multicharacter command. */
643a5f0fb15SPaul Saab 		break;
644a5f0fb15SPaul Saab 	}
645a5f0fb15SPaul Saab 
646a5f0fb15SPaul Saab 	/*
64733096f16SXin LI 	 * The multichar command is terminated by a newline.
648a5f0fb15SPaul Saab 	 */
649b2ea2440SXin LI 	if (is_newline_char(c))
650a5f0fb15SPaul Saab 	{
651a5f0fb15SPaul Saab 		/*
652a5f0fb15SPaul Saab 		 * Execute the command.
653a5f0fb15SPaul Saab 		 */
654a5f0fb15SPaul Saab 		exec_mca();
655a5f0fb15SPaul Saab 		return (MCA_DONE);
656a5f0fb15SPaul Saab 	}
657a5f0fb15SPaul Saab 
658a5f0fb15SPaul Saab 	/*
659a5f0fb15SPaul Saab 	 * Append the char to the command buffer.
660a5f0fb15SPaul Saab 	 */
661a5f0fb15SPaul Saab 	if (cmd_char(c) == CC_QUIT)
662a5f0fb15SPaul Saab 		/*
663a5f0fb15SPaul Saab 		 * Abort the multi-char command.
664a5f0fb15SPaul Saab 		 */
665a5f0fb15SPaul Saab 		return (MCA_DONE);
666a5f0fb15SPaul Saab 
667*2235c7feSXin LI 	switch (mca)
668*2235c7feSXin LI 	{
669*2235c7feSXin LI 	case A_F_BRACKET:
670*2235c7feSXin LI 	case A_B_BRACKET:
671*2235c7feSXin LI 		if (len_cmdbuf() >= 2)
672a5f0fb15SPaul Saab 		{
673a5f0fb15SPaul Saab 			/*
674a5f0fb15SPaul Saab 			 * Special case for the bracket-matching commands.
675a5f0fb15SPaul Saab 			 * Execute the command after getting exactly two
676a5f0fb15SPaul Saab 			 * characters from the user.
677a5f0fb15SPaul Saab 			 */
678a5f0fb15SPaul Saab 			exec_mca();
679a5f0fb15SPaul Saab 			return (MCA_DONE);
680a5f0fb15SPaul Saab 		}
681*2235c7feSXin LI 		break;
682*2235c7feSXin LI 	case A_F_SEARCH:
683*2235c7feSXin LI 	case A_B_SEARCH:
684*2235c7feSXin LI 		if (incr_search)
685*2235c7feSXin LI 		{
686*2235c7feSXin LI 			/* Incremental search: do a search after every input char. */
687*2235c7feSXin LI 			int st = (search_type & (SRCH_FORW|SRCH_BACK|SRCH_NO_MATCH|SRCH_NO_REGEX|SRCH_NO_MOVE|SRCH_WRAP));
688*2235c7feSXin LI 			char *pattern = get_cmdbuf();
689*2235c7feSXin LI 			cmd_exec();
690*2235c7feSXin LI 			if (*pattern == '\0')
691*2235c7feSXin LI 			{
692*2235c7feSXin LI 				/* User has backspaced to an empty pattern. */
693*2235c7feSXin LI 				undo_search(1);
694*2235c7feSXin LI 			} else
695*2235c7feSXin LI 			{
696*2235c7feSXin LI 				if (search(st | SRCH_INCR, pattern, 1) != 0)
697*2235c7feSXin LI 					/* No match, invalid pattern, etc. */
698*2235c7feSXin LI 					undo_search(1);
699*2235c7feSXin LI 			}
700*2235c7feSXin LI 			/* Redraw the search prompt and search string. */
701*2235c7feSXin LI 			mca_search();
702*2235c7feSXin LI 			cmd_repaint(NULL);
703*2235c7feSXin LI 		}
704*2235c7feSXin LI 		break;
705*2235c7feSXin LI 	}
706a5f0fb15SPaul Saab 
707a5f0fb15SPaul Saab 	/*
708a5f0fb15SPaul Saab 	 * Need another character.
709a5f0fb15SPaul Saab 	 */
710a5f0fb15SPaul Saab 	return (MCA_MORE);
711a5f0fb15SPaul Saab }
712a5f0fb15SPaul Saab 
713a5f0fb15SPaul Saab /*
714423c5ce5SXin LI  * Discard any buffered file data.
715423c5ce5SXin LI  */
716423c5ce5SXin LI 	static void
717b7780dbeSXin LI clear_buffers(VOID_PARAM)
718423c5ce5SXin LI {
719423c5ce5SXin LI 	if (!(ch_getflags() & CH_CANSEEK))
720423c5ce5SXin LI 		return;
721423c5ce5SXin LI 	ch_flush();
722423c5ce5SXin LI 	clr_linenum();
723423c5ce5SXin LI #if HILITE_SEARCH
724423c5ce5SXin LI 	clr_hilite();
725423c5ce5SXin LI #endif
726423c5ce5SXin LI }
727423c5ce5SXin LI 
728423c5ce5SXin LI /*
729a5f0fb15SPaul Saab  * Make sure the screen is displayed.
730a5f0fb15SPaul Saab  */
731a5f0fb15SPaul Saab 	static void
732b7780dbeSXin LI make_display(VOID_PARAM)
733a5f0fb15SPaul Saab {
734a5f0fb15SPaul Saab 	/*
735a5f0fb15SPaul Saab 	 * If nothing is displayed yet, display starting from initial_scrpos.
736a5f0fb15SPaul Saab 	 */
737a5f0fb15SPaul Saab 	if (empty_screen())
738a5f0fb15SPaul Saab 	{
739a5f0fb15SPaul Saab 		if (initial_scrpos.pos == NULL_POSITION)
740a5f0fb15SPaul Saab 			jump_loc(ch_zero(), 1);
741a5f0fb15SPaul Saab 		else
742a5f0fb15SPaul Saab 			jump_loc(initial_scrpos.pos, initial_scrpos.ln);
743a5f0fb15SPaul Saab 	} else if (screen_trashed)
744a5f0fb15SPaul Saab 	{
745423c5ce5SXin LI 		int save_top_scroll = top_scroll;
746423c5ce5SXin LI 		int save_ignore_eoi = ignore_eoi;
747a5f0fb15SPaul Saab 		top_scroll = 1;
748423c5ce5SXin LI 		ignore_eoi = 0;
749423c5ce5SXin LI 		if (screen_trashed == 2)
750423c5ce5SXin LI 		{
751423c5ce5SXin LI 			/* Special case used by ignore_eoi: re-open the input file
752423c5ce5SXin LI 			 * and jump to the end of the file. */
753423c5ce5SXin LI 			reopen_curr_ifile();
754423c5ce5SXin LI 			jump_forw();
755423c5ce5SXin LI 		}
756a5f0fb15SPaul Saab 		repaint();
757a5f0fb15SPaul Saab 		top_scroll = save_top_scroll;
758423c5ce5SXin LI 		ignore_eoi = save_ignore_eoi;
759a5f0fb15SPaul Saab 	}
760a5f0fb15SPaul Saab }
761a5f0fb15SPaul Saab 
762a5f0fb15SPaul Saab /*
763a5f0fb15SPaul Saab  * Display the appropriate prompt.
764a5f0fb15SPaul Saab  */
765a5f0fb15SPaul Saab 	static void
766b7780dbeSXin LI prompt(VOID_PARAM)
767a5f0fb15SPaul Saab {
7681ea31627SRobert Watson 	constant char *p;
769a5f0fb15SPaul Saab 
770b2ea2440SXin LI 	if (ungot != NULL && ungot->ug_char != CHAR_END_COMMAND)
771a5f0fb15SPaul Saab 	{
772a5f0fb15SPaul Saab 		/*
773a5f0fb15SPaul Saab 		 * No prompt necessary if commands are from
774a5f0fb15SPaul Saab 		 * ungotten chars rather than from the user.
775a5f0fb15SPaul Saab 		 */
776a5f0fb15SPaul Saab 		return;
777a5f0fb15SPaul Saab 	}
778a5f0fb15SPaul Saab 
779a5f0fb15SPaul Saab 	/*
780a5f0fb15SPaul Saab 	 * Make sure the screen is displayed.
781a5f0fb15SPaul Saab 	 */
782a5f0fb15SPaul Saab 	make_display();
783a5f0fb15SPaul Saab 	bottompos = position(BOTTOM_PLUS_ONE);
784a5f0fb15SPaul Saab 
785a5f0fb15SPaul Saab 	/*
7867374caaaSXin LI 	 * If we've hit EOF on the last file and the -E flag is set, quit.
787a5f0fb15SPaul Saab 	 */
7887374caaaSXin LI 	if (get_quit_at_eof() == OPT_ONPLUS &&
7897374caaaSXin LI 	    eof_displayed() && !(ch_getflags() & CH_HELPFILE) &&
790a5f0fb15SPaul Saab 	    next_ifile(curr_ifile) == NULL_IFILE)
791a5f0fb15SPaul Saab 		quit(QUIT_OK);
7927374caaaSXin LI 
793a5f0fb15SPaul Saab 	/*
7947374caaaSXin LI 	 * If the entire file is displayed and the -F flag is set, quit.
795a5f0fb15SPaul Saab 	 */
7967374caaaSXin LI 	if (quit_if_one_screen &&
7977374caaaSXin LI 	    entire_file_displayed() && !(ch_getflags() & CH_HELPFILE) &&
798a5f0fb15SPaul Saab 	    next_ifile(curr_ifile) == NULL_IFILE)
799a5f0fb15SPaul Saab 		quit(QUIT_OK);
800a5f0fb15SPaul Saab 
8018fd4165cSPaul Saab #if MSDOS_COMPILER==WIN32C
8028fd4165cSPaul Saab 	/*
8038fd4165cSPaul Saab 	 * In Win32, display the file name in the window title.
8048fd4165cSPaul Saab 	 */
8058fd4165cSPaul Saab 	if (!(ch_getflags() & CH_HELPFILE))
806b7780dbeSXin LI 	{
807b7780dbeSXin LI 		WCHAR w[MAX_PATH+16];
808b7780dbeSXin LI 		p = pr_expand("Less?f - %f.", 0);
809b7780dbeSXin LI 		MultiByteToWideChar(CP_ACP, 0, p, -1, w, sizeof(w)/sizeof(*w));
810b7780dbeSXin LI 		SetConsoleTitleW(w);
811b7780dbeSXin LI 	}
8128fd4165cSPaul Saab #endif
813b7780dbeSXin LI 
814a5f0fb15SPaul Saab 	/*
815a5f0fb15SPaul Saab 	 * Select the proper prompt and display it.
816a5f0fb15SPaul Saab 	 */
817720c436cSXin LI 	/*
818720c436cSXin LI 	 * If the previous action was a forward movement,
819720c436cSXin LI 	 * don't clear the bottom line of the display;
820720c436cSXin LI 	 * just print the prompt since the forward movement guarantees
821720c436cSXin LI 	 * that we're in the right position to display the prompt.
822720c436cSXin LI 	 * Clearing the line could cause a problem: for example, if the last
823720c436cSXin LI 	 * line displayed ended at the right screen edge without a newline,
824720c436cSXin LI 	 * then clearing would clear the last displayed line rather than
825720c436cSXin LI 	 * the prompt line.
826720c436cSXin LI 	 */
827720c436cSXin LI 	if (!forw_prompt)
828720c436cSXin LI 		clear_bot();
829a5f0fb15SPaul Saab 	clear_cmd();
830720c436cSXin LI 	forw_prompt = 0;
831a5f0fb15SPaul Saab 	p = pr_string();
832*2235c7feSXin LI #if HILITE_SEARCH
8337374caaaSXin LI 	if (is_filtering())
8347374caaaSXin LI 		putstr("& ");
835*2235c7feSXin LI #endif
83689dd99dcSXin LI 	if (p == NULL || *p == '\0')
837*2235c7feSXin LI 	{
838*2235c7feSXin LI 		at_enter(AT_NORMAL|AT_COLOR_PROMPT);
839a5f0fb15SPaul Saab 		putchr(':');
840*2235c7feSXin LI 		at_exit();
841*2235c7feSXin LI 	} else
842a5f0fb15SPaul Saab 	{
843b7780dbeSXin LI #if MSDOS_COMPILER==WIN32C
844b7780dbeSXin LI 		WCHAR w[MAX_PATH*2];
845b7780dbeSXin LI 		char  a[MAX_PATH*2];
846b7780dbeSXin LI 		MultiByteToWideChar(CP_ACP, 0, p, -1, w, sizeof(w)/sizeof(*w));
847b7780dbeSXin LI 		WideCharToMultiByte(utf_mode ? CP_UTF8 : GetConsoleOutputCP(),
848b7780dbeSXin LI 		                    0, w, -1, a, sizeof(a), NULL, NULL);
849b7780dbeSXin LI 		p = a;
850b7780dbeSXin LI #endif
851*2235c7feSXin LI 		at_enter(AT_STANDOUT|AT_COLOR_PROMPT);
852a5f0fb15SPaul Saab 		putstr(p);
85389dd99dcSXin LI 		at_exit();
854a5f0fb15SPaul Saab 	}
855720c436cSXin LI 	clear_eol();
856a5f0fb15SPaul Saab }
857a5f0fb15SPaul Saab 
858a5f0fb15SPaul Saab /*
859a5f0fb15SPaul Saab  * Display the less version message.
860a5f0fb15SPaul Saab  */
861a5f0fb15SPaul Saab 	public void
862b7780dbeSXin LI dispversion(VOID_PARAM)
863a5f0fb15SPaul Saab {
864a5f0fb15SPaul Saab 	PARG parg;
865a5f0fb15SPaul Saab 
866a5f0fb15SPaul Saab 	parg.p_string = version;
867a5f0fb15SPaul Saab 	error("less %s", &parg);
868a5f0fb15SPaul Saab }
869a5f0fb15SPaul Saab 
870a5f0fb15SPaul Saab /*
871b2ea2440SXin LI  * Return a character to complete a partial command, if possible.
872b2ea2440SXin LI  */
873b2ea2440SXin LI 	static LWCHAR
874b7780dbeSXin LI getcc_end_command(VOID_PARAM)
875b2ea2440SXin LI {
876b2ea2440SXin LI 	switch (mca)
877b2ea2440SXin LI 	{
878b2ea2440SXin LI 	case A_DIGIT:
879b2ea2440SXin LI 		/* We have a number but no command.  Treat as #g. */
880b2ea2440SXin LI 		return ('g');
881b2ea2440SXin LI 	case A_F_SEARCH:
882b2ea2440SXin LI 	case A_B_SEARCH:
883b2ea2440SXin LI 		/* We have "/string" but no newline.  Add the \n. */
884b2ea2440SXin LI 		return ('\n');
885b2ea2440SXin LI 	default:
886b2ea2440SXin LI 		/* Some other incomplete command.  Let user complete it. */
887*2235c7feSXin LI 		return ((ungot == NULL) ? getchr() : 0);
888b2ea2440SXin LI 	}
889b2ea2440SXin LI }
890b2ea2440SXin LI 
891b2ea2440SXin LI /*
892a5f0fb15SPaul Saab  * Get command character.
893a5f0fb15SPaul Saab  * The character normally comes from the keyboard,
894a5f0fb15SPaul Saab  * but may come from ungotten characters
895a5f0fb15SPaul Saab  * (characters previously given to ungetcc or ungetsc).
896a5f0fb15SPaul Saab  */
897b2ea2440SXin LI 	static LWCHAR
89874709ed0SXin LI getccu(VOID_PARAM)
899a5f0fb15SPaul Saab {
900*2235c7feSXin LI 	LWCHAR c = 0;
901*2235c7feSXin LI 	while (c == 0)
902*2235c7feSXin LI 	{
903a15691bfSXin LI 		if (ungot == NULL)
90433096f16SXin LI 		{
905b2ea2440SXin LI 			/* Normal case: no ungotten chars.
906b2ea2440SXin LI 			 * Get char from the user. */
907b2ea2440SXin LI 			c = getchr();
908b2ea2440SXin LI 		} else
909a15691bfSXin LI 		{
910b2ea2440SXin LI 			/* Ungotten chars available:
911b2ea2440SXin LI 			 * Take the top of stack (most recent). */
912a15691bfSXin LI 			struct ungot *ug = ungot;
913b2ea2440SXin LI 			c = ug->ug_char;
914a15691bfSXin LI 			ungot = ug->ug_next;
915a15691bfSXin LI 			free(ug);
916a5f0fb15SPaul Saab 
917b2ea2440SXin LI 			if (c == CHAR_END_COMMAND)
918b2ea2440SXin LI 				c = getcc_end_command();
919a5f0fb15SPaul Saab 		}
920*2235c7feSXin LI 	}
92133096f16SXin LI 	return (c);
92233096f16SXin LI }
923b2ea2440SXin LI 
924b2ea2440SXin LI /*
925b2ea2440SXin LI  * Get a command character, but if we receive the orig sequence,
926b2ea2440SXin LI  * convert it to the repl sequence.
927b2ea2440SXin LI  */
928b2ea2440SXin LI 	static LWCHAR
929b2ea2440SXin LI getcc_repl(orig, repl, gr_getc, gr_ungetc)
930b2ea2440SXin LI 	char const* orig;
931b2ea2440SXin LI 	char const* repl;
932b2ea2440SXin LI 	LWCHAR (*gr_getc)(VOID_PARAM);
933b2ea2440SXin LI 	void (*gr_ungetc)(LWCHAR);
934b2ea2440SXin LI {
935b2ea2440SXin LI 	LWCHAR c;
936b2ea2440SXin LI 	LWCHAR keys[16];
937b2ea2440SXin LI 	int ki = 0;
938b2ea2440SXin LI 
939b2ea2440SXin LI 	c = (*gr_getc)();
940b2ea2440SXin LI 	if (orig == NULL || orig[0] == '\0')
941b2ea2440SXin LI 		return c;
942b2ea2440SXin LI 	for (;;)
943b2ea2440SXin LI 	{
944b2ea2440SXin LI 		keys[ki] = c;
945b2ea2440SXin LI 		if (c != orig[ki] || ki >= sizeof(keys)-1)
946b2ea2440SXin LI 		{
947b2ea2440SXin LI 			/* This is not orig we have been receiving.
948b2ea2440SXin LI 			 * If we have stashed chars in keys[],
949b2ea2440SXin LI 			 * unget them and return the first one. */
950b2ea2440SXin LI 			while (ki > 0)
951b2ea2440SXin LI 				(*gr_ungetc)(keys[ki--]);
952b2ea2440SXin LI 			return keys[0];
953b2ea2440SXin LI 		}
954b2ea2440SXin LI 		if (orig[++ki] == '\0')
955b2ea2440SXin LI 		{
956b2ea2440SXin LI 			/* We've received the full orig sequence.
957b2ea2440SXin LI 			 * Return the repl sequence. */
958b2ea2440SXin LI 			ki = strlen(repl)-1;
959b2ea2440SXin LI 			while (ki > 0)
960b2ea2440SXin LI 				(*gr_ungetc)(repl[ki--]);
961b2ea2440SXin LI 			return repl[0];
962b2ea2440SXin LI 		}
963b2ea2440SXin LI 		/* We've received a partial orig sequence (ki chars of it).
964b2ea2440SXin LI 		 * Get next char and see if it continues to match orig. */
965b2ea2440SXin LI 		c = (*gr_getc)();
966b2ea2440SXin LI 	}
967b2ea2440SXin LI }
968b2ea2440SXin LI 
969b2ea2440SXin LI /*
970b2ea2440SXin LI  * Get command character.
971b2ea2440SXin LI  */
972b2ea2440SXin LI 	public int
973b7780dbeSXin LI getcc(VOID_PARAM)
974b2ea2440SXin LI {
975b2ea2440SXin LI 	/* Replace kent (keypad Enter) with a newline. */
976b2ea2440SXin LI 	return getcc_repl(kent, "\n", getccu, ungetcc);
97733096f16SXin LI }
97833096f16SXin LI 
979a5f0fb15SPaul Saab /*
980a5f0fb15SPaul Saab  * "Unget" a command character.
981a5f0fb15SPaul Saab  * The next getcc() will return this character.
982a5f0fb15SPaul Saab  */
983a5f0fb15SPaul Saab 	public void
984f6b74a7dSXin LI ungetcc(c)
985b2ea2440SXin LI 	LWCHAR c;
986a5f0fb15SPaul Saab {
98733096f16SXin LI 	struct ungot *ug = (struct ungot *) ecalloc(1, sizeof(struct ungot));
98833096f16SXin LI 
989b2ea2440SXin LI 	ug->ug_char = c;
99033096f16SXin LI 	ug->ug_next = ungot;
99133096f16SXin LI 	ungot = ug;
992a5f0fb15SPaul Saab }
993a5f0fb15SPaul Saab 
994a5f0fb15SPaul Saab /*
995*2235c7feSXin LI  * "Unget" a command character.
996*2235c7feSXin LI  * If any other chars are already ungotten, put this one after those.
997*2235c7feSXin LI  */
998*2235c7feSXin LI 	public void
999*2235c7feSXin LI ungetcc_back(c)
1000*2235c7feSXin LI 	LWCHAR c;
1001*2235c7feSXin LI {
1002*2235c7feSXin LI 	struct ungot *ug = (struct ungot *) ecalloc(1, sizeof(struct ungot));
1003*2235c7feSXin LI 	ug->ug_char = c;
1004*2235c7feSXin LI 	ug->ug_next = NULL;
1005*2235c7feSXin LI 	if (ungot == NULL)
1006*2235c7feSXin LI 		ungot = ug;
1007*2235c7feSXin LI 	else
1008*2235c7feSXin LI 	{
1009*2235c7feSXin LI 		struct ungot *pu;
1010*2235c7feSXin LI 		for (pu = ungot; pu->ug_next != NULL; pu = pu->ug_next)
1011*2235c7feSXin LI 			continue;
1012*2235c7feSXin LI 		pu->ug_next = ug;
1013*2235c7feSXin LI 	}
1014*2235c7feSXin LI }
1015*2235c7feSXin LI 
1016*2235c7feSXin LI /*
1017a5f0fb15SPaul Saab  * Unget a whole string of command characters.
1018a5f0fb15SPaul Saab  * The next sequence of getcc()'s will return this string.
1019a5f0fb15SPaul Saab  */
1020a5f0fb15SPaul Saab 	public void
1021f6b74a7dSXin LI ungetsc(s)
1022f6b74a7dSXin LI 	char *s;
1023a5f0fb15SPaul Saab {
1024*2235c7feSXin LI 	while (*s != '\0')
1025*2235c7feSXin LI 		ungetcc_back(*s++);
1026a5f0fb15SPaul Saab }
1027a5f0fb15SPaul Saab 
1028a5f0fb15SPaul Saab /*
1029b2ea2440SXin LI  * Peek the next command character, without consuming it.
1030b2ea2440SXin LI  */
1031b2ea2440SXin LI 	public LWCHAR
1032b7780dbeSXin LI peekcc(VOID_PARAM)
1033b2ea2440SXin LI {
1034b2ea2440SXin LI 	LWCHAR c = getcc();
1035b2ea2440SXin LI 	ungetcc(c);
1036b2ea2440SXin LI 	return c;
1037b2ea2440SXin LI }
1038b2ea2440SXin LI 
1039b2ea2440SXin LI /*
1040a5f0fb15SPaul Saab  * Search for a pattern, possibly in multiple files.
1041a5f0fb15SPaul Saab  * If SRCH_FIRST_FILE is set, begin searching at the first file.
1042a5f0fb15SPaul Saab  * If SRCH_PAST_EOF is set, continue the search thru multiple files.
1043a5f0fb15SPaul Saab  */
1044a5f0fb15SPaul Saab 	static void
1045f6b74a7dSXin LI multi_search(pattern, n, silent)
1046f6b74a7dSXin LI 	char *pattern;
1047f6b74a7dSXin LI 	int n;
1048f6b74a7dSXin LI 	int silent;
1049a5f0fb15SPaul Saab {
10501ea31627SRobert Watson 	int nomore;
1051a5f0fb15SPaul Saab 	IFILE save_ifile;
1052a5f0fb15SPaul Saab 	int changed_file;
1053a5f0fb15SPaul Saab 
1054a5f0fb15SPaul Saab 	changed_file = 0;
1055a5f0fb15SPaul Saab 	save_ifile = save_curr_ifile();
1056a5f0fb15SPaul Saab 
1057a5f0fb15SPaul Saab 	if (search_type & SRCH_FIRST_FILE)
1058a5f0fb15SPaul Saab 	{
1059a5f0fb15SPaul Saab 		/*
1060a5f0fb15SPaul Saab 		 * Start at the first (or last) file
1061a5f0fb15SPaul Saab 		 * in the command line list.
1062a5f0fb15SPaul Saab 		 */
1063a5f0fb15SPaul Saab 		if (search_type & SRCH_FORW)
1064a5f0fb15SPaul Saab 			nomore = edit_first();
1065a5f0fb15SPaul Saab 		else
1066a5f0fb15SPaul Saab 			nomore = edit_last();
1067a5f0fb15SPaul Saab 		if (nomore)
1068a5f0fb15SPaul Saab 		{
1069a5f0fb15SPaul Saab 			unsave_ifile(save_ifile);
1070a5f0fb15SPaul Saab 			return;
1071a5f0fb15SPaul Saab 		}
1072a5f0fb15SPaul Saab 		changed_file = 1;
1073a5f0fb15SPaul Saab 		search_type &= ~SRCH_FIRST_FILE;
1074a5f0fb15SPaul Saab 	}
1075a5f0fb15SPaul Saab 
1076a5f0fb15SPaul Saab 	for (;;)
1077a5f0fb15SPaul Saab 	{
1078a5f0fb15SPaul Saab 		n = search(search_type, pattern, n);
1079a5f0fb15SPaul Saab 		/*
1080a5f0fb15SPaul Saab 		 * The SRCH_NO_MOVE flag doesn't "stick": it gets cleared
1081a5f0fb15SPaul Saab 		 * after being used once.  This allows "n" to work after
1082a5f0fb15SPaul Saab 		 * using a /@@ search.
1083a5f0fb15SPaul Saab 		 */
1084a5f0fb15SPaul Saab 		search_type &= ~SRCH_NO_MOVE;
1085a5f0fb15SPaul Saab 		if (n == 0)
1086a5f0fb15SPaul Saab 		{
1087a5f0fb15SPaul Saab 			/*
1088a5f0fb15SPaul Saab 			 * Found it.
1089a5f0fb15SPaul Saab 			 */
1090a5f0fb15SPaul Saab 			unsave_ifile(save_ifile);
1091a5f0fb15SPaul Saab 			return;
1092a5f0fb15SPaul Saab 		}
1093a5f0fb15SPaul Saab 
1094a5f0fb15SPaul Saab 		if (n < 0)
1095a5f0fb15SPaul Saab 			/*
1096a5f0fb15SPaul Saab 			 * Some kind of error in the search.
1097a5f0fb15SPaul Saab 			 * Error message has been printed by search().
1098a5f0fb15SPaul Saab 			 */
1099a5f0fb15SPaul Saab 			break;
1100a5f0fb15SPaul Saab 
1101a5f0fb15SPaul Saab 		if ((search_type & SRCH_PAST_EOF) == 0)
1102a5f0fb15SPaul Saab 			/*
1103a5f0fb15SPaul Saab 			 * We didn't find a match, but we're
1104a5f0fb15SPaul Saab 			 * supposed to search only one file.
1105a5f0fb15SPaul Saab 			 */
1106a5f0fb15SPaul Saab 			break;
1107a5f0fb15SPaul Saab 		/*
1108a5f0fb15SPaul Saab 		 * Move on to the next file.
1109a5f0fb15SPaul Saab 		 */
1110a5f0fb15SPaul Saab 		if (search_type & SRCH_FORW)
1111a5f0fb15SPaul Saab 			nomore = edit_next(1);
1112a5f0fb15SPaul Saab 		else
1113a5f0fb15SPaul Saab 			nomore = edit_prev(1);
1114a5f0fb15SPaul Saab 		if (nomore)
1115a5f0fb15SPaul Saab 			break;
1116a5f0fb15SPaul Saab 		changed_file = 1;
1117a5f0fb15SPaul Saab 	}
1118a5f0fb15SPaul Saab 
1119a5f0fb15SPaul Saab 	/*
1120a5f0fb15SPaul Saab 	 * Didn't find it.
1121a5f0fb15SPaul Saab 	 * Print an error message if we haven't already.
1122a5f0fb15SPaul Saab 	 */
1123a15691bfSXin LI 	if (n > 0 && !silent)
1124a5f0fb15SPaul Saab 		error("Pattern not found", NULL_PARG);
1125a5f0fb15SPaul Saab 
1126a5f0fb15SPaul Saab 	if (changed_file)
1127a5f0fb15SPaul Saab 	{
1128a5f0fb15SPaul Saab 		/*
1129a5f0fb15SPaul Saab 		 * Restore the file we were originally viewing.
1130a5f0fb15SPaul Saab 		 */
1131a5f0fb15SPaul Saab 		reedit_ifile(save_ifile);
113289dd99dcSXin LI 	} else
113389dd99dcSXin LI 	{
113489dd99dcSXin LI 		unsave_ifile(save_ifile);
1135a5f0fb15SPaul Saab 	}
1136a5f0fb15SPaul Saab }
1137a5f0fb15SPaul Saab 
1138a5f0fb15SPaul Saab /*
113996e55cc7SXin LI  * Forward forever, or until a highlighted line appears.
114096e55cc7SXin LI  */
114196e55cc7SXin LI 	static int
1142f6b74a7dSXin LI forw_loop(until_hilite)
1143f6b74a7dSXin LI 	int until_hilite;
114496e55cc7SXin LI {
114596e55cc7SXin LI 	POSITION curr_len;
114696e55cc7SXin LI 
114796e55cc7SXin LI 	if (ch_getflags() & CH_HELPFILE)
114896e55cc7SXin LI 		return (A_NOACTION);
114996e55cc7SXin LI 
115096e55cc7SXin LI 	cmd_exec();
1151a15691bfSXin LI 	jump_forw_buffered();
115296e55cc7SXin LI 	curr_len = ch_length();
115396e55cc7SXin LI 	highest_hilite = until_hilite ? curr_len : NULL_POSITION;
115496e55cc7SXin LI 	ignore_eoi = 1;
115596e55cc7SXin LI 	while (!sigs)
115696e55cc7SXin LI 	{
115796e55cc7SXin LI 		if (until_hilite && highest_hilite > curr_len)
115896e55cc7SXin LI 		{
115996e55cc7SXin LI 			bell();
116096e55cc7SXin LI 			break;
116196e55cc7SXin LI 		}
116296e55cc7SXin LI 		make_display();
116396e55cc7SXin LI 		forward(1, 0, 0);
116496e55cc7SXin LI 	}
116596e55cc7SXin LI 	ignore_eoi = 0;
1166e2449719SXin LI 	ch_set_eof();
116796e55cc7SXin LI 
116896e55cc7SXin LI 	/*
116996e55cc7SXin LI 	 * This gets us back in "F mode" after processing
117096e55cc7SXin LI 	 * a non-abort signal (e.g. window-change).
117196e55cc7SXin LI 	 */
117296e55cc7SXin LI 	if (sigs && !ABORT_SIGS())
1173e2449719SXin LI 		return (until_hilite ? A_F_UNTIL_HILITE : A_F_FOREVER);
1174e2449719SXin LI 
117596e55cc7SXin LI 	return (A_NOACTION);
117696e55cc7SXin LI }
117796e55cc7SXin LI 
117896e55cc7SXin LI /*
1179a5f0fb15SPaul Saab  * Main command processor.
1180a5f0fb15SPaul Saab  * Accept and execute commands until a quit command.
1181a5f0fb15SPaul Saab  */
1182a5f0fb15SPaul Saab 	public void
1183b7780dbeSXin LI commands(VOID_PARAM)
1184a5f0fb15SPaul Saab {
11851ea31627SRobert Watson 	int c;
11861ea31627SRobert Watson 	int action;
11871ea31627SRobert Watson 	char *cbuf;
1188a5f0fb15SPaul Saab 	int newaction;
1189*2235c7feSXin LI 	int save_jump_sline;
1190a5f0fb15SPaul Saab 	int save_search_type;
1191a5f0fb15SPaul Saab 	char *extra;
1192a5f0fb15SPaul Saab 	char tbuf[2];
1193a5f0fb15SPaul Saab 	PARG parg;
1194a5f0fb15SPaul Saab 	IFILE old_ifile;
1195a5f0fb15SPaul Saab 	IFILE new_ifile;
11968fd4165cSPaul Saab 	char *tagfile;
1197a5f0fb15SPaul Saab 
1198a5f0fb15SPaul Saab 	search_type = SRCH_FORW;
1199a5f0fb15SPaul Saab 	wscroll = (sc_height + 1) / 2;
1200a5f0fb15SPaul Saab 	newaction = A_NOACTION;
1201a5f0fb15SPaul Saab 
1202a5f0fb15SPaul Saab 	for (;;)
1203a5f0fb15SPaul Saab 	{
1204b7780dbeSXin LI 		clear_mca();
1205a5f0fb15SPaul Saab 		cmd_accept();
1206a5f0fb15SPaul Saab 		number = 0;
120733096f16SXin LI 		curropt = NULL;
1208a5f0fb15SPaul Saab 
1209a5f0fb15SPaul Saab 		/*
1210a5f0fb15SPaul Saab 		 * See if any signals need processing.
1211a5f0fb15SPaul Saab 		 */
1212a5f0fb15SPaul Saab 		if (sigs)
1213a5f0fb15SPaul Saab 		{
1214a5f0fb15SPaul Saab 			psignals();
1215a5f0fb15SPaul Saab 			if (quitting)
1216a5f0fb15SPaul Saab 				quit(QUIT_SAVED_STATUS);
1217a5f0fb15SPaul Saab 		}
1218a5f0fb15SPaul Saab 
1219a5f0fb15SPaul Saab 		/*
1220a5f0fb15SPaul Saab 		 * See if window size changed, for systems that don't
1221a5f0fb15SPaul Saab 		 * generate SIGWINCH.
1222a5f0fb15SPaul Saab 		 */
1223a5f0fb15SPaul Saab 		check_winch();
1224a5f0fb15SPaul Saab 
1225a5f0fb15SPaul Saab 		/*
1226a5f0fb15SPaul Saab 		 * Display prompt and accept a character.
1227a5f0fb15SPaul Saab 		 */
1228a5f0fb15SPaul Saab 		cmd_reset();
1229a5f0fb15SPaul Saab 		prompt();
1230a5f0fb15SPaul Saab 		if (sigs)
1231a5f0fb15SPaul Saab 			continue;
1232a5f0fb15SPaul Saab 		if (newaction == A_NOACTION)
1233a5f0fb15SPaul Saab 			c = getcc();
1234a5f0fb15SPaul Saab 
1235a5f0fb15SPaul Saab 	again:
1236a5f0fb15SPaul Saab 		if (sigs)
1237a5f0fb15SPaul Saab 			continue;
1238a5f0fb15SPaul Saab 
1239a5f0fb15SPaul Saab 		if (newaction != A_NOACTION)
1240a5f0fb15SPaul Saab 		{
1241a5f0fb15SPaul Saab 			action = newaction;
1242a5f0fb15SPaul Saab 			newaction = A_NOACTION;
1243a5f0fb15SPaul Saab 		} else
1244a5f0fb15SPaul Saab 		{
1245a5f0fb15SPaul Saab 			/*
1246a5f0fb15SPaul Saab 			 * If we are in a multicharacter command, call mca_char.
1247a5f0fb15SPaul Saab 			 * Otherwise we call fcmd_decode to determine the
1248a5f0fb15SPaul Saab 			 * action to be performed.
1249a5f0fb15SPaul Saab 			 */
1250a5f0fb15SPaul Saab 			if (mca)
1251a5f0fb15SPaul Saab 				switch (mca_char(c))
1252a5f0fb15SPaul Saab 				{
1253a5f0fb15SPaul Saab 				case MCA_MORE:
1254a5f0fb15SPaul Saab 					/*
1255a5f0fb15SPaul Saab 					 * Need another character.
1256a5f0fb15SPaul Saab 					 */
1257a5f0fb15SPaul Saab 					c = getcc();
1258a5f0fb15SPaul Saab 					goto again;
1259a5f0fb15SPaul Saab 				case MCA_DONE:
1260a5f0fb15SPaul Saab 					/*
1261a5f0fb15SPaul Saab 					 * Command has been handled by mca_char.
1262a5f0fb15SPaul Saab 					 * Start clean with a prompt.
1263a5f0fb15SPaul Saab 					 */
1264a5f0fb15SPaul Saab 					continue;
1265a5f0fb15SPaul Saab 				case NO_MCA:
1266a5f0fb15SPaul Saab 					/*
1267a5f0fb15SPaul Saab 					 * Not a multi-char command
1268a5f0fb15SPaul Saab 					 * (at least, not anymore).
1269a5f0fb15SPaul Saab 					 */
1270a5f0fb15SPaul Saab 					break;
1271a5f0fb15SPaul Saab 				}
1272a5f0fb15SPaul Saab 
1273a5f0fb15SPaul Saab 			/*
1274a5f0fb15SPaul Saab 			 * Decode the command character and decide what to do.
1275a5f0fb15SPaul Saab 			 */
1276a5f0fb15SPaul Saab 			if (mca)
1277a5f0fb15SPaul Saab 			{
1278a5f0fb15SPaul Saab 				/*
1279a5f0fb15SPaul Saab 				 * We're in a multichar command.
1280a5f0fb15SPaul Saab 				 * Add the character to the command buffer
1281a5f0fb15SPaul Saab 				 * and display it on the screen.
1282a5f0fb15SPaul Saab 				 * If the user backspaces past the start
1283a5f0fb15SPaul Saab 				 * of the line, abort the command.
1284a5f0fb15SPaul Saab 				 */
1285a5f0fb15SPaul Saab 				if (cmd_char(c) == CC_QUIT || len_cmdbuf() == 0)
1286a5f0fb15SPaul Saab 					continue;
1287a5f0fb15SPaul Saab 				cbuf = get_cmdbuf();
1288a5f0fb15SPaul Saab 			} else
1289a5f0fb15SPaul Saab 			{
1290a5f0fb15SPaul Saab 				/*
1291a5f0fb15SPaul Saab 				 * Don't use cmd_char if we're starting fresh
1292a5f0fb15SPaul Saab 				 * at the beginning of a command, because we
1293a5f0fb15SPaul Saab 				 * don't want to echo the command until we know
1294a5f0fb15SPaul Saab 				 * it is a multichar command.  We also don't
1295a5f0fb15SPaul Saab 				 * want erase_char/kill_char to be treated
1296a5f0fb15SPaul Saab 				 * as line editing characters.
1297a5f0fb15SPaul Saab 				 */
1298a5f0fb15SPaul Saab 				tbuf[0] = c;
1299a5f0fb15SPaul Saab 				tbuf[1] = '\0';
1300a5f0fb15SPaul Saab 				cbuf = tbuf;
1301a5f0fb15SPaul Saab 			}
1302a5f0fb15SPaul Saab 			extra = NULL;
1303a5f0fb15SPaul Saab 			action = fcmd_decode(cbuf, &extra);
1304a5f0fb15SPaul Saab 			/*
1305a5f0fb15SPaul Saab 			 * If an "extra" string was returned,
1306a5f0fb15SPaul Saab 			 * process it as a string of command characters.
1307a5f0fb15SPaul Saab 			 */
1308a5f0fb15SPaul Saab 			if (extra != NULL)
1309a5f0fb15SPaul Saab 				ungetsc(extra);
1310a5f0fb15SPaul Saab 		}
1311a5f0fb15SPaul Saab 		/*
1312a5f0fb15SPaul Saab 		 * Clear the cmdbuf string.
1313a5f0fb15SPaul Saab 		 * (But not if we're in the prefix of a command,
1314a5f0fb15SPaul Saab 		 * because the partial command string is kept there.)
1315a5f0fb15SPaul Saab 		 */
1316a5f0fb15SPaul Saab 		if (action != A_PREFIX)
1317a5f0fb15SPaul Saab 			cmd_reset();
1318a5f0fb15SPaul Saab 
1319a5f0fb15SPaul Saab 		switch (action)
1320a5f0fb15SPaul Saab 		{
1321a5f0fb15SPaul Saab 		case A_DIGIT:
1322a5f0fb15SPaul Saab 			/*
1323a5f0fb15SPaul Saab 			 * First digit of a number.
1324a5f0fb15SPaul Saab 			 */
1325a5f0fb15SPaul Saab 			start_mca(A_DIGIT, ":", (void*)NULL, CF_QUIT_ON_ERASE);
1326a5f0fb15SPaul Saab 			goto again;
1327a5f0fb15SPaul Saab 
1328a5f0fb15SPaul Saab 		case A_F_WINDOW:
1329a5f0fb15SPaul Saab 			/*
1330a5f0fb15SPaul Saab 			 * Forward one window (and set the window size).
1331a5f0fb15SPaul Saab 			 */
1332a5f0fb15SPaul Saab 			if (number > 0)
13331ede1615STim J. Robbins 				swindow = (int) number;
1334a5f0fb15SPaul Saab 			/* FALLTHRU */
1335a5f0fb15SPaul Saab 		case A_F_SCREEN:
1336a5f0fb15SPaul Saab 			/*
1337a5f0fb15SPaul Saab 			 * Forward one screen.
1338a5f0fb15SPaul Saab 			 */
1339a5f0fb15SPaul Saab 			if (number <= 0)
1340a5f0fb15SPaul Saab 				number = get_swindow();
1341a5f0fb15SPaul Saab 			cmd_exec();
1342a5f0fb15SPaul Saab 			if (show_attn)
1343a5f0fb15SPaul Saab 				set_attnpos(bottompos);
13441ede1615STim J. Robbins 			forward((int) number, 0, 1);
1345a5f0fb15SPaul Saab 			break;
1346a5f0fb15SPaul Saab 
1347a5f0fb15SPaul Saab 		case A_B_WINDOW:
1348a5f0fb15SPaul Saab 			/*
1349a5f0fb15SPaul Saab 			 * Backward one window (and set the window size).
1350a5f0fb15SPaul Saab 			 */
1351a5f0fb15SPaul Saab 			if (number > 0)
13521ede1615STim J. Robbins 				swindow = (int) number;
1353a5f0fb15SPaul Saab 			/* FALLTHRU */
1354a5f0fb15SPaul Saab 		case A_B_SCREEN:
1355a5f0fb15SPaul Saab 			/*
1356a5f0fb15SPaul Saab 			 * Backward one screen.
1357a5f0fb15SPaul Saab 			 */
1358a5f0fb15SPaul Saab 			if (number <= 0)
1359a5f0fb15SPaul Saab 				number = get_swindow();
1360a5f0fb15SPaul Saab 			cmd_exec();
13611ede1615STim J. Robbins 			backward((int) number, 0, 1);
1362a5f0fb15SPaul Saab 			break;
1363a5f0fb15SPaul Saab 
1364a5f0fb15SPaul Saab 		case A_F_LINE:
1365a5f0fb15SPaul Saab 			/*
1366a5f0fb15SPaul Saab 			 * Forward N (default 1) line.
1367a5f0fb15SPaul Saab 			 */
1368a5f0fb15SPaul Saab 			if (number <= 0)
1369a5f0fb15SPaul Saab 				number = 1;
1370a5f0fb15SPaul Saab 			cmd_exec();
1371a5f0fb15SPaul Saab 			if (show_attn == OPT_ONPLUS && number > 1)
1372a5f0fb15SPaul Saab 				set_attnpos(bottompos);
13731ede1615STim J. Robbins 			forward((int) number, 0, 0);
1374a5f0fb15SPaul Saab 			break;
1375a5f0fb15SPaul Saab 
1376a5f0fb15SPaul Saab 		case A_B_LINE:
1377a5f0fb15SPaul Saab 			/*
1378a5f0fb15SPaul Saab 			 * Backward N (default 1) line.
1379a5f0fb15SPaul Saab 			 */
1380a5f0fb15SPaul Saab 			if (number <= 0)
1381a5f0fb15SPaul Saab 				number = 1;
1382a5f0fb15SPaul Saab 			cmd_exec();
13831ede1615STim J. Robbins 			backward((int) number, 0, 0);
1384a5f0fb15SPaul Saab 			break;
1385a5f0fb15SPaul Saab 
1386b7780dbeSXin LI 		case A_F_MOUSE:
1387b7780dbeSXin LI 			/*
1388b7780dbeSXin LI 			 * Forward wheel_lines lines.
1389b7780dbeSXin LI 			 */
1390b7780dbeSXin LI 			cmd_exec();
1391b7780dbeSXin LI 			forward(wheel_lines, 0, 0);
1392b7780dbeSXin LI 			break;
1393b7780dbeSXin LI 
1394b7780dbeSXin LI 		case A_B_MOUSE:
1395b7780dbeSXin LI 			/*
1396b7780dbeSXin LI 			 * Backward wheel_lines lines.
1397b7780dbeSXin LI 			 */
1398b7780dbeSXin LI 			cmd_exec();
1399b7780dbeSXin LI 			backward(wheel_lines, 0, 0);
1400b7780dbeSXin LI 			break;
1401b7780dbeSXin LI 
1402a5f0fb15SPaul Saab 		case A_FF_LINE:
1403a5f0fb15SPaul Saab 			/*
1404a5f0fb15SPaul Saab 			 * Force forward N (default 1) line.
1405a5f0fb15SPaul Saab 			 */
1406a5f0fb15SPaul Saab 			if (number <= 0)
1407a5f0fb15SPaul Saab 				number = 1;
1408a5f0fb15SPaul Saab 			cmd_exec();
1409a5f0fb15SPaul Saab 			if (show_attn == OPT_ONPLUS && number > 1)
1410a5f0fb15SPaul Saab 				set_attnpos(bottompos);
14111ede1615STim J. Robbins 			forward((int) number, 1, 0);
1412a5f0fb15SPaul Saab 			break;
1413a5f0fb15SPaul Saab 
1414a5f0fb15SPaul Saab 		case A_BF_LINE:
1415a5f0fb15SPaul Saab 			/*
1416a5f0fb15SPaul Saab 			 * Force backward N (default 1) line.
1417a5f0fb15SPaul Saab 			 */
1418a5f0fb15SPaul Saab 			if (number <= 0)
1419a5f0fb15SPaul Saab 				number = 1;
1420a5f0fb15SPaul Saab 			cmd_exec();
14211ede1615STim J. Robbins 			backward((int) number, 1, 0);
1422a5f0fb15SPaul Saab 			break;
1423a5f0fb15SPaul Saab 
1424a5f0fb15SPaul Saab 		case A_FF_SCREEN:
1425a5f0fb15SPaul Saab 			/*
1426a5f0fb15SPaul Saab 			 * Force forward one screen.
1427a5f0fb15SPaul Saab 			 */
1428a5f0fb15SPaul Saab 			if (number <= 0)
1429a5f0fb15SPaul Saab 				number = get_swindow();
1430a5f0fb15SPaul Saab 			cmd_exec();
1431a5f0fb15SPaul Saab 			if (show_attn == OPT_ONPLUS)
1432a5f0fb15SPaul Saab 				set_attnpos(bottompos);
14331ede1615STim J. Robbins 			forward((int) number, 1, 0);
1434a5f0fb15SPaul Saab 			break;
1435a5f0fb15SPaul Saab 
1436a5f0fb15SPaul Saab 		case A_F_FOREVER:
1437a5f0fb15SPaul Saab 			/*
1438a5f0fb15SPaul Saab 			 * Forward forever, ignoring EOF.
1439a5f0fb15SPaul Saab 			 */
1440a15691bfSXin LI 			if (show_attn)
1441a15691bfSXin LI 				set_attnpos(bottompos);
144296e55cc7SXin LI 			newaction = forw_loop(0);
1443a5f0fb15SPaul Saab 			break;
144496e55cc7SXin LI 
144596e55cc7SXin LI 		case A_F_UNTIL_HILITE:
144696e55cc7SXin LI 			newaction = forw_loop(1);
1447a5f0fb15SPaul Saab 			break;
1448a5f0fb15SPaul Saab 
1449a5f0fb15SPaul Saab 		case A_F_SCROLL:
1450a5f0fb15SPaul Saab 			/*
1451a5f0fb15SPaul Saab 			 * Forward N lines
1452a5f0fb15SPaul Saab 			 * (default same as last 'd' or 'u' command).
1453a5f0fb15SPaul Saab 			 */
1454a5f0fb15SPaul Saab 			if (number > 0)
14551ede1615STim J. Robbins 				wscroll = (int) number;
1456a5f0fb15SPaul Saab 			cmd_exec();
1457a5f0fb15SPaul Saab 			if (show_attn == OPT_ONPLUS)
1458a5f0fb15SPaul Saab 				set_attnpos(bottompos);
1459a5f0fb15SPaul Saab 			forward(wscroll, 0, 0);
1460a5f0fb15SPaul Saab 			break;
1461a5f0fb15SPaul Saab 
1462a5f0fb15SPaul Saab 		case A_B_SCROLL:
1463a5f0fb15SPaul Saab 			/*
1464a5f0fb15SPaul Saab 			 * Forward N lines
1465a5f0fb15SPaul Saab 			 * (default same as last 'd' or 'u' command).
1466a5f0fb15SPaul Saab 			 */
1467a5f0fb15SPaul Saab 			if (number > 0)
14681ede1615STim J. Robbins 				wscroll = (int) number;
1469a5f0fb15SPaul Saab 			cmd_exec();
1470a5f0fb15SPaul Saab 			backward(wscroll, 0, 0);
1471a5f0fb15SPaul Saab 			break;
1472a5f0fb15SPaul Saab 
1473a5f0fb15SPaul Saab 		case A_FREPAINT:
1474a5f0fb15SPaul Saab 			/*
1475a5f0fb15SPaul Saab 			 * Flush buffers, then repaint screen.
1476a5f0fb15SPaul Saab 			 * Don't flush the buffers on a pipe!
1477a5f0fb15SPaul Saab 			 */
1478423c5ce5SXin LI 			clear_buffers();
1479a5f0fb15SPaul Saab 			/* FALLTHRU */
1480a5f0fb15SPaul Saab 		case A_REPAINT:
1481a5f0fb15SPaul Saab 			/*
1482a5f0fb15SPaul Saab 			 * Repaint screen.
1483a5f0fb15SPaul Saab 			 */
1484a5f0fb15SPaul Saab 			cmd_exec();
1485a5f0fb15SPaul Saab 			repaint();
1486a5f0fb15SPaul Saab 			break;
1487a5f0fb15SPaul Saab 
1488a5f0fb15SPaul Saab 		case A_GOLINE:
1489a5f0fb15SPaul Saab 			/*
1490a5f0fb15SPaul Saab 			 * Go to line N, default beginning of file.
1491*2235c7feSXin LI 			 * If N <= 0, ignore jump_sline in order to avoid
1492*2235c7feSXin LI 			 * empty lines before the beginning of the file.
1493a5f0fb15SPaul Saab 			 */
1494*2235c7feSXin LI 			save_jump_sline = jump_sline;
1495a5f0fb15SPaul Saab 			if (number <= 0)
1496*2235c7feSXin LI 			{
1497a5f0fb15SPaul Saab 				number = 1;
1498*2235c7feSXin LI 				jump_sline = 0;
1499*2235c7feSXin LI 			}
1500a5f0fb15SPaul Saab 			cmd_exec();
1501a5f0fb15SPaul Saab 			jump_back(number);
1502*2235c7feSXin LI 			jump_sline = save_jump_sline;
1503a5f0fb15SPaul Saab 			break;
1504a5f0fb15SPaul Saab 
1505a5f0fb15SPaul Saab 		case A_PERCENT:
1506a5f0fb15SPaul Saab 			/*
1507a5f0fb15SPaul Saab 			 * Go to a specified percentage into the file.
1508a5f0fb15SPaul Saab 			 */
1509a5f0fb15SPaul Saab 			if (number < 0)
1510720c436cSXin LI 			{
1511a5f0fb15SPaul Saab 				number = 0;
1512720c436cSXin LI 				fraction = 0;
1513720c436cSXin LI 			}
1514b7780dbeSXin LI 			if (number > 100 || (number == 100 && fraction != 0))
1515720c436cSXin LI 			{
1516a5f0fb15SPaul Saab 				number = 100;
1517720c436cSXin LI 				fraction = 0;
1518720c436cSXin LI 			}
1519a5f0fb15SPaul Saab 			cmd_exec();
1520720c436cSXin LI 			jump_percent((int) number, fraction);
1521a5f0fb15SPaul Saab 			break;
1522a5f0fb15SPaul Saab 
1523a5f0fb15SPaul Saab 		case A_GOEND:
1524a5f0fb15SPaul Saab 			/*
1525a5f0fb15SPaul Saab 			 * Go to line N, default end of file.
1526a5f0fb15SPaul Saab 			 */
1527a5f0fb15SPaul Saab 			cmd_exec();
1528a5f0fb15SPaul Saab 			if (number <= 0)
1529a5f0fb15SPaul Saab 				jump_forw();
1530a5f0fb15SPaul Saab 			else
1531a5f0fb15SPaul Saab 				jump_back(number);
1532a5f0fb15SPaul Saab 			break;
1533a5f0fb15SPaul Saab 
1534a15691bfSXin LI 		case A_GOEND_BUF:
1535a15691bfSXin LI 			/*
1536a15691bfSXin LI 			 * Go to line N, default last buffered byte.
1537a15691bfSXin LI 			 */
1538a15691bfSXin LI 			cmd_exec();
1539a15691bfSXin LI 			if (number <= 0)
1540a15691bfSXin LI 				jump_forw_buffered();
1541a15691bfSXin LI 			else
1542a15691bfSXin LI 				jump_back(number);
1543a15691bfSXin LI 			break;
1544a15691bfSXin LI 
1545a5f0fb15SPaul Saab 		case A_GOPOS:
1546a5f0fb15SPaul Saab 			/*
1547a5f0fb15SPaul Saab 			 * Go to a specified byte position in the file.
1548a5f0fb15SPaul Saab 			 */
1549a5f0fb15SPaul Saab 			cmd_exec();
1550a5f0fb15SPaul Saab 			if (number < 0)
1551a5f0fb15SPaul Saab 				number = 0;
1552a5f0fb15SPaul Saab 			jump_line_loc((POSITION) number, jump_sline);
1553a5f0fb15SPaul Saab 			break;
1554a5f0fb15SPaul Saab 
1555a5f0fb15SPaul Saab 		case A_STAT:
1556a5f0fb15SPaul Saab 			/*
1557a5f0fb15SPaul Saab 			 * Print file name, etc.
1558a5f0fb15SPaul Saab 			 */
1559a5f0fb15SPaul Saab 			if (ch_getflags() & CH_HELPFILE)
1560a5f0fb15SPaul Saab 				break;
1561a5f0fb15SPaul Saab 			cmd_exec();
1562a5f0fb15SPaul Saab 			parg.p_string = eq_message();
1563a5f0fb15SPaul Saab 			error("%s", &parg);
1564a5f0fb15SPaul Saab 			break;
1565a5f0fb15SPaul Saab 
1566a5f0fb15SPaul Saab 		case A_VERSION:
1567a5f0fb15SPaul Saab 			/*
1568*2235c7feSXin LI 			 * Print version number.
1569a5f0fb15SPaul Saab 			 */
1570a5f0fb15SPaul Saab 			cmd_exec();
1571a5f0fb15SPaul Saab 			dispversion();
1572a5f0fb15SPaul Saab 			break;
1573a5f0fb15SPaul Saab 
1574a5f0fb15SPaul Saab 		case A_QUIT:
1575a5f0fb15SPaul Saab 			/*
1576a5f0fb15SPaul Saab 			 * Exit.
1577a5f0fb15SPaul Saab 			 */
1578a5f0fb15SPaul Saab 			if (curr_ifile != NULL_IFILE &&
1579a5f0fb15SPaul Saab 			    ch_getflags() & CH_HELPFILE)
1580a5f0fb15SPaul Saab 			{
1581a5f0fb15SPaul Saab 				/*
1582a5f0fb15SPaul Saab 				 * Quit while viewing the help file
1583a5f0fb15SPaul Saab 				 * just means return to viewing the
1584a5f0fb15SPaul Saab 				 * previous file.
1585a5f0fb15SPaul Saab 				 */
158689dd99dcSXin LI 				hshift = save_hshift;
1587a15691bfSXin LI 				bs_mode = save_bs_mode;
1588a5f0fb15SPaul Saab 				if (edit_prev(1) == 0)
1589a5f0fb15SPaul Saab 					break;
1590a5f0fb15SPaul Saab 			}
1591a5f0fb15SPaul Saab 			if (extra != NULL)
1592a5f0fb15SPaul Saab 				quit(*extra);
1593a5f0fb15SPaul Saab 			quit(QUIT_OK);
1594a5f0fb15SPaul Saab 			break;
1595a5f0fb15SPaul Saab 
1596a5f0fb15SPaul Saab /*
1597a5f0fb15SPaul Saab  * Define abbreviation for a commonly used sequence below.
1598a5f0fb15SPaul Saab  */
1599423c5ce5SXin LI #define DO_SEARCH() \
1600423c5ce5SXin LI 			if (number <= 0) number = 1;    \
1601a5f0fb15SPaul Saab 			mca_search();                   \
1602a5f0fb15SPaul Saab 			cmd_exec();                     \
1603a15691bfSXin LI 			multi_search((char *)NULL, (int) number, 0);
1604a5f0fb15SPaul Saab 
1605a5f0fb15SPaul Saab 
1606a5f0fb15SPaul Saab 		case A_F_SEARCH:
1607a5f0fb15SPaul Saab 			/*
1608a5f0fb15SPaul Saab 			 * Search forward for a pattern.
1609a5f0fb15SPaul Saab 			 * Get the first char of the pattern.
1610a5f0fb15SPaul Saab 			 */
1611a5f0fb15SPaul Saab 			search_type = SRCH_FORW;
1612a5f0fb15SPaul Saab 			if (number <= 0)
1613a5f0fb15SPaul Saab 				number = 1;
1614a5f0fb15SPaul Saab 			mca_search();
1615a5f0fb15SPaul Saab 			c = getcc();
1616a5f0fb15SPaul Saab 			goto again;
1617a5f0fb15SPaul Saab 
1618a5f0fb15SPaul Saab 		case A_B_SEARCH:
1619a5f0fb15SPaul Saab 			/*
1620a5f0fb15SPaul Saab 			 * Search backward for a pattern.
1621a5f0fb15SPaul Saab 			 * Get the first char of the pattern.
1622a5f0fb15SPaul Saab 			 */
1623a5f0fb15SPaul Saab 			search_type = SRCH_BACK;
1624a5f0fb15SPaul Saab 			if (number <= 0)
1625a5f0fb15SPaul Saab 				number = 1;
1626a5f0fb15SPaul Saab 			mca_search();
1627a5f0fb15SPaul Saab 			c = getcc();
1628a5f0fb15SPaul Saab 			goto again;
1629a5f0fb15SPaul Saab 
16307374caaaSXin LI 		case A_FILTER:
16317374caaaSXin LI #if HILITE_SEARCH
16327374caaaSXin LI 			search_type = SRCH_FORW | SRCH_FILTER;
16337374caaaSXin LI 			mca_search();
16347374caaaSXin LI 			c = getcc();
16357374caaaSXin LI 			goto again;
16367374caaaSXin LI #else
16377374caaaSXin LI 			error("Command not available", NULL_PARG);
16387374caaaSXin LI 			break;
16397374caaaSXin LI #endif
16407374caaaSXin LI 
1641a5f0fb15SPaul Saab 		case A_AGAIN_SEARCH:
1642a5f0fb15SPaul Saab 			/*
1643a5f0fb15SPaul Saab 			 * Repeat previous search.
1644a5f0fb15SPaul Saab 			 */
1645a5f0fb15SPaul Saab 			DO_SEARCH();
1646a5f0fb15SPaul Saab 			break;
1647a5f0fb15SPaul Saab 
1648a5f0fb15SPaul Saab 		case A_T_AGAIN_SEARCH:
1649a5f0fb15SPaul Saab 			/*
1650a5f0fb15SPaul Saab 			 * Repeat previous search, multiple files.
1651a5f0fb15SPaul Saab 			 */
1652a5f0fb15SPaul Saab 			search_type |= SRCH_PAST_EOF;
1653a5f0fb15SPaul Saab 			DO_SEARCH();
1654a5f0fb15SPaul Saab 			break;
1655a5f0fb15SPaul Saab 
1656a5f0fb15SPaul Saab 		case A_REVERSE_SEARCH:
1657a5f0fb15SPaul Saab 			/*
1658a5f0fb15SPaul Saab 			 * Repeat previous search, in reverse direction.
1659a5f0fb15SPaul Saab 			 */
1660a5f0fb15SPaul Saab 			save_search_type = search_type;
1661a5f0fb15SPaul Saab 			search_type = SRCH_REVERSE(search_type);
1662a5f0fb15SPaul Saab 			DO_SEARCH();
1663a5f0fb15SPaul Saab 			search_type = save_search_type;
1664a5f0fb15SPaul Saab 			break;
1665a5f0fb15SPaul Saab 
1666a5f0fb15SPaul Saab 		case A_T_REVERSE_SEARCH:
1667a5f0fb15SPaul Saab 			/*
1668a5f0fb15SPaul Saab 			 * Repeat previous search,
1669a5f0fb15SPaul Saab 			 * multiple files in reverse direction.
1670a5f0fb15SPaul Saab 			 */
1671a5f0fb15SPaul Saab 			save_search_type = search_type;
1672a5f0fb15SPaul Saab 			search_type = SRCH_REVERSE(search_type);
1673a5f0fb15SPaul Saab 			search_type |= SRCH_PAST_EOF;
1674a5f0fb15SPaul Saab 			DO_SEARCH();
1675a5f0fb15SPaul Saab 			search_type = save_search_type;
1676a5f0fb15SPaul Saab 			break;
1677a5f0fb15SPaul Saab 
1678a5f0fb15SPaul Saab 		case A_UNDO_SEARCH:
1679*2235c7feSXin LI 		case A_CLR_SEARCH:
1680b2ea2440SXin LI 			/*
1681b2ea2440SXin LI 			 * Clear search string highlighting.
1682b2ea2440SXin LI 			 */
1683*2235c7feSXin LI 			undo_search(action == A_CLR_SEARCH);
1684a5f0fb15SPaul Saab 			break;
1685a5f0fb15SPaul Saab 
1686a5f0fb15SPaul Saab 		case A_HELP:
1687a5f0fb15SPaul Saab 			/*
1688a5f0fb15SPaul Saab 			 * Help.
1689a5f0fb15SPaul Saab 			 */
1690a5f0fb15SPaul Saab 			if (ch_getflags() & CH_HELPFILE)
1691a5f0fb15SPaul Saab 				break;
1692a5f0fb15SPaul Saab 			cmd_exec();
169389dd99dcSXin LI 			save_hshift = hshift;
169489dd99dcSXin LI 			hshift = 0;
1695a15691bfSXin LI 			save_bs_mode = bs_mode;
1696a15691bfSXin LI 			bs_mode = BS_SPECIAL;
1697a5f0fb15SPaul Saab 			(void) edit(FAKE_HELPFILE);
1698a5f0fb15SPaul Saab 			break;
1699a5f0fb15SPaul Saab 
1700a5f0fb15SPaul Saab 		case A_EXAMINE:
1701a5f0fb15SPaul Saab 			/*
1702a5f0fb15SPaul Saab 			 * Edit a new file.  Get the filename.
1703a5f0fb15SPaul Saab 			 */
1704b2ea2440SXin LI #if EXAMINE
1705b2ea2440SXin LI 			if (!secure)
1706a5f0fb15SPaul Saab 			{
1707dd3bd0edSDimitry Andric 				start_mca(A_EXAMINE, "Examine: ", ml_examine, 0);
1708a5f0fb15SPaul Saab 				c = getcc();
1709a5f0fb15SPaul Saab 				goto again;
1710b2ea2440SXin LI 			}
1711b2ea2440SXin LI #endif
1712a5f0fb15SPaul Saab 			error("Command not available", NULL_PARG);
1713a5f0fb15SPaul Saab 			break;
1714a5f0fb15SPaul Saab 
1715a5f0fb15SPaul Saab 		case A_VISUAL:
1716a5f0fb15SPaul Saab 			/*
1717a5f0fb15SPaul Saab 			 * Invoke an editor on the input file.
1718a5f0fb15SPaul Saab 			 */
1719a5f0fb15SPaul Saab #if EDITOR
1720b2ea2440SXin LI 			if (!secure)
1721a5f0fb15SPaul Saab 			{
1722a5f0fb15SPaul Saab 				if (ch_getflags() & CH_HELPFILE)
1723a5f0fb15SPaul Saab 					break;
1724a5f0fb15SPaul Saab 				if (strcmp(get_filename(curr_ifile), "-") == 0)
1725a5f0fb15SPaul Saab 				{
1726a5f0fb15SPaul Saab 					error("Cannot edit standard input", NULL_PARG);
1727a5f0fb15SPaul Saab 					break;
1728a5f0fb15SPaul Saab 				}
1729b2ea2440SXin LI 				if (get_altfilename(curr_ifile) != NULL)
1730a5f0fb15SPaul Saab 				{
173189dd99dcSXin LI 					error("WARNING: This file was viewed via LESSOPEN",
1732a5f0fb15SPaul Saab 						NULL_PARG);
1733a5f0fb15SPaul Saab 				}
1734dd3bd0edSDimitry Andric 				start_mca(A_SHELL, "!", ml_shell, 0);
1735a5f0fb15SPaul Saab 				/*
1736a5f0fb15SPaul Saab 				 * Expand the editor prototype string
1737a5f0fb15SPaul Saab 				 * and pass it to the system to execute.
1738a5f0fb15SPaul Saab 				 * (Make sure the screen is displayed so the
1739a5f0fb15SPaul Saab 				 * expansion of "+%lm" works.)
1740a5f0fb15SPaul Saab 				 */
1741a5f0fb15SPaul Saab 				make_display();
1742a5f0fb15SPaul Saab 				cmd_exec();
1743a5f0fb15SPaul Saab 				lsystem(pr_expand(editproto, 0), (char*)NULL);
1744a5f0fb15SPaul Saab 				break;
1745b2ea2440SXin LI 			}
1746b2ea2440SXin LI #endif
1747a5f0fb15SPaul Saab 			error("Command not available", NULL_PARG);
1748a5f0fb15SPaul Saab 			break;
1749a5f0fb15SPaul Saab 
1750a5f0fb15SPaul Saab 		case A_NEXT_FILE:
1751a5f0fb15SPaul Saab 			/*
1752a5f0fb15SPaul Saab 			 * Examine next file.
1753a5f0fb15SPaul Saab 			 */
17541ede1615STim J. Robbins #if TAGS
17558fd4165cSPaul Saab 			if (ntags())
17568fd4165cSPaul Saab 			{
17578fd4165cSPaul Saab 				error("No next file", NULL_PARG);
17588fd4165cSPaul Saab 				break;
17598fd4165cSPaul Saab 			}
17601ede1615STim J. Robbins #endif
1761a5f0fb15SPaul Saab 			if (number <= 0)
1762a5f0fb15SPaul Saab 				number = 1;
17631ede1615STim J. Robbins 			if (edit_next((int) number))
1764a5f0fb15SPaul Saab 			{
17657374caaaSXin LI 				if (get_quit_at_eof() && eof_displayed() &&
1766a5f0fb15SPaul Saab 				    !(ch_getflags() & CH_HELPFILE))
1767a5f0fb15SPaul Saab 					quit(QUIT_OK);
1768a5f0fb15SPaul Saab 				parg.p_string = (number > 1) ? "(N-th) " : "";
1769a5f0fb15SPaul Saab 				error("No %snext file", &parg);
1770a5f0fb15SPaul Saab 			}
1771a5f0fb15SPaul Saab 			break;
1772a5f0fb15SPaul Saab 
1773a5f0fb15SPaul Saab 		case A_PREV_FILE:
1774a5f0fb15SPaul Saab 			/*
1775a5f0fb15SPaul Saab 			 * Examine previous file.
1776a5f0fb15SPaul Saab 			 */
17771ede1615STim J. Robbins #if TAGS
17788fd4165cSPaul Saab 			if (ntags())
17798fd4165cSPaul Saab 			{
17808fd4165cSPaul Saab 				error("No previous file", NULL_PARG);
17818fd4165cSPaul Saab 				break;
17828fd4165cSPaul Saab 			}
17831ede1615STim J. Robbins #endif
1784a5f0fb15SPaul Saab 			if (number <= 0)
1785a5f0fb15SPaul Saab 				number = 1;
17861ede1615STim J. Robbins 			if (edit_prev((int) number))
1787a5f0fb15SPaul Saab 			{
1788a5f0fb15SPaul Saab 				parg.p_string = (number > 1) ? "(N-th) " : "";
1789a5f0fb15SPaul Saab 				error("No %sprevious file", &parg);
1790a5f0fb15SPaul Saab 			}
1791a5f0fb15SPaul Saab 			break;
1792a5f0fb15SPaul Saab 
17938fd4165cSPaul Saab 		case A_NEXT_TAG:
1794b2ea2440SXin LI 			/*
1795b2ea2440SXin LI 			 * Jump to the next tag in the current tag list.
1796b2ea2440SXin LI 			 */
17971ede1615STim J. Robbins #if TAGS
17988fd4165cSPaul Saab 			if (number <= 0)
17998fd4165cSPaul Saab 				number = 1;
18001ede1615STim J. Robbins 			tagfile = nexttag((int) number);
18018fd4165cSPaul Saab 			if (tagfile == NULL)
18028fd4165cSPaul Saab 			{
18038fd4165cSPaul Saab 				error("No next tag", NULL_PARG);
18048fd4165cSPaul Saab 				break;
18058fd4165cSPaul Saab 			}
1806b2ea2440SXin LI 			cmd_exec();
18078fd4165cSPaul Saab 			if (edit(tagfile) == 0)
18088fd4165cSPaul Saab 			{
18098fd4165cSPaul Saab 				POSITION pos = tagsearch();
18108fd4165cSPaul Saab 				if (pos != NULL_POSITION)
18118fd4165cSPaul Saab 					jump_loc(pos, jump_sline);
18128fd4165cSPaul Saab 			}
18131ede1615STim J. Robbins #else
18141ede1615STim J. Robbins 			error("Command not available", NULL_PARG);
18151ede1615STim J. Robbins #endif
18168fd4165cSPaul Saab 			break;
18178fd4165cSPaul Saab 
18188fd4165cSPaul Saab 		case A_PREV_TAG:
1819b2ea2440SXin LI 			/*
1820b2ea2440SXin LI 			 * Jump to the previous tag in the current tag list.
1821b2ea2440SXin LI 			 */
18221ede1615STim J. Robbins #if TAGS
18238fd4165cSPaul Saab 			if (number <= 0)
18248fd4165cSPaul Saab 				number = 1;
18251ede1615STim J. Robbins 			tagfile = prevtag((int) number);
18268fd4165cSPaul Saab 			if (tagfile == NULL)
18278fd4165cSPaul Saab 			{
18288fd4165cSPaul Saab 				error("No previous tag", NULL_PARG);
18298fd4165cSPaul Saab 				break;
18308fd4165cSPaul Saab 			}
1831b2ea2440SXin LI 			cmd_exec();
18328fd4165cSPaul Saab 			if (edit(tagfile) == 0)
18338fd4165cSPaul Saab 			{
18348fd4165cSPaul Saab 				POSITION pos = tagsearch();
18358fd4165cSPaul Saab 				if (pos != NULL_POSITION)
18368fd4165cSPaul Saab 					jump_loc(pos, jump_sline);
18378fd4165cSPaul Saab 			}
18381ede1615STim J. Robbins #else
18391ede1615STim J. Robbins 			error("Command not available", NULL_PARG);
18401ede1615STim J. Robbins #endif
18418fd4165cSPaul Saab 			break;
18428fd4165cSPaul Saab 
1843a5f0fb15SPaul Saab 		case A_INDEX_FILE:
1844a5f0fb15SPaul Saab 			/*
1845a5f0fb15SPaul Saab 			 * Examine a particular file.
1846a5f0fb15SPaul Saab 			 */
1847a5f0fb15SPaul Saab 			if (number <= 0)
1848a5f0fb15SPaul Saab 				number = 1;
18491ede1615STim J. Robbins 			if (edit_index((int) number))
1850a5f0fb15SPaul Saab 				error("No such file", NULL_PARG);
1851a5f0fb15SPaul Saab 			break;
1852a5f0fb15SPaul Saab 
1853a5f0fb15SPaul Saab 		case A_REMOVE_FILE:
1854b2ea2440SXin LI 			/*
1855b2ea2440SXin LI 			 * Remove a file from the input file list.
1856b2ea2440SXin LI 			 */
1857a5f0fb15SPaul Saab 			if (ch_getflags() & CH_HELPFILE)
1858a5f0fb15SPaul Saab 				break;
1859a5f0fb15SPaul Saab 			old_ifile = curr_ifile;
1860a5f0fb15SPaul Saab 			new_ifile = getoff_ifile(curr_ifile);
1861a5f0fb15SPaul Saab 			if (new_ifile == NULL_IFILE)
1862a5f0fb15SPaul Saab 			{
1863a5f0fb15SPaul Saab 				bell();
1864a5f0fb15SPaul Saab 				break;
1865a5f0fb15SPaul Saab 			}
1866a5f0fb15SPaul Saab 			if (edit_ifile(new_ifile) != 0)
1867a5f0fb15SPaul Saab 			{
1868a5f0fb15SPaul Saab 				reedit_ifile(old_ifile);
1869a5f0fb15SPaul Saab 				break;
1870a5f0fb15SPaul Saab 			}
1871a5f0fb15SPaul Saab 			del_ifile(old_ifile);
1872a5f0fb15SPaul Saab 			break;
1873a5f0fb15SPaul Saab 
1874a5f0fb15SPaul Saab 		case A_OPT_TOGGLE:
1875b2ea2440SXin LI 			/*
1876b2ea2440SXin LI 			 * Change the setting of an  option.
1877b2ea2440SXin LI 			 */
1878a5f0fb15SPaul Saab 			optflag = OPT_TOGGLE;
1879a5f0fb15SPaul Saab 			optgetname = FALSE;
1880a5f0fb15SPaul Saab 			mca_opt_toggle();
1881a5f0fb15SPaul Saab 			c = getcc();
18826f26c71dSXin LI 			cbuf = opt_toggle_disallowed(c);
18836f26c71dSXin LI 			if (cbuf != NULL)
18846f26c71dSXin LI 			{
18856f26c71dSXin LI 				error(cbuf, NULL_PARG);
18866f26c71dSXin LI 				break;
18876f26c71dSXin LI 			}
1888a5f0fb15SPaul Saab 			goto again;
1889a5f0fb15SPaul Saab 
1890a5f0fb15SPaul Saab 		case A_DISP_OPTION:
1891a5f0fb15SPaul Saab 			/*
1892b2ea2440SXin LI 			 * Report the setting of an option.
1893a5f0fb15SPaul Saab 			 */
1894a5f0fb15SPaul Saab 			optflag = OPT_NO_TOGGLE;
1895a5f0fb15SPaul Saab 			optgetname = FALSE;
1896a5f0fb15SPaul Saab 			mca_opt_toggle();
1897a5f0fb15SPaul Saab 			c = getcc();
1898a5f0fb15SPaul Saab 			goto again;
1899a5f0fb15SPaul Saab 
1900a5f0fb15SPaul Saab 		case A_FIRSTCMD:
1901a5f0fb15SPaul Saab 			/*
1902a5f0fb15SPaul Saab 			 * Set an initial command for new files.
1903a5f0fb15SPaul Saab 			 */
1904a5f0fb15SPaul Saab 			start_mca(A_FIRSTCMD, "+", (void*)NULL, 0);
1905a5f0fb15SPaul Saab 			c = getcc();
1906a5f0fb15SPaul Saab 			goto again;
1907a5f0fb15SPaul Saab 
1908a5f0fb15SPaul Saab 		case A_SHELL:
1909a5f0fb15SPaul Saab 			/*
1910a5f0fb15SPaul Saab 			 * Shell escape.
1911a5f0fb15SPaul Saab 			 */
1912a5f0fb15SPaul Saab #if SHELL_ESCAPE
1913b2ea2440SXin LI 			if (!secure)
1914a5f0fb15SPaul Saab 			{
1915dd3bd0edSDimitry Andric 				start_mca(A_SHELL, "!", ml_shell, 0);
1916a5f0fb15SPaul Saab 				c = getcc();
1917a5f0fb15SPaul Saab 				goto again;
1918b2ea2440SXin LI 			}
1919b2ea2440SXin LI #endif
1920a5f0fb15SPaul Saab 			error("Command not available", NULL_PARG);
1921a5f0fb15SPaul Saab 			break;
1922a5f0fb15SPaul Saab 
1923a5f0fb15SPaul Saab 		case A_SETMARK:
1924b2ea2440SXin LI 		case A_SETMARKBOT:
1925a5f0fb15SPaul Saab 			/*
1926a5f0fb15SPaul Saab 			 * Set a mark.
1927a5f0fb15SPaul Saab 			 */
1928a5f0fb15SPaul Saab 			if (ch_getflags() & CH_HELPFILE)
1929a5f0fb15SPaul Saab 				break;
1930b2ea2440SXin LI 			start_mca(A_SETMARK, "set mark: ", (void*)NULL, 0);
1931a5f0fb15SPaul Saab 			c = getcc();
1932b2ea2440SXin LI 			if (is_erase_char(c) || is_newline_char(c))
1933a5f0fb15SPaul Saab 				break;
1934b2ea2440SXin LI 			setmark(c, action == A_SETMARKBOT ? BOTTOM : TOP);
1935b2ea2440SXin LI 			repaint();
1936b2ea2440SXin LI 			break;
1937b2ea2440SXin LI 
1938b2ea2440SXin LI 		case A_CLRMARK:
1939b2ea2440SXin LI 			/*
1940b2ea2440SXin LI 			 * Clear a mark.
1941b2ea2440SXin LI 			 */
1942b2ea2440SXin LI 			start_mca(A_CLRMARK, "clear mark: ", (void*)NULL, 0);
1943b2ea2440SXin LI 			c = getcc();
1944b2ea2440SXin LI 			if (is_erase_char(c) || is_newline_char(c))
1945b2ea2440SXin LI 				break;
1946b2ea2440SXin LI 			clrmark(c);
1947b2ea2440SXin LI 			repaint();
1948a5f0fb15SPaul Saab 			break;
1949a5f0fb15SPaul Saab 
1950a5f0fb15SPaul Saab 		case A_GOMARK:
1951a5f0fb15SPaul Saab 			/*
1952b2ea2440SXin LI 			 * Jump to a marked position.
1953a5f0fb15SPaul Saab 			 */
1954a5f0fb15SPaul Saab 			start_mca(A_GOMARK, "goto mark: ", (void*)NULL, 0);
1955a5f0fb15SPaul Saab 			c = getcc();
1956b2ea2440SXin LI 			if (is_erase_char(c) || is_newline_char(c))
1957a5f0fb15SPaul Saab 				break;
19587374caaaSXin LI 			cmd_exec();
1959a5f0fb15SPaul Saab 			gomark(c);
1960a5f0fb15SPaul Saab 			break;
1961a5f0fb15SPaul Saab 
1962a5f0fb15SPaul Saab 		case A_PIPE:
1963b2ea2440SXin LI 			/*
1964b2ea2440SXin LI 			 * Write part of the input to a pipe to a shell command.
1965b2ea2440SXin LI 			 */
1966a5f0fb15SPaul Saab #if PIPEC
1967b2ea2440SXin LI 			if (!secure)
1968a5f0fb15SPaul Saab 			{
1969a5f0fb15SPaul Saab 				start_mca(A_PIPE, "|mark: ", (void*)NULL, 0);
1970a5f0fb15SPaul Saab 				c = getcc();
1971b2ea2440SXin LI 				if (is_erase_char(c))
1972a5f0fb15SPaul Saab 					break;
1973b2ea2440SXin LI 				if (is_newline_char(c))
1974a5f0fb15SPaul Saab 					c = '.';
1975a5f0fb15SPaul Saab 				if (badmark(c))
1976a5f0fb15SPaul Saab 					break;
1977a5f0fb15SPaul Saab 				pipec = c;
1978dd3bd0edSDimitry Andric 				start_mca(A_PIPE, "!", ml_shell, 0);
1979a5f0fb15SPaul Saab 				c = getcc();
1980a5f0fb15SPaul Saab 				goto again;
1981b2ea2440SXin LI 			}
1982b2ea2440SXin LI #endif
1983a5f0fb15SPaul Saab 			error("Command not available", NULL_PARG);
1984a5f0fb15SPaul Saab 			break;
1985a5f0fb15SPaul Saab 
1986a5f0fb15SPaul Saab 		case A_B_BRACKET:
1987a5f0fb15SPaul Saab 		case A_F_BRACKET:
1988a5f0fb15SPaul Saab 			start_mca(action, "Brackets: ", (void*)NULL, 0);
1989a5f0fb15SPaul Saab 			c = getcc();
1990a5f0fb15SPaul Saab 			goto again;
1991a5f0fb15SPaul Saab 
1992a5f0fb15SPaul Saab 		case A_LSHIFT:
1993b2ea2440SXin LI 			/*
1994b2ea2440SXin LI 			 * Shift view left.
1995b2ea2440SXin LI 			 */
19968fd4165cSPaul Saab 			if (number > 0)
19978fd4165cSPaul Saab 				shift_count = number;
19988fd4165cSPaul Saab 			else
199915596da4SPaul Saab 				number = (shift_count > 0) ?
200015596da4SPaul Saab 					shift_count : sc_width / 2;
2001a5f0fb15SPaul Saab 			if (number > hshift)
2002a5f0fb15SPaul Saab 				number = hshift;
2003a5f0fb15SPaul Saab 			hshift -= number;
2004a5f0fb15SPaul Saab 			screen_trashed = 1;
2005a5f0fb15SPaul Saab 			break;
2006a5f0fb15SPaul Saab 
2007a5f0fb15SPaul Saab 		case A_RSHIFT:
2008b2ea2440SXin LI 			/*
2009b2ea2440SXin LI 			 * Shift view right.
2010b2ea2440SXin LI 			 */
20118fd4165cSPaul Saab 			if (number > 0)
20128fd4165cSPaul Saab 				shift_count = number;
20138fd4165cSPaul Saab 			else
201415596da4SPaul Saab 				number = (shift_count > 0) ?
201515596da4SPaul Saab 					shift_count : sc_width / 2;
2016a5f0fb15SPaul Saab 			hshift += number;
2017a5f0fb15SPaul Saab 			screen_trashed = 1;
2018a5f0fb15SPaul Saab 			break;
2019a5f0fb15SPaul Saab 
2020f6b74a7dSXin LI 		case A_LLSHIFT:
2021b2ea2440SXin LI 			/*
2022b2ea2440SXin LI 			 * Shift view left to margin.
2023b2ea2440SXin LI 			 */
2024f6b74a7dSXin LI 			hshift = 0;
2025f6b74a7dSXin LI 			screen_trashed = 1;
2026f6b74a7dSXin LI 			break;
2027f6b74a7dSXin LI 
2028f6b74a7dSXin LI 		case A_RRSHIFT:
2029b2ea2440SXin LI 			/*
2030b2ea2440SXin LI 			 * Shift view right to view rightmost char on screen.
2031b2ea2440SXin LI 			 */
2032f6b74a7dSXin LI 			hshift = rrshift();
2033f6b74a7dSXin LI 			screen_trashed = 1;
2034f6b74a7dSXin LI 			break;
2035f6b74a7dSXin LI 
2036a5f0fb15SPaul Saab 		case A_PREFIX:
2037a5f0fb15SPaul Saab 			/*
2038a5f0fb15SPaul Saab 			 * The command is incomplete (more chars are needed).
2039a5f0fb15SPaul Saab 			 * Display the current char, so the user knows
2040a5f0fb15SPaul Saab 			 * what's going on, and get another character.
2041a5f0fb15SPaul Saab 			 */
2042a5f0fb15SPaul Saab 			if (mca != A_PREFIX)
2043a5f0fb15SPaul Saab 			{
2044a5f0fb15SPaul Saab 				cmd_reset();
2045a5f0fb15SPaul Saab 				start_mca(A_PREFIX, " ", (void*)NULL,
2046a5f0fb15SPaul Saab 					CF_QUIT_ON_ERASE);
2047a5f0fb15SPaul Saab 				(void) cmd_char(c);
2048a5f0fb15SPaul Saab 			}
2049a5f0fb15SPaul Saab 			c = getcc();
2050a5f0fb15SPaul Saab 			goto again;
2051a5f0fb15SPaul Saab 
2052a5f0fb15SPaul Saab 		case A_NOACTION:
2053a5f0fb15SPaul Saab 			break;
2054a5f0fb15SPaul Saab 
2055a5f0fb15SPaul Saab 		default:
2056a5f0fb15SPaul Saab 			bell();
2057a5f0fb15SPaul Saab 			break;
2058a5f0fb15SPaul Saab 		}
2059a5f0fb15SPaul Saab 	}
2060a5f0fb15SPaul Saab }
2061