xref: /freebsd/contrib/less/command.c (revision c77c488926555ca344ae3a417544cf7a720e1de1)
1a8f92a7cSPaul Saab /* $FreeBSD$ */
2a5f0fb15SPaul Saab /*
3*c77c4889SXin LI  * Copyright (C) 1984-2024  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;
27d713e089SXin LI extern int one_screen;
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 hshift;
38a15691bfSXin LI extern int bs_mode;
39d713e089SXin LI extern int proc_backspace;
40a5f0fb15SPaul Saab extern int show_attn;
41720c436cSXin LI extern int less_is_more;
4296e55cc7SXin LI extern POSITION highest_hilite;
43a5f0fb15SPaul Saab extern char *every_first_cmd;
44a5f0fb15SPaul Saab extern char version[];
45a5f0fb15SPaul Saab extern struct scrpos initial_scrpos;
46a5f0fb15SPaul Saab extern IFILE curr_ifile;
47f6b74a7dSXin LI extern void *ml_search;
48f6b74a7dSXin LI extern void *ml_examine;
49b7780dbeSXin LI extern int wheel_lines;
5095270f73SXin LI extern int def_search_type;
51*c77c4889SXin LI extern lbool search_wrapped;
52a5f0fb15SPaul Saab #if SHELL_ESCAPE || PIPEC
53f6b74a7dSXin LI extern void *ml_shell;
54a5f0fb15SPaul Saab #endif
55a5f0fb15SPaul Saab #if EDITOR
56*c77c4889SXin LI extern constant char *editproto;
57a5f0fb15SPaul Saab #endif
58*c77c4889SXin LI #if OSC8_LINK
59*c77c4889SXin LI extern char *osc8_uri;
60*c77c4889SXin LI #endif
6115596da4SPaul Saab extern int shift_count;
62720c436cSXin LI extern int forw_prompt;
632235c7feSXin LI extern int incr_search;
64d713e089SXin LI extern int full_screen;
65b7780dbeSXin LI #if MSDOS_COMPILER==WIN32C
66b7780dbeSXin LI extern int utf_mode;
67*c77c4889SXin LI extern unsigned less_acp;
68b7780dbeSXin LI #endif
69a5f0fb15SPaul Saab 
70a5f0fb15SPaul Saab #if SHELL_ESCAPE
71a5f0fb15SPaul Saab static char *shellcmd = NULL;   /* For holding last shell command for "!!" */
72a5f0fb15SPaul Saab #endif
73a5f0fb15SPaul Saab static int mca;                 /* The multicharacter command (action) */
74a5f0fb15SPaul Saab static int search_type;         /* The previous type of search */
75d713e089SXin LI static int last_search_type;    /* Type of last executed search */
761ede1615STim J. Robbins static LINENUM number;          /* The number typed by the user */
77720c436cSXin LI static long fraction;           /* The fractional part of the number */
7833096f16SXin LI static struct loption *curropt;
7933096f16SXin LI static int opt_lower;
80a5f0fb15SPaul Saab static int optflag;
81*c77c4889SXin LI static lbool optgetname;
82a5f0fb15SPaul Saab static POSITION bottompos;
8389dd99dcSXin LI static int save_hshift;
84a15691bfSXin LI static int save_bs_mode;
85d713e089SXin LI static int save_proc_backspace;
86*c77c4889SXin LI static int screen_trashed_value = 0;
87*c77c4889SXin LI static lbool literal_char = FALSE;
88a5f0fb15SPaul Saab #if PIPEC
89a5f0fb15SPaul Saab static char pipec;
90a5f0fb15SPaul Saab #endif
91a5f0fb15SPaul Saab 
92b2ea2440SXin LI /* Stack of ungotten chars (via ungetcc) */
9333096f16SXin LI struct ungot {
9433096f16SXin LI 	struct ungot *ug_next;
95*c77c4889SXin LI 	char ug_char;
96*c77c4889SXin LI 	lbool ug_end_command;
9733096f16SXin LI };
9833096f16SXin LI static struct ungot* ungot = NULL;
9933096f16SXin LI 
100*c77c4889SXin LI static void multi_search(constant char *pattern, int n, int silent);
101a5f0fb15SPaul Saab 
102a5f0fb15SPaul Saab /*
103720c436cSXin LI  * Move the cursor to start of prompt line before executing a command.
104a5f0fb15SPaul Saab  * This looks nicer if the command takes a long time before
105a5f0fb15SPaul Saab  * updating the screen.
106a5f0fb15SPaul Saab  */
107d713e089SXin LI static void cmd_exec(void)
108a5f0fb15SPaul Saab {
109a5f0fb15SPaul Saab 	clear_attn();
110aa22b8b6SXin LI 	clear_bot();
111a5f0fb15SPaul Saab 	flush();
112a5f0fb15SPaul Saab }
113a5f0fb15SPaul Saab 
114a5f0fb15SPaul Saab /*
115b7780dbeSXin LI  * Indicate we are reading a multi-character command.
116b7780dbeSXin LI  */
117d713e089SXin LI static void set_mca(int action)
118b7780dbeSXin LI {
119b7780dbeSXin LI 	mca = action;
120b7780dbeSXin LI 	clear_bot();
121b7780dbeSXin LI 	clear_cmd();
122b7780dbeSXin LI }
123b7780dbeSXin LI 
124b7780dbeSXin LI /*
125b7780dbeSXin LI  * Indicate we are not reading a multi-character command.
126b7780dbeSXin LI  */
127d713e089SXin LI static void clear_mca(void)
128b7780dbeSXin LI {
129b7780dbeSXin LI 	if (mca == 0)
130b7780dbeSXin LI 		return;
131b7780dbeSXin LI 	mca = 0;
132b7780dbeSXin LI }
133b7780dbeSXin LI 
134b7780dbeSXin LI /*
135a5f0fb15SPaul Saab  * Set up the display to start a new multi-character command.
136a5f0fb15SPaul Saab  */
137d713e089SXin LI static void start_mca(int action, constant char *prompt, void *mlist, int cmdflags)
138a5f0fb15SPaul Saab {
139b7780dbeSXin LI 	set_mca(action);
140a5f0fb15SPaul Saab 	cmd_putstr(prompt);
141a5f0fb15SPaul Saab 	set_mlist(mlist, cmdflags);
142a5f0fb15SPaul Saab }
143a5f0fb15SPaul Saab 
144d713e089SXin LI public int in_mca(void)
145a5f0fb15SPaul Saab {
146a5f0fb15SPaul Saab 	return (mca != 0 && mca != A_PREFIX);
147a5f0fb15SPaul Saab }
148a5f0fb15SPaul Saab 
149a5f0fb15SPaul Saab /*
150a5f0fb15SPaul Saab  * Set up the display to start a new search command.
151a5f0fb15SPaul Saab  */
152d713e089SXin LI static void mca_search1(void)
153a5f0fb15SPaul Saab {
154d713e089SXin LI 	int i;
155d713e089SXin LI 
1567374caaaSXin LI #if HILITE_SEARCH
1577374caaaSXin LI 	if (search_type & SRCH_FILTER)
158b7780dbeSXin LI 		set_mca(A_FILTER);
1597374caaaSXin LI 	else
1607374caaaSXin LI #endif
161a5f0fb15SPaul Saab 	if (search_type & SRCH_FORW)
162b7780dbeSXin LI 		set_mca(A_F_SEARCH);
163a5f0fb15SPaul Saab 	else
164b7780dbeSXin LI 		set_mca(A_B_SEARCH);
165a5f0fb15SPaul Saab 
166a5f0fb15SPaul Saab 	if (search_type & SRCH_NO_MATCH)
167a5f0fb15SPaul Saab 		cmd_putstr("Non-match ");
168a5f0fb15SPaul Saab 	if (search_type & SRCH_FIRST_FILE)
169a5f0fb15SPaul Saab 		cmd_putstr("First-file ");
170a5f0fb15SPaul Saab 	if (search_type & SRCH_PAST_EOF)
171a5f0fb15SPaul Saab 		cmd_putstr("EOF-ignore ");
172a5f0fb15SPaul Saab 	if (search_type & SRCH_NO_MOVE)
173a5f0fb15SPaul Saab 		cmd_putstr("Keep-pos ");
174a5f0fb15SPaul Saab 	if (search_type & SRCH_NO_REGEX)
175a5f0fb15SPaul Saab 		cmd_putstr("Regex-off ");
1762235c7feSXin LI 	if (search_type & SRCH_WRAP)
1772235c7feSXin LI 		cmd_putstr("Wrap ");
178d713e089SXin LI 	for (i = 1; i <= NUM_SEARCH_COLORS; i++)
179d713e089SXin LI 	{
180d713e089SXin LI 		if (search_type & SRCH_SUBSEARCH(i))
181d713e089SXin LI 		{
182f80a33eaSXin LI 			char buf[INT_STRLEN_BOUND(int)+8];
183d713e089SXin LI 			SNPRINTF1(buf, sizeof(buf), "Sub-%d ", i);
184d713e089SXin LI 			cmd_putstr(buf);
185d713e089SXin LI 		}
186d713e089SXin LI 	}
187*c77c4889SXin LI 	if (literal_char)
188*c77c4889SXin LI 		cmd_putstr("Lit ");
189a5f0fb15SPaul Saab 
1907374caaaSXin LI #if HILITE_SEARCH
1917374caaaSXin LI 	if (search_type & SRCH_FILTER)
1927374caaaSXin LI 		cmd_putstr("&/");
1937374caaaSXin LI 	else
1947374caaaSXin LI #endif
195a5f0fb15SPaul Saab 	if (search_type & SRCH_FORW)
196a5f0fb15SPaul Saab 		cmd_putstr("/");
197a5f0fb15SPaul Saab 	else
198a5f0fb15SPaul Saab 		cmd_putstr("?");
199a15691bfSXin LI 	forw_prompt = 0;
20095270f73SXin LI }
20195270f73SXin LI 
202d713e089SXin LI static void mca_search(void)
20395270f73SXin LI {
20495270f73SXin LI 	mca_search1();
205a5f0fb15SPaul Saab 	set_mlist(ml_search, 0);
206a5f0fb15SPaul Saab }
207a5f0fb15SPaul Saab 
208a5f0fb15SPaul Saab /*
209a5f0fb15SPaul Saab  * Set up the display to start a new toggle-option command.
210a5f0fb15SPaul Saab  */
211d713e089SXin LI static void mca_opt_toggle(void)
212a5f0fb15SPaul Saab {
213*c77c4889SXin LI 	int no_prompt = (optflag & OPT_NO_PROMPT);
214*c77c4889SXin LI 	int flag = (optflag & ~OPT_NO_PROMPT);
215*c77c4889SXin LI 	constant char *dash = (flag == OPT_NO_TOGGLE) ? "_" : "-";
216a5f0fb15SPaul Saab 
217b7780dbeSXin LI 	set_mca(A_OPT_TOGGLE);
218a5f0fb15SPaul Saab 	cmd_putstr(dash);
219a5f0fb15SPaul Saab 	if (optgetname)
220a5f0fb15SPaul Saab 		cmd_putstr(dash);
221a5f0fb15SPaul Saab 	if (no_prompt)
222a5f0fb15SPaul Saab 		cmd_putstr("(P)");
223a5f0fb15SPaul Saab 	switch (flag)
224a5f0fb15SPaul Saab 	{
225a5f0fb15SPaul Saab 	case OPT_UNSET:
226a5f0fb15SPaul Saab 		cmd_putstr("+");
227a5f0fb15SPaul Saab 		break;
228a5f0fb15SPaul Saab 	case OPT_SET:
229a5f0fb15SPaul Saab 		cmd_putstr("!");
230a5f0fb15SPaul Saab 		break;
231a5f0fb15SPaul Saab 	}
232a15691bfSXin LI 	forw_prompt = 0;
233a5f0fb15SPaul Saab 	set_mlist(NULL, 0);
234a5f0fb15SPaul Saab }
235a5f0fb15SPaul Saab 
236a5f0fb15SPaul Saab /*
237a5f0fb15SPaul Saab  * Execute a multicharacter command.
238a5f0fb15SPaul Saab  */
239d713e089SXin LI static void exec_mca(void)
240a5f0fb15SPaul Saab {
241*c77c4889SXin LI 	constant char *cbuf;
242*c77c4889SXin LI 	char *p;
243a5f0fb15SPaul Saab 
244a5f0fb15SPaul Saab 	cmd_exec();
245a5f0fb15SPaul Saab 	cbuf = get_cmdbuf();
24695270f73SXin LI 	if (cbuf == NULL)
24795270f73SXin LI 		return;
248a5f0fb15SPaul Saab 
249a5f0fb15SPaul Saab 	switch (mca)
250a5f0fb15SPaul Saab 	{
251a5f0fb15SPaul Saab 	case A_F_SEARCH:
252a5f0fb15SPaul Saab 	case A_B_SEARCH:
253a15691bfSXin LI 		multi_search(cbuf, (int) number, 0);
254a5f0fb15SPaul Saab 		break;
2557374caaaSXin LI #if HILITE_SEARCH
2567374caaaSXin LI 	case A_FILTER:
2577374caaaSXin LI 		search_type ^= SRCH_NO_MATCH;
2587374caaaSXin LI 		set_filter_pattern(cbuf, search_type);
2597374caaaSXin LI 		break;
2607374caaaSXin LI #endif
261a5f0fb15SPaul Saab 	case A_FIRSTCMD:
262a5f0fb15SPaul Saab 		/*
263a5f0fb15SPaul Saab 		 * Skip leading spaces or + signs in the string.
264a5f0fb15SPaul Saab 		 */
265a5f0fb15SPaul Saab 		while (*cbuf == '+' || *cbuf == ' ')
266a5f0fb15SPaul Saab 			cbuf++;
267a5f0fb15SPaul Saab 		if (every_first_cmd != NULL)
268a5f0fb15SPaul Saab 			free(every_first_cmd);
269a5f0fb15SPaul Saab 		if (*cbuf == '\0')
270a5f0fb15SPaul Saab 			every_first_cmd = NULL;
271a5f0fb15SPaul Saab 		else
272a5f0fb15SPaul Saab 			every_first_cmd = save(cbuf);
273a5f0fb15SPaul Saab 		break;
274a5f0fb15SPaul Saab 	case A_OPT_TOGGLE:
27533096f16SXin LI 		toggle_option(curropt, opt_lower, cbuf, optflag);
27633096f16SXin LI 		curropt = NULL;
277a5f0fb15SPaul Saab 		break;
278a5f0fb15SPaul Saab 	case A_F_BRACKET:
2791ede1615STim J. Robbins 		match_brac(cbuf[0], cbuf[1], 1, (int) number);
280a5f0fb15SPaul Saab 		break;
281a5f0fb15SPaul Saab 	case A_B_BRACKET:
2821ede1615STim J. Robbins 		match_brac(cbuf[1], cbuf[0], 0, (int) number);
283a5f0fb15SPaul Saab 		break;
284a5f0fb15SPaul Saab #if EXAMINE
285a5f0fb15SPaul Saab 	case A_EXAMINE:
286*c77c4889SXin LI 		if (!secure_allow(SF_EXAMINE))
287a5f0fb15SPaul Saab 			break;
288*c77c4889SXin LI 		p = save(cbuf);
289*c77c4889SXin LI 		edit_list(p);
290*c77c4889SXin LI 		free(p);
2911ede1615STim J. Robbins #if TAGS
2928fd4165cSPaul Saab 		/* If tag structure is loaded then clean it up. */
2938fd4165cSPaul Saab 		cleantags();
2941ede1615STim J. Robbins #endif
295a5f0fb15SPaul Saab 		break;
296a5f0fb15SPaul Saab #endif
297a5f0fb15SPaul Saab #if SHELL_ESCAPE
298*c77c4889SXin LI 	case A_SHELL: {
299a5f0fb15SPaul Saab 		/*
300a5f0fb15SPaul Saab 		 * !! just uses whatever is in shellcmd.
301a5f0fb15SPaul Saab 		 * Otherwise, copy cmdbuf to shellcmd,
302a5f0fb15SPaul Saab 		 * expanding any special characters ("%" or "#").
303a5f0fb15SPaul Saab 		 */
304*c77c4889SXin LI 		constant char *done_msg = (*cbuf == CONTROL('P')) ? NULL : "!done";
305*c77c4889SXin LI 		if (done_msg == NULL)
306*c77c4889SXin LI 			++cbuf;
307a5f0fb15SPaul Saab 		if (*cbuf != '!')
308a5f0fb15SPaul Saab 		{
309a5f0fb15SPaul Saab 			if (shellcmd != NULL)
310a5f0fb15SPaul Saab 				free(shellcmd);
311a5f0fb15SPaul Saab 			shellcmd = fexpand(cbuf);
312a5f0fb15SPaul Saab 		}
313*c77c4889SXin LI 		if (!secure_allow(SF_SHELL))
314a5f0fb15SPaul Saab 			break;
315a5f0fb15SPaul Saab 		if (shellcmd == NULL)
316*c77c4889SXin LI 			shellcmd = "";
317*c77c4889SXin LI 		lsystem(shellcmd, done_msg);
318*c77c4889SXin LI 		break; }
319*c77c4889SXin LI 	case A_PSHELL: {
320*c77c4889SXin LI 		constant char *done_msg = (*cbuf == CONTROL('P')) ? NULL : "#done";
321*c77c4889SXin LI 		if (done_msg == NULL)
322*c77c4889SXin LI 			++cbuf;
323*c77c4889SXin LI 		if (!secure_allow(SF_SHELL))
324a5f0fb15SPaul Saab 			break;
325*c77c4889SXin LI 		lsystem(pr_expand(cbuf), done_msg);
326*c77c4889SXin LI 		break; }
327a5f0fb15SPaul Saab #endif
328a5f0fb15SPaul Saab #if PIPEC
329*c77c4889SXin LI 	case A_PIPE: {
330*c77c4889SXin LI 		constant char *done_msg = (*cbuf == CONTROL('P')) ? NULL : "|done";
331*c77c4889SXin LI 		if (done_msg == NULL)
332*c77c4889SXin LI 			++cbuf;
333*c77c4889SXin LI 		if (!secure_allow(SF_PIPE))
334a5f0fb15SPaul Saab 			break;
335a5f0fb15SPaul Saab 		(void) pipe_mark(pipec, cbuf);
336*c77c4889SXin LI 		if (done_msg != NULL)
337*c77c4889SXin LI 			error(done_msg, NULL_PARG);
338*c77c4889SXin LI 		break; }
339a5f0fb15SPaul Saab #endif
340a5f0fb15SPaul Saab 	}
341a5f0fb15SPaul Saab }
342a5f0fb15SPaul Saab 
343a5f0fb15SPaul Saab /*
34433096f16SXin LI  * Is a character an erase or kill char?
345a5f0fb15SPaul Saab  */
346*c77c4889SXin LI static lbool is_erase_char(char c)
347a5f0fb15SPaul Saab {
34833096f16SXin LI 	return (c == erase_char || c == erase2_char || c == kill_char);
349a5f0fb15SPaul Saab }
350a5f0fb15SPaul Saab 
351a5f0fb15SPaul Saab /*
352b2ea2440SXin LI  * Is a character a carriage return or newline?
353b2ea2440SXin LI  */
354*c77c4889SXin LI static lbool is_newline_char(char c)
355b2ea2440SXin LI {
356b2ea2440SXin LI 	return (c == '\n' || c == '\r');
357b2ea2440SXin LI }
358b2ea2440SXin LI 
359b2ea2440SXin LI /*
36033096f16SXin LI  * Handle the first char of an option (after the initial dash).
361a5f0fb15SPaul Saab  */
362*c77c4889SXin LI static int mca_opt_first_char(char c)
363a5f0fb15SPaul Saab {
36495270f73SXin LI 	int no_prompt = (optflag & OPT_NO_PROMPT);
36533096f16SXin LI 	int flag = (optflag & ~OPT_NO_PROMPT);
366a5f0fb15SPaul Saab 	if (flag == OPT_NO_TOGGLE)
367a5f0fb15SPaul Saab 	{
368a5f0fb15SPaul Saab 		switch (c)
369a5f0fb15SPaul Saab 		{
370a5f0fb15SPaul Saab 		case '_':
371a5f0fb15SPaul Saab 			/* "__" = long option name. */
372a5f0fb15SPaul Saab 			optgetname = TRUE;
373a5f0fb15SPaul Saab 			mca_opt_toggle();
374a5f0fb15SPaul Saab 			return (MCA_MORE);
375a5f0fb15SPaul Saab 		}
376a5f0fb15SPaul Saab 	} else
377a5f0fb15SPaul Saab 	{
378a5f0fb15SPaul Saab 		switch (c)
379a5f0fb15SPaul Saab 		{
380a5f0fb15SPaul Saab 		case '+':
381a5f0fb15SPaul Saab 			/* "-+" = UNSET. */
38295270f73SXin LI 			optflag = no_prompt | ((flag == OPT_UNSET) ?
38395270f73SXin LI 				OPT_TOGGLE : OPT_UNSET);
384a5f0fb15SPaul Saab 			mca_opt_toggle();
385a5f0fb15SPaul Saab 			return (MCA_MORE);
386a5f0fb15SPaul Saab 		case '!':
387a5f0fb15SPaul Saab 			/* "-!" = SET */
38895270f73SXin LI 			optflag = no_prompt | ((flag == OPT_SET) ?
38995270f73SXin LI 				OPT_TOGGLE : OPT_SET);
390a5f0fb15SPaul Saab 			mca_opt_toggle();
391a5f0fb15SPaul Saab 			return (MCA_MORE);
392a5f0fb15SPaul Saab 		case CONTROL('P'):
393a5f0fb15SPaul Saab 			optflag ^= OPT_NO_PROMPT;
394a5f0fb15SPaul Saab 			mca_opt_toggle();
395a5f0fb15SPaul Saab 			return (MCA_MORE);
396a5f0fb15SPaul Saab 		case '-':
397a5f0fb15SPaul Saab 			/* "--" = long option name. */
398a5f0fb15SPaul Saab 			optgetname = TRUE;
399a5f0fb15SPaul Saab 			mca_opt_toggle();
400a5f0fb15SPaul Saab 			return (MCA_MORE);
401a5f0fb15SPaul Saab 		}
402a5f0fb15SPaul Saab 	}
40333096f16SXin LI 	/* Char was not handled here. */
40433096f16SXin LI 	return (NO_MCA);
405a5f0fb15SPaul Saab }
40633096f16SXin LI 
407a5f0fb15SPaul Saab /*
40833096f16SXin LI  * Add a char to a long option name.
40933096f16SXin LI  * See if we've got a match for an option name yet.
410a5f0fb15SPaul Saab  * If so, display the complete name and stop
411a5f0fb15SPaul Saab  * accepting chars until user hits RETURN.
412a5f0fb15SPaul Saab  */
413*c77c4889SXin LI static int mca_opt_nonfirst_char(char c)
41433096f16SXin LI {
415*c77c4889SXin LI 	constant char *p;
416*c77c4889SXin LI 	constant char *oname;
417*c77c4889SXin LI 	lbool ambig;
418a5f0fb15SPaul Saab 
41933096f16SXin LI 	if (curropt != NULL)
420a5f0fb15SPaul Saab 	{
421a5f0fb15SPaul Saab 		/*
422a5f0fb15SPaul Saab 		 * Already have a match for the name.
423a5f0fb15SPaul Saab 		 * Don't accept anything but erase/kill.
424a5f0fb15SPaul Saab 		 */
42533096f16SXin LI 		if (is_erase_char(c))
426a5f0fb15SPaul Saab 			return (MCA_DONE);
427a5f0fb15SPaul Saab 		return (MCA_MORE);
428a5f0fb15SPaul Saab 	}
429a5f0fb15SPaul Saab 	/*
430a5f0fb15SPaul Saab 	 * Add char to cmd buffer and try to match
431a5f0fb15SPaul Saab 	 * the option name.
432a5f0fb15SPaul Saab 	 */
433a5f0fb15SPaul Saab 	if (cmd_char(c) == CC_QUIT)
434a5f0fb15SPaul Saab 		return (MCA_DONE);
435a5f0fb15SPaul Saab 	p = get_cmdbuf();
43695270f73SXin LI 	if (p == NULL)
43795270f73SXin LI 		return (MCA_MORE);
43833096f16SXin LI 	opt_lower = ASCII_IS_LOWER(p[0]);
439*c77c4889SXin LI 	curropt = findopt_name(&p, &oname, &ambig);
44033096f16SXin LI 	if (curropt != NULL)
441a5f0fb15SPaul Saab 	{
442a5f0fb15SPaul Saab 		/*
443a5f0fb15SPaul Saab 		 * Got a match.
44433096f16SXin LI 		 * Remember the option and
445a5f0fb15SPaul Saab 		 * display the full option name.
446a5f0fb15SPaul Saab 		 */
447a5f0fb15SPaul Saab 		cmd_reset();
448a5f0fb15SPaul Saab 		mca_opt_toggle();
449a5f0fb15SPaul Saab 		for (p = oname;  *p != '\0';  p++)
450a5f0fb15SPaul Saab 		{
451a5f0fb15SPaul Saab 			c = *p;
45233096f16SXin LI 			if (!opt_lower && ASCII_IS_LOWER(c))
45389dd99dcSXin LI 				c = ASCII_TO_UPPER(c);
454a5f0fb15SPaul Saab 			if (cmd_char(c) != CC_OK)
455a5f0fb15SPaul Saab 				return (MCA_DONE);
456a5f0fb15SPaul Saab 		}
457*c77c4889SXin LI 	} else if (!ambig)
458b7780dbeSXin LI 	{
459b7780dbeSXin LI 		bell();
460a5f0fb15SPaul Saab 	}
461a5f0fb15SPaul Saab 	return (MCA_MORE);
462a5f0fb15SPaul Saab }
46333096f16SXin LI 
46433096f16SXin LI /*
46533096f16SXin LI  * Handle a char of an option toggle command.
46633096f16SXin LI  */
467*c77c4889SXin LI static int mca_opt_char(char c)
46833096f16SXin LI {
46933096f16SXin LI 	PARG parg;
47033096f16SXin LI 
47133096f16SXin LI 	/*
47233096f16SXin LI 	 * This may be a short option (single char),
47333096f16SXin LI 	 * or one char of a long option name,
47433096f16SXin LI 	 * or one char of the option parameter.
47533096f16SXin LI 	 */
47633096f16SXin LI 	if (curropt == NULL && len_cmdbuf() == 0)
47733096f16SXin LI 	{
47833096f16SXin LI 		int ret = mca_opt_first_char(c);
47933096f16SXin LI 		if (ret != NO_MCA)
48033096f16SXin LI 			return (ret);
48133096f16SXin LI 	}
48233096f16SXin LI 	if (optgetname)
48333096f16SXin LI 	{
48433096f16SXin LI 		/* We're getting a long option name.  */
48595270f73SXin LI 		if (!is_newline_char(c) && c != '=')
48633096f16SXin LI 			return (mca_opt_nonfirst_char(c));
48733096f16SXin LI 		if (curropt == NULL)
48833096f16SXin LI 		{
48933096f16SXin LI 			parg.p_string = get_cmdbuf();
49095270f73SXin LI 			if (parg.p_string == NULL)
49195270f73SXin LI 				return (MCA_MORE);
49233096f16SXin LI 			error("There is no --%s option", &parg);
49333096f16SXin LI 			return (MCA_DONE);
49433096f16SXin LI 		}
49533096f16SXin LI 		optgetname = FALSE;
49633096f16SXin LI 		cmd_reset();
497a5f0fb15SPaul Saab 	} else
498a5f0fb15SPaul Saab 	{
49933096f16SXin LI 		if (is_erase_char(c))
50033096f16SXin LI 			return (NO_MCA);
50133096f16SXin LI 		if (curropt != NULL)
50233096f16SXin LI 			/* We're getting the option parameter. */
50333096f16SXin LI 			return (NO_MCA);
50433096f16SXin LI 		curropt = findopt(c);
50533096f16SXin LI 		if (curropt == NULL)
506a5f0fb15SPaul Saab 		{
50733096f16SXin LI 			parg.p_string = propt(c);
50833096f16SXin LI 			error("There is no %s option", &parg);
50933096f16SXin LI 			return (MCA_DONE);
51033096f16SXin LI 		}
511b7780dbeSXin LI 		opt_lower = ASCII_IS_LOWER(c);
51233096f16SXin LI 	}
51333096f16SXin LI 	/*
51433096f16SXin LI 	 * If the option which was entered does not take a
51533096f16SXin LI 	 * parameter, toggle the option immediately,
51633096f16SXin LI 	 * so user doesn't have to hit RETURN.
51733096f16SXin LI 	 */
51833096f16SXin LI 	if ((optflag & ~OPT_NO_PROMPT) != OPT_TOGGLE ||
51933096f16SXin LI 	    !opt_has_param(curropt))
52033096f16SXin LI 	{
521b7780dbeSXin LI 		toggle_option(curropt, opt_lower, "", optflag);
522a5f0fb15SPaul Saab 		return (MCA_DONE);
523a5f0fb15SPaul Saab 	}
524a5f0fb15SPaul Saab 	/*
52533096f16SXin LI 	 * Display a prompt appropriate for the option parameter.
526a5f0fb15SPaul Saab 	 */
527*c77c4889SXin LI 	start_mca(A_OPT_TOGGLE, opt_prompt(curropt), NULL, 0);
528a5f0fb15SPaul Saab 	return (MCA_MORE);
52933096f16SXin LI }
530a5f0fb15SPaul Saab 
531a5f0fb15SPaul Saab /*
53295270f73SXin LI  * Normalize search type.
53395270f73SXin LI  */
534d713e089SXin LI public int norm_search_type(int st)
53595270f73SXin LI {
53695270f73SXin LI 	/* WRAP and PAST_EOF are mutually exclusive. */
53795270f73SXin LI 	if ((st & (SRCH_PAST_EOF|SRCH_WRAP)) == (SRCH_PAST_EOF|SRCH_WRAP))
53895270f73SXin LI 		st ^= SRCH_PAST_EOF;
53995270f73SXin LI 	return st;
54095270f73SXin LI }
54195270f73SXin LI 
54295270f73SXin LI /*
54333096f16SXin LI  * Handle a char of a search command.
54433096f16SXin LI  */
545*c77c4889SXin LI static int mca_search_char(char c)
54633096f16SXin LI {
54733096f16SXin LI 	int flag = 0;
54833096f16SXin LI 
54933096f16SXin LI 	/*
550a5f0fb15SPaul Saab 	 * Certain characters as the first char of
551a5f0fb15SPaul Saab 	 * the pattern have special meaning:
552a5f0fb15SPaul Saab 	 *      !  Toggle the NO_MATCH flag
553a5f0fb15SPaul Saab 	 *      *  Toggle the PAST_EOF flag
554a5f0fb15SPaul Saab 	 *      @  Toggle the FIRST_FILE flag
555a5f0fb15SPaul Saab 	 */
556*c77c4889SXin LI 	if (len_cmdbuf() > 0 || literal_char)
557*c77c4889SXin LI 	{
558*c77c4889SXin LI 		literal_char = FALSE;
55933096f16SXin LI 		return (NO_MCA);
560*c77c4889SXin LI 	}
561a5f0fb15SPaul Saab 
562a5f0fb15SPaul Saab 	switch (c)
563a5f0fb15SPaul Saab 	{
564a5f0fb15SPaul Saab 	case '*':
565720c436cSXin LI 		if (less_is_more)
566a8f92a7cSPaul Saab 			break;
567a8f92a7cSPaul Saab 	case CONTROL('E'): /* ignore END of file */
5687374caaaSXin LI 		if (mca != A_FILTER)
569a5f0fb15SPaul Saab 			flag = SRCH_PAST_EOF;
570f80a33eaSXin LI 		search_type &= ~SRCH_WRAP;
571a5f0fb15SPaul Saab 		break;
572a5f0fb15SPaul Saab 	case '@':
573720c436cSXin LI 		if (less_is_more)
574a8f92a7cSPaul Saab 			break;
575a8f92a7cSPaul Saab 	case CONTROL('F'): /* FIRST file */
5767374caaaSXin LI 		if (mca != A_FILTER)
577a5f0fb15SPaul Saab 			flag = SRCH_FIRST_FILE;
578a5f0fb15SPaul Saab 		break;
579a5f0fb15SPaul Saab 	case CONTROL('K'): /* KEEP position */
5807374caaaSXin LI 		if (mca != A_FILTER)
581a5f0fb15SPaul Saab 			flag = SRCH_NO_MOVE;
582a5f0fb15SPaul Saab 		break;
583d713e089SXin LI 	case CONTROL('S'): { /* SUBSEARCH */
584f80a33eaSXin LI 		char buf[INT_STRLEN_BOUND(int)+24];
585d713e089SXin LI 		SNPRINTF1(buf, sizeof(buf), "Sub-pattern (1-%d):", NUM_SEARCH_COLORS);
586d713e089SXin LI 		clear_bot();
587d713e089SXin LI 		cmd_putstr(buf);
588d713e089SXin LI 		flush();
589d713e089SXin LI 		c = getcc();
590d713e089SXin LI 		if (c >= '1' && c <= '0'+NUM_SEARCH_COLORS)
591d713e089SXin LI 			flag = SRCH_SUBSEARCH(c-'0');
592d713e089SXin LI 		else
593d713e089SXin LI 			flag = -1; /* calls mca_search() below to repaint */
594d713e089SXin LI 		break; }
5952235c7feSXin LI 	case CONTROL('W'): /* WRAP around */
5962235c7feSXin LI 		if (mca != A_FILTER)
5972235c7feSXin LI 			flag = SRCH_WRAP;
5982235c7feSXin LI 		break;
599a5f0fb15SPaul Saab 	case CONTROL('R'): /* Don't use REGULAR EXPRESSIONS */
600a5f0fb15SPaul Saab 		flag = SRCH_NO_REGEX;
601a5f0fb15SPaul Saab 		break;
602a5f0fb15SPaul Saab 	case CONTROL('N'): /* NOT match */
603a5f0fb15SPaul Saab 	case '!':
604a5f0fb15SPaul Saab 		flag = SRCH_NO_MATCH;
605a5f0fb15SPaul Saab 		break;
606*c77c4889SXin LI 	case CONTROL('L'):
607*c77c4889SXin LI 		literal_char = TRUE;
608*c77c4889SXin LI 		flag = -1;
609*c77c4889SXin LI 		break;
610a5f0fb15SPaul Saab 	}
61133096f16SXin LI 
612a5f0fb15SPaul Saab 	if (flag != 0)
613a5f0fb15SPaul Saab 	{
614d713e089SXin LI 		if (flag != -1)
61595270f73SXin LI 			search_type = norm_search_type(search_type ^ flag);
616a5f0fb15SPaul Saab 		mca_search();
617a5f0fb15SPaul Saab 		return (MCA_MORE);
618a5f0fb15SPaul Saab 	}
61933096f16SXin LI 	return (NO_MCA);
62033096f16SXin LI }
62133096f16SXin LI 
62233096f16SXin LI /*
62333096f16SXin LI  * Handle a character of a multi-character command.
62433096f16SXin LI  */
625*c77c4889SXin LI static int mca_char(char c)
62633096f16SXin LI {
62733096f16SXin LI 	int ret;
62833096f16SXin LI 
62933096f16SXin LI 	switch (mca)
63033096f16SXin LI 	{
63133096f16SXin LI 	case 0:
63233096f16SXin LI 		/*
63333096f16SXin LI 		 * We're not in a multicharacter command.
63433096f16SXin LI 		 */
63533096f16SXin LI 		return (NO_MCA);
63633096f16SXin LI 
63733096f16SXin LI 	case A_PREFIX:
63833096f16SXin LI 		/*
63933096f16SXin LI 		 * In the prefix of a command.
64033096f16SXin LI 		 * This not considered a multichar command
64133096f16SXin LI 		 * (even tho it uses cmdbuf, etc.).
64233096f16SXin LI 		 * It is handled in the commands() switch.
64333096f16SXin LI 		 */
64433096f16SXin LI 		return (NO_MCA);
64533096f16SXin LI 
64633096f16SXin LI 	case A_DIGIT:
64733096f16SXin LI 		/*
64833096f16SXin LI 		 * Entering digits of a number.
64933096f16SXin LI 		 * Terminated by a non-digit.
65033096f16SXin LI 		 */
6512235c7feSXin LI 		if ((c >= '0' && c <= '9') || c == '.')
6522235c7feSXin LI 			break;
6532235c7feSXin LI 		switch (editchar(c, ECF_PEEK|ECF_NOHISTORY|ECF_NOCOMPLETE|ECF_NORIGHTLEFT))
65433096f16SXin LI 		{
6552235c7feSXin LI 		case A_NOACTION:
6562235c7feSXin LI 			/*
6572235c7feSXin LI 			 * Ignore this char and get another one.
6582235c7feSXin LI 			 */
6592235c7feSXin LI 			return (MCA_MORE);
6602235c7feSXin LI 		case A_INVALID:
66133096f16SXin LI 			/*
66233096f16SXin LI 			 * Not part of the number.
66333096f16SXin LI 			 * End the number and treat this char
66433096f16SXin LI 			 * as a normal command character.
66533096f16SXin LI 			 */
66633096f16SXin LI 			number = cmd_int(&fraction);
667b7780dbeSXin LI 			clear_mca();
66833096f16SXin LI 			cmd_accept();
66933096f16SXin LI 			return (NO_MCA);
67033096f16SXin LI 		}
67133096f16SXin LI 		break;
67233096f16SXin LI 
67333096f16SXin LI 	case A_OPT_TOGGLE:
67433096f16SXin LI 		ret = mca_opt_char(c);
67533096f16SXin LI 		if (ret != NO_MCA)
67633096f16SXin LI 			return (ret);
67733096f16SXin LI 		break;
67833096f16SXin LI 
67933096f16SXin LI 	case A_F_SEARCH:
68033096f16SXin LI 	case A_B_SEARCH:
68133096f16SXin LI 	case A_FILTER:
68233096f16SXin LI 		ret = mca_search_char(c);
68333096f16SXin LI 		if (ret != NO_MCA)
68433096f16SXin LI 			return (ret);
68533096f16SXin LI 		break;
68633096f16SXin LI 
68733096f16SXin LI 	default:
68833096f16SXin LI 		/* Other multicharacter command. */
689a5f0fb15SPaul Saab 		break;
690a5f0fb15SPaul Saab 	}
691a5f0fb15SPaul Saab 
692a5f0fb15SPaul Saab 	/*
69333096f16SXin LI 	 * The multichar command is terminated by a newline.
694a5f0fb15SPaul Saab 	 */
695b2ea2440SXin LI 	if (is_newline_char(c))
696a5f0fb15SPaul Saab 	{
697a5f0fb15SPaul Saab 		/*
698a5f0fb15SPaul Saab 		 * Execute the command.
699a5f0fb15SPaul Saab 		 */
700a5f0fb15SPaul Saab 		exec_mca();
701a5f0fb15SPaul Saab 		return (MCA_DONE);
702a5f0fb15SPaul Saab 	}
703a5f0fb15SPaul Saab 
704a5f0fb15SPaul Saab 	/*
705a5f0fb15SPaul Saab 	 * Append the char to the command buffer.
706a5f0fb15SPaul Saab 	 */
707a5f0fb15SPaul Saab 	if (cmd_char(c) == CC_QUIT)
708a5f0fb15SPaul Saab 		/*
709a5f0fb15SPaul Saab 		 * Abort the multi-char command.
710a5f0fb15SPaul Saab 		 */
711a5f0fb15SPaul Saab 		return (MCA_DONE);
712a5f0fb15SPaul Saab 
7132235c7feSXin LI 	switch (mca)
7142235c7feSXin LI 	{
7152235c7feSXin LI 	case A_F_BRACKET:
7162235c7feSXin LI 	case A_B_BRACKET:
7172235c7feSXin LI 		if (len_cmdbuf() >= 2)
718a5f0fb15SPaul Saab 		{
719a5f0fb15SPaul Saab 			/*
720a5f0fb15SPaul Saab 			 * Special case for the bracket-matching commands.
721a5f0fb15SPaul Saab 			 * Execute the command after getting exactly two
722a5f0fb15SPaul Saab 			 * characters from the user.
723a5f0fb15SPaul Saab 			 */
724a5f0fb15SPaul Saab 			exec_mca();
725a5f0fb15SPaul Saab 			return (MCA_DONE);
726a5f0fb15SPaul Saab 		}
7272235c7feSXin LI 		break;
7282235c7feSXin LI 	case A_F_SEARCH:
7292235c7feSXin LI 	case A_B_SEARCH:
7302235c7feSXin LI 		if (incr_search)
7312235c7feSXin LI 		{
7322235c7feSXin LI 			/* Incremental search: do a search after every input char. */
733d713e089SXin LI 			int st = (search_type & (SRCH_FORW|SRCH_BACK|SRCH_NO_MATCH|SRCH_NO_REGEX|SRCH_NO_MOVE|SRCH_WRAP|SRCH_SUBSEARCH_ALL));
734*c77c4889SXin LI 			ssize_t save_updown;
735*c77c4889SXin LI 			constant char *pattern = get_cmdbuf();
73695270f73SXin LI 			if (pattern == NULL)
73795270f73SXin LI 				return (MCA_MORE);
73895270f73SXin LI 			/*
73995270f73SXin LI 			 * Must save updown_match because mca_search
74095270f73SXin LI 			 * reinits it. That breaks history scrolling.
74195270f73SXin LI 			 * {{ This is ugly. mca_search probably shouldn't call set_mlist. }}
74295270f73SXin LI 			 */
743*c77c4889SXin LI 			save_updown = save_updown_match();
7442235c7feSXin LI 			cmd_exec();
7452235c7feSXin LI 			if (*pattern == '\0')
7462235c7feSXin LI 			{
7472235c7feSXin LI 				/* User has backspaced to an empty pattern. */
7482235c7feSXin LI 				undo_search(1);
7492235c7feSXin LI 			} else
7502235c7feSXin LI 			{
7512235c7feSXin LI 				if (search(st | SRCH_INCR, pattern, 1) != 0)
7522235c7feSXin LI 					/* No match, invalid pattern, etc. */
7532235c7feSXin LI 					undo_search(1);
7542235c7feSXin LI 			}
7552235c7feSXin LI 			/* Redraw the search prompt and search string. */
756*c77c4889SXin LI 			if (is_screen_trashed() || !full_screen)
757d713e089SXin LI 			{
758d713e089SXin LI 				clear();
759d713e089SXin LI 				repaint();
760d713e089SXin LI 			}
76195270f73SXin LI 			mca_search1();
762*c77c4889SXin LI 			restore_updown_match(save_updown);
7632235c7feSXin LI 			cmd_repaint(NULL);
7642235c7feSXin LI 		}
7652235c7feSXin LI 		break;
7662235c7feSXin LI 	}
767a5f0fb15SPaul Saab 
768a5f0fb15SPaul Saab 	/*
769a5f0fb15SPaul Saab 	 * Need another character.
770a5f0fb15SPaul Saab 	 */
771a5f0fb15SPaul Saab 	return (MCA_MORE);
772a5f0fb15SPaul Saab }
773a5f0fb15SPaul Saab 
774a5f0fb15SPaul Saab /*
775423c5ce5SXin LI  * Discard any buffered file data.
776423c5ce5SXin LI  */
777d713e089SXin LI static void clear_buffers(void)
778423c5ce5SXin LI {
779423c5ce5SXin LI 	if (!(ch_getflags() & CH_CANSEEK))
780423c5ce5SXin LI 		return;
781423c5ce5SXin LI 	ch_flush();
782423c5ce5SXin LI 	clr_linenum();
783423c5ce5SXin LI #if HILITE_SEARCH
784423c5ce5SXin LI 	clr_hilite();
785423c5ce5SXin LI #endif
786423c5ce5SXin LI }
787423c5ce5SXin LI 
788*c77c4889SXin LI public void screen_trashed_num(int trashed)
789*c77c4889SXin LI {
790*c77c4889SXin LI 	screen_trashed_value = trashed;
791*c77c4889SXin LI }
792*c77c4889SXin LI 
793*c77c4889SXin LI public void screen_trashed(void)
794*c77c4889SXin LI {
795*c77c4889SXin LI 	screen_trashed_num(1);
796*c77c4889SXin LI }
797*c77c4889SXin LI 
798*c77c4889SXin LI public int is_screen_trashed(void)
799*c77c4889SXin LI {
800*c77c4889SXin LI 	return screen_trashed_value;
801*c77c4889SXin LI }
802*c77c4889SXin LI 
803423c5ce5SXin LI /*
804a5f0fb15SPaul Saab  * Make sure the screen is displayed.
805a5f0fb15SPaul Saab  */
806d713e089SXin LI static void make_display(void)
807a5f0fb15SPaul Saab {
808a5f0fb15SPaul Saab 	/*
809d713e089SXin LI 	 * If not full_screen, we can't rely on scrolling to fill the screen.
810d713e089SXin LI 	 * We need to clear and repaint screen before any change.
811d713e089SXin LI 	 */
812d713e089SXin LI 	if (!full_screen && !(quit_if_one_screen && one_screen))
813d713e089SXin LI 		clear();
814d713e089SXin LI 	/*
815a5f0fb15SPaul Saab 	 * If nothing is displayed yet, display starting from initial_scrpos.
816a5f0fb15SPaul Saab 	 */
817a5f0fb15SPaul Saab 	if (empty_screen())
818a5f0fb15SPaul Saab 	{
819a5f0fb15SPaul Saab 		if (initial_scrpos.pos == NULL_POSITION)
820a5f0fb15SPaul Saab 			jump_loc(ch_zero(), 1);
821a5f0fb15SPaul Saab 		else
822a5f0fb15SPaul Saab 			jump_loc(initial_scrpos.pos, initial_scrpos.ln);
823*c77c4889SXin LI 	} else if (is_screen_trashed() || !full_screen)
824a5f0fb15SPaul Saab 	{
825423c5ce5SXin LI 		int save_top_scroll = top_scroll;
826423c5ce5SXin LI 		int save_ignore_eoi = ignore_eoi;
827a5f0fb15SPaul Saab 		top_scroll = 1;
828423c5ce5SXin LI 		ignore_eoi = 0;
829*c77c4889SXin LI 		if (is_screen_trashed() == 2)
830423c5ce5SXin LI 		{
831423c5ce5SXin LI 			/* Special case used by ignore_eoi: re-open the input file
832423c5ce5SXin LI 			 * and jump to the end of the file. */
833423c5ce5SXin LI 			reopen_curr_ifile();
834423c5ce5SXin LI 			jump_forw();
835423c5ce5SXin LI 		}
836a5f0fb15SPaul Saab 		repaint();
837a5f0fb15SPaul Saab 		top_scroll = save_top_scroll;
838423c5ce5SXin LI 		ignore_eoi = save_ignore_eoi;
839a5f0fb15SPaul Saab 	}
840a5f0fb15SPaul Saab }
841a5f0fb15SPaul Saab 
842a5f0fb15SPaul Saab /*
843a5f0fb15SPaul Saab  * Display the appropriate prompt.
844a5f0fb15SPaul Saab  */
845d713e089SXin LI static void prompt(void)
846a5f0fb15SPaul Saab {
8471ea31627SRobert Watson 	constant char *p;
848a5f0fb15SPaul Saab 
849*c77c4889SXin LI 	if (ungot != NULL && !ungot->ug_end_command)
850a5f0fb15SPaul Saab 	{
851a5f0fb15SPaul Saab 		/*
852a5f0fb15SPaul Saab 		 * No prompt necessary if commands are from
853a5f0fb15SPaul Saab 		 * ungotten chars rather than from the user.
854a5f0fb15SPaul Saab 		 */
855a5f0fb15SPaul Saab 		return;
856a5f0fb15SPaul Saab 	}
857a5f0fb15SPaul Saab 
858a5f0fb15SPaul Saab 	/*
859a5f0fb15SPaul Saab 	 * Make sure the screen is displayed.
860a5f0fb15SPaul Saab 	 */
861a5f0fb15SPaul Saab 	make_display();
862a5f0fb15SPaul Saab 	bottompos = position(BOTTOM_PLUS_ONE);
863a5f0fb15SPaul Saab 
864a5f0fb15SPaul Saab 	/*
8657374caaaSXin LI 	 * If we've hit EOF on the last file and the -E flag is set, quit.
866a5f0fb15SPaul Saab 	 */
8677374caaaSXin LI 	if (get_quit_at_eof() == OPT_ONPLUS &&
8687374caaaSXin LI 	    eof_displayed() && !(ch_getflags() & CH_HELPFILE) &&
869a5f0fb15SPaul Saab 	    next_ifile(curr_ifile) == NULL_IFILE)
870a5f0fb15SPaul Saab 		quit(QUIT_OK);
8717374caaaSXin LI 
872a5f0fb15SPaul Saab 	/*
8737374caaaSXin LI 	 * If the entire file is displayed and the -F flag is set, quit.
874a5f0fb15SPaul Saab 	 */
8757374caaaSXin LI 	if (quit_if_one_screen &&
8767374caaaSXin LI 	    entire_file_displayed() && !(ch_getflags() & CH_HELPFILE) &&
877a5f0fb15SPaul Saab 	    next_ifile(curr_ifile) == NULL_IFILE)
878a5f0fb15SPaul Saab 		quit(QUIT_OK);
87930a1828cSXin LI 	quit_if_one_screen = FALSE; /* only get one chance at this */
880a5f0fb15SPaul Saab 
8818fd4165cSPaul Saab #if MSDOS_COMPILER==WIN32C
8828fd4165cSPaul Saab 	/*
8838fd4165cSPaul Saab 	 * In Win32, display the file name in the window title.
8848fd4165cSPaul Saab 	 */
8858fd4165cSPaul Saab 	if (!(ch_getflags() & CH_HELPFILE))
886b7780dbeSXin LI 	{
887b7780dbeSXin LI 		WCHAR w[MAX_PATH+16];
88895270f73SXin LI 		p = pr_expand("Less?f - %f.");
889*c77c4889SXin LI 		MultiByteToWideChar(less_acp, 0, p, -1, w, countof(w));
890b7780dbeSXin LI 		SetConsoleTitleW(w);
891b7780dbeSXin LI 	}
8928fd4165cSPaul Saab #endif
893b7780dbeSXin LI 
894a5f0fb15SPaul Saab 	/*
895a5f0fb15SPaul Saab 	 * Select the proper prompt and display it.
896a5f0fb15SPaul Saab 	 */
897720c436cSXin LI 	/*
898720c436cSXin LI 	 * If the previous action was a forward movement,
899720c436cSXin LI 	 * don't clear the bottom line of the display;
900720c436cSXin LI 	 * just print the prompt since the forward movement guarantees
901720c436cSXin LI 	 * that we're in the right position to display the prompt.
902720c436cSXin LI 	 * Clearing the line could cause a problem: for example, if the last
903720c436cSXin LI 	 * line displayed ended at the right screen edge without a newline,
904720c436cSXin LI 	 * then clearing would clear the last displayed line rather than
905720c436cSXin LI 	 * the prompt line.
906720c436cSXin LI 	 */
907720c436cSXin LI 	if (!forw_prompt)
908720c436cSXin LI 		clear_bot();
909a5f0fb15SPaul Saab 	clear_cmd();
910720c436cSXin LI 	forw_prompt = 0;
911a5f0fb15SPaul Saab 	p = pr_string();
9122235c7feSXin LI #if HILITE_SEARCH
9137374caaaSXin LI 	if (is_filtering())
9147374caaaSXin LI 		putstr("& ");
9152235c7feSXin LI #endif
916*c77c4889SXin LI 	if (search_wrapped)
917*c77c4889SXin LI 	{
918*c77c4889SXin LI 		if (search_type & SRCH_BACK)
919*c77c4889SXin LI 			error("Search hit top; continuing at bottom", NULL_PARG);
920*c77c4889SXin LI 		else
921*c77c4889SXin LI 			error("Search hit bottom; continuing at top", NULL_PARG);
922*c77c4889SXin LI 		search_wrapped = FALSE;
923*c77c4889SXin LI 	}
924*c77c4889SXin LI #if OSC8_LINK
925*c77c4889SXin LI 	if (osc8_uri != NULL)
926*c77c4889SXin LI 	{
927*c77c4889SXin LI 		PARG parg;
928*c77c4889SXin LI 		parg.p_string = osc8_uri;
929*c77c4889SXin LI 		error("Link: %s", &parg);
930*c77c4889SXin LI 		free(osc8_uri);
931*c77c4889SXin LI 		osc8_uri = NULL;
932*c77c4889SXin LI 	}
933*c77c4889SXin LI #endif
93489dd99dcSXin LI 	if (p == NULL || *p == '\0')
9352235c7feSXin LI 	{
9362235c7feSXin LI 		at_enter(AT_NORMAL|AT_COLOR_PROMPT);
937a5f0fb15SPaul Saab 		putchr(':');
9382235c7feSXin LI 		at_exit();
9392235c7feSXin LI 	} else
940a5f0fb15SPaul Saab 	{
941b7780dbeSXin LI #if MSDOS_COMPILER==WIN32C
942b7780dbeSXin LI 		WCHAR w[MAX_PATH*2];
943b7780dbeSXin LI 		char  a[MAX_PATH*2];
944*c77c4889SXin LI 		MultiByteToWideChar(less_acp, 0, p, -1, w, countof(w));
945b7780dbeSXin LI 		WideCharToMultiByte(utf_mode ? CP_UTF8 : GetConsoleOutputCP(),
946b7780dbeSXin LI 		                    0, w, -1, a, sizeof(a), NULL, NULL);
947b7780dbeSXin LI 		p = a;
948b7780dbeSXin LI #endif
94995270f73SXin LI 		load_line(p);
95095270f73SXin LI 		put_line();
951a5f0fb15SPaul Saab 	}
952720c436cSXin LI 	clear_eol();
953a5f0fb15SPaul Saab }
954a5f0fb15SPaul Saab 
955a5f0fb15SPaul Saab /*
956a5f0fb15SPaul Saab  * Display the less version message.
957a5f0fb15SPaul Saab  */
958d713e089SXin LI public void dispversion(void)
959a5f0fb15SPaul Saab {
960a5f0fb15SPaul Saab 	PARG parg;
961a5f0fb15SPaul Saab 
962a5f0fb15SPaul Saab 	parg.p_string = version;
963a5f0fb15SPaul Saab 	error("less %s", &parg);
964a5f0fb15SPaul Saab }
965a5f0fb15SPaul Saab 
966a5f0fb15SPaul Saab /*
967b2ea2440SXin LI  * Return a character to complete a partial command, if possible.
968b2ea2440SXin LI  */
969*c77c4889SXin LI static char getcc_end_command(void)
970b2ea2440SXin LI {
971*c77c4889SXin LI 	int ch;
972b2ea2440SXin LI 	switch (mca)
973b2ea2440SXin LI 	{
974b2ea2440SXin LI 	case A_DIGIT:
975b2ea2440SXin LI 		/* We have a number but no command.  Treat as #g. */
976b2ea2440SXin LI 		return ('g');
977b2ea2440SXin LI 	case A_F_SEARCH:
978b2ea2440SXin LI 	case A_B_SEARCH:
979d713e089SXin LI 	case A_FILTER:
980b2ea2440SXin LI 		/* We have "/string" but no newline.  Add the \n. */
981b2ea2440SXin LI 		return ('\n');
982b2ea2440SXin LI 	default:
983b2ea2440SXin LI 		/* Some other incomplete command.  Let user complete it. */
984*c77c4889SXin LI 		if (ungot != NULL)
985*c77c4889SXin LI 			return ('\0');
986*c77c4889SXin LI 		ch = getchr();
987*c77c4889SXin LI 		if (ch < 0) ch = '\0';
988*c77c4889SXin LI 		return (char) ch;
989b2ea2440SXin LI 	}
990b2ea2440SXin LI }
991b2ea2440SXin LI 
992b2ea2440SXin LI /*
993*c77c4889SXin LI  * Get a command character from the ungotten stack.
994*c77c4889SXin LI  */
995*c77c4889SXin LI static char get_ungot(lbool *p_end_command)
996*c77c4889SXin LI {
997*c77c4889SXin LI 	struct ungot *ug = ungot;
998*c77c4889SXin LI 	char c = ug->ug_char;
999*c77c4889SXin LI 	if (p_end_command != NULL)
1000*c77c4889SXin LI 		*p_end_command = ug->ug_end_command;
1001*c77c4889SXin LI 	ungot = ug->ug_next;
1002*c77c4889SXin LI 	free(ug);
1003*c77c4889SXin LI 	return c;
1004*c77c4889SXin LI }
1005*c77c4889SXin LI 
1006*c77c4889SXin LI /*
1007*c77c4889SXin LI  * Delete all ungotten characters.
1008*c77c4889SXin LI  */
1009*c77c4889SXin LI public void getcc_clear(void)
1010*c77c4889SXin LI {
1011*c77c4889SXin LI 	while (ungot != NULL)
1012*c77c4889SXin LI 		(void) get_ungot(NULL);
1013*c77c4889SXin LI }
1014*c77c4889SXin LI 
1015*c77c4889SXin LI /*
1016a5f0fb15SPaul Saab  * Get command character.
1017a5f0fb15SPaul Saab  * The character normally comes from the keyboard,
1018a5f0fb15SPaul Saab  * but may come from ungotten characters
1019a5f0fb15SPaul Saab  * (characters previously given to ungetcc or ungetsc).
1020a5f0fb15SPaul Saab  */
1021*c77c4889SXin LI static char getccu(void)
1022a5f0fb15SPaul Saab {
1023*c77c4889SXin LI 	int c = 0;
1024*c77c4889SXin LI 	while (c == 0 && !ABORT_SIGS())
10252235c7feSXin LI 	{
1026a15691bfSXin LI 		if (ungot == NULL)
102733096f16SXin LI 		{
1028b2ea2440SXin LI 			/* Normal case: no ungotten chars.
1029b2ea2440SXin LI 			 * Get char from the user. */
1030b2ea2440SXin LI 			c = getchr();
1031*c77c4889SXin LI 			if (c < 0) return ('\0');
1032b2ea2440SXin LI 		} else
1033a15691bfSXin LI 		{
1034b2ea2440SXin LI 			/* Ungotten chars available:
1035b2ea2440SXin LI 			 * Take the top of stack (most recent). */
1036*c77c4889SXin LI 			lbool end_command;
1037*c77c4889SXin LI 			c = get_ungot(&end_command);
1038*c77c4889SXin LI 			if (end_command)
1039b2ea2440SXin LI 				c = getcc_end_command();
1040a5f0fb15SPaul Saab 		}
10412235c7feSXin LI 	}
1042*c77c4889SXin LI 	return ((char) c);
104333096f16SXin LI }
1044b2ea2440SXin LI 
1045b2ea2440SXin LI /*
1046b2ea2440SXin LI  * Get a command character, but if we receive the orig sequence,
1047b2ea2440SXin LI  * convert it to the repl sequence.
1048b2ea2440SXin LI  */
1049*c77c4889SXin LI static char getcc_repl(char constant *orig, char constant *repl, char (*gr_getc)(void), void (*gr_ungetc)(char))
1050b2ea2440SXin LI {
1051*c77c4889SXin LI 	char c;
1052*c77c4889SXin LI 	char keys[16];
1053*c77c4889SXin LI 	size_t ki = 0;
1054b2ea2440SXin LI 
1055b2ea2440SXin LI 	c = (*gr_getc)();
1056b2ea2440SXin LI 	if (orig == NULL || orig[0] == '\0')
1057b2ea2440SXin LI 		return c;
1058b2ea2440SXin LI 	for (;;)
1059b2ea2440SXin LI 	{
1060b2ea2440SXin LI 		keys[ki] = c;
1061b2ea2440SXin LI 		if (c != orig[ki] || ki >= sizeof(keys)-1)
1062b2ea2440SXin LI 		{
1063b2ea2440SXin LI 			/* This is not orig we have been receiving.
1064b2ea2440SXin LI 			 * If we have stashed chars in keys[],
1065b2ea2440SXin LI 			 * unget them and return the first one. */
1066b2ea2440SXin LI 			while (ki > 0)
1067b2ea2440SXin LI 				(*gr_ungetc)(keys[ki--]);
1068b2ea2440SXin LI 			return keys[0];
1069b2ea2440SXin LI 		}
1070b2ea2440SXin LI 		if (orig[++ki] == '\0')
1071b2ea2440SXin LI 		{
1072b2ea2440SXin LI 			/* We've received the full orig sequence.
1073b2ea2440SXin LI 			 * Return the repl sequence. */
1074b2ea2440SXin LI 			ki = strlen(repl)-1;
1075b2ea2440SXin LI 			while (ki > 0)
1076b2ea2440SXin LI 				(*gr_ungetc)(repl[ki--]);
1077b2ea2440SXin LI 			return repl[0];
1078b2ea2440SXin LI 		}
1079b2ea2440SXin LI 		/* We've received a partial orig sequence (ki chars of it).
1080b2ea2440SXin LI 		 * Get next char and see if it continues to match orig. */
1081b2ea2440SXin LI 		c = (*gr_getc)();
1082b2ea2440SXin LI 	}
1083b2ea2440SXin LI }
1084b2ea2440SXin LI 
1085b2ea2440SXin LI /*
1086b2ea2440SXin LI  * Get command character.
1087b2ea2440SXin LI  */
1088*c77c4889SXin LI public char getcc(void)
1089b2ea2440SXin LI {
1090b2ea2440SXin LI 	/* Replace kent (keypad Enter) with a newline. */
1091b2ea2440SXin LI 	return getcc_repl(kent, "\n", getccu, ungetcc);
109233096f16SXin LI }
109333096f16SXin LI 
1094a5f0fb15SPaul Saab /*
1095a5f0fb15SPaul Saab  * "Unget" a command character.
1096a5f0fb15SPaul Saab  * The next getcc() will return this character.
1097a5f0fb15SPaul Saab  */
1098*c77c4889SXin LI public void ungetcc(char c)
1099a5f0fb15SPaul Saab {
110033096f16SXin LI 	struct ungot *ug = (struct ungot *) ecalloc(1, sizeof(struct ungot));
110133096f16SXin LI 
1102b2ea2440SXin LI 	ug->ug_char = c;
110333096f16SXin LI 	ug->ug_next = ungot;
110433096f16SXin LI 	ungot = ug;
1105a5f0fb15SPaul Saab }
1106a5f0fb15SPaul Saab 
1107a5f0fb15SPaul Saab /*
11082235c7feSXin LI  * "Unget" a command character.
11092235c7feSXin LI  * If any other chars are already ungotten, put this one after those.
11102235c7feSXin LI  */
1111*c77c4889SXin LI static void ungetcc_back1(char c, lbool end_command)
11122235c7feSXin LI {
11132235c7feSXin LI 	struct ungot *ug = (struct ungot *) ecalloc(1, sizeof(struct ungot));
11142235c7feSXin LI 	ug->ug_char = c;
1115*c77c4889SXin LI 	ug->ug_end_command = end_command;
11162235c7feSXin LI 	ug->ug_next = NULL;
11172235c7feSXin LI 	if (ungot == NULL)
11182235c7feSXin LI 		ungot = ug;
11192235c7feSXin LI 	else
11202235c7feSXin LI 	{
11212235c7feSXin LI 		struct ungot *pu;
11222235c7feSXin LI 		for (pu = ungot; pu->ug_next != NULL; pu = pu->ug_next)
11232235c7feSXin LI 			continue;
11242235c7feSXin LI 		pu->ug_next = ug;
11252235c7feSXin LI 	}
11262235c7feSXin LI }
11272235c7feSXin LI 
1128*c77c4889SXin LI public void ungetcc_back(char c)
1129*c77c4889SXin LI {
1130*c77c4889SXin LI 	ungetcc_back1(c, FALSE);
1131*c77c4889SXin LI }
1132*c77c4889SXin LI 
1133*c77c4889SXin LI public void ungetcc_end_command(void)
1134*c77c4889SXin LI {
1135*c77c4889SXin LI 	ungetcc_back1('\0', TRUE);
1136*c77c4889SXin LI }
1137*c77c4889SXin LI 
11382235c7feSXin LI /*
1139a5f0fb15SPaul Saab  * Unget a whole string of command characters.
1140a5f0fb15SPaul Saab  * The next sequence of getcc()'s will return this string.
1141a5f0fb15SPaul Saab  */
1142*c77c4889SXin LI public void ungetsc(constant char *s)
1143a5f0fb15SPaul Saab {
11442235c7feSXin LI 	while (*s != '\0')
11452235c7feSXin LI 		ungetcc_back(*s++);
1146a5f0fb15SPaul Saab }
1147a5f0fb15SPaul Saab 
1148a5f0fb15SPaul Saab /*
1149b2ea2440SXin LI  * Peek the next command character, without consuming it.
1150b2ea2440SXin LI  */
1151*c77c4889SXin LI public char peekcc(void)
1152b2ea2440SXin LI {
1153*c77c4889SXin LI 	char c = getcc();
1154b2ea2440SXin LI 	ungetcc(c);
1155b2ea2440SXin LI 	return c;
1156b2ea2440SXin LI }
1157b2ea2440SXin LI 
1158b2ea2440SXin LI /*
1159a5f0fb15SPaul Saab  * Search for a pattern, possibly in multiple files.
1160a5f0fb15SPaul Saab  * If SRCH_FIRST_FILE is set, begin searching at the first file.
1161a5f0fb15SPaul Saab  * If SRCH_PAST_EOF is set, continue the search thru multiple files.
1162a5f0fb15SPaul Saab  */
1163*c77c4889SXin LI static void multi_search(constant char *pattern, int n, int silent)
1164a5f0fb15SPaul Saab {
11651ea31627SRobert Watson 	int nomore;
1166a5f0fb15SPaul Saab 	IFILE save_ifile;
1167*c77c4889SXin LI 	lbool changed_file;
1168a5f0fb15SPaul Saab 
1169*c77c4889SXin LI 	changed_file = FALSE;
1170a5f0fb15SPaul Saab 	save_ifile = save_curr_ifile();
1171a5f0fb15SPaul Saab 
1172d713e089SXin LI 	if ((search_type & (SRCH_FORW|SRCH_BACK)) == 0)
1173d713e089SXin LI 		search_type |= SRCH_FORW;
1174a5f0fb15SPaul Saab 	if (search_type & SRCH_FIRST_FILE)
1175a5f0fb15SPaul Saab 	{
1176a5f0fb15SPaul Saab 		/*
1177a5f0fb15SPaul Saab 		 * Start at the first (or last) file
1178a5f0fb15SPaul Saab 		 * in the command line list.
1179a5f0fb15SPaul Saab 		 */
1180a5f0fb15SPaul Saab 		if (search_type & SRCH_FORW)
1181a5f0fb15SPaul Saab 			nomore = edit_first();
1182a5f0fb15SPaul Saab 		else
1183a5f0fb15SPaul Saab 			nomore = edit_last();
1184a5f0fb15SPaul Saab 		if (nomore)
1185a5f0fb15SPaul Saab 		{
1186a5f0fb15SPaul Saab 			unsave_ifile(save_ifile);
1187a5f0fb15SPaul Saab 			return;
1188a5f0fb15SPaul Saab 		}
1189*c77c4889SXin LI 		changed_file = TRUE;
1190a5f0fb15SPaul Saab 		search_type &= ~SRCH_FIRST_FILE;
1191a5f0fb15SPaul Saab 	}
1192a5f0fb15SPaul Saab 
1193a5f0fb15SPaul Saab 	for (;;)
1194a5f0fb15SPaul Saab 	{
1195a5f0fb15SPaul Saab 		n = search(search_type, pattern, n);
1196a5f0fb15SPaul Saab 		/*
1197a5f0fb15SPaul Saab 		 * The SRCH_NO_MOVE flag doesn't "stick": it gets cleared
1198a5f0fb15SPaul Saab 		 * after being used once.  This allows "n" to work after
1199a5f0fb15SPaul Saab 		 * using a /@@ search.
1200a5f0fb15SPaul Saab 		 */
1201a5f0fb15SPaul Saab 		search_type &= ~SRCH_NO_MOVE;
1202d713e089SXin LI 		last_search_type = search_type;
1203a5f0fb15SPaul Saab 		if (n == 0)
1204a5f0fb15SPaul Saab 		{
1205a5f0fb15SPaul Saab 			/*
1206a5f0fb15SPaul Saab 			 * Found it.
1207a5f0fb15SPaul Saab 			 */
1208a5f0fb15SPaul Saab 			unsave_ifile(save_ifile);
1209a5f0fb15SPaul Saab 			return;
1210a5f0fb15SPaul Saab 		}
1211a5f0fb15SPaul Saab 
1212a5f0fb15SPaul Saab 		if (n < 0)
1213a5f0fb15SPaul Saab 			/*
1214a5f0fb15SPaul Saab 			 * Some kind of error in the search.
1215a5f0fb15SPaul Saab 			 * Error message has been printed by search().
1216a5f0fb15SPaul Saab 			 */
1217a5f0fb15SPaul Saab 			break;
1218a5f0fb15SPaul Saab 
1219a5f0fb15SPaul Saab 		if ((search_type & SRCH_PAST_EOF) == 0)
1220a5f0fb15SPaul Saab 			/*
1221a5f0fb15SPaul Saab 			 * We didn't find a match, but we're
1222a5f0fb15SPaul Saab 			 * supposed to search only one file.
1223a5f0fb15SPaul Saab 			 */
1224a5f0fb15SPaul Saab 			break;
1225a5f0fb15SPaul Saab 		/*
1226a5f0fb15SPaul Saab 		 * Move on to the next file.
1227a5f0fb15SPaul Saab 		 */
1228a5f0fb15SPaul Saab 		if (search_type & SRCH_FORW)
1229a5f0fb15SPaul Saab 			nomore = edit_next(1);
1230a5f0fb15SPaul Saab 		else
1231a5f0fb15SPaul Saab 			nomore = edit_prev(1);
1232a5f0fb15SPaul Saab 		if (nomore)
1233a5f0fb15SPaul Saab 			break;
1234*c77c4889SXin LI 		changed_file = TRUE;
1235a5f0fb15SPaul Saab 	}
1236a5f0fb15SPaul Saab 
1237a5f0fb15SPaul Saab 	/*
1238a5f0fb15SPaul Saab 	 * Didn't find it.
1239a5f0fb15SPaul Saab 	 * Print an error message if we haven't already.
1240a5f0fb15SPaul Saab 	 */
1241a15691bfSXin LI 	if (n > 0 && !silent)
1242a5f0fb15SPaul Saab 		error("Pattern not found", NULL_PARG);
1243a5f0fb15SPaul Saab 
1244a5f0fb15SPaul Saab 	if (changed_file)
1245a5f0fb15SPaul Saab 	{
1246a5f0fb15SPaul Saab 		/*
1247a5f0fb15SPaul Saab 		 * Restore the file we were originally viewing.
1248a5f0fb15SPaul Saab 		 */
1249a5f0fb15SPaul Saab 		reedit_ifile(save_ifile);
125089dd99dcSXin LI 	} else
125189dd99dcSXin LI 	{
125289dd99dcSXin LI 		unsave_ifile(save_ifile);
1253a5f0fb15SPaul Saab 	}
1254a5f0fb15SPaul Saab }
1255a5f0fb15SPaul Saab 
1256a5f0fb15SPaul Saab /*
125796e55cc7SXin LI  * Forward forever, or until a highlighted line appears.
125896e55cc7SXin LI  */
1259d713e089SXin LI static int forw_loop(int until_hilite)
126096e55cc7SXin LI {
126196e55cc7SXin LI 	POSITION curr_len;
126296e55cc7SXin LI 
126396e55cc7SXin LI 	if (ch_getflags() & CH_HELPFILE)
126496e55cc7SXin LI 		return (A_NOACTION);
126596e55cc7SXin LI 
126696e55cc7SXin LI 	cmd_exec();
1267a15691bfSXin LI 	jump_forw_buffered();
126896e55cc7SXin LI 	curr_len = ch_length();
126996e55cc7SXin LI 	highest_hilite = until_hilite ? curr_len : NULL_POSITION;
127096e55cc7SXin LI 	ignore_eoi = 1;
127196e55cc7SXin LI 	while (!sigs)
127296e55cc7SXin LI 	{
127396e55cc7SXin LI 		if (until_hilite && highest_hilite > curr_len)
127496e55cc7SXin LI 		{
127596e55cc7SXin LI 			bell();
127696e55cc7SXin LI 			break;
127796e55cc7SXin LI 		}
127896e55cc7SXin LI 		make_display();
127996e55cc7SXin LI 		forward(1, 0, 0);
128096e55cc7SXin LI 	}
128196e55cc7SXin LI 	ignore_eoi = 0;
1282e2449719SXin LI 	ch_set_eof();
128396e55cc7SXin LI 
128496e55cc7SXin LI 	/*
128596e55cc7SXin LI 	 * This gets us back in "F mode" after processing
128696e55cc7SXin LI 	 * a non-abort signal (e.g. window-change).
128796e55cc7SXin LI 	 */
128896e55cc7SXin LI 	if (sigs && !ABORT_SIGS())
1289e2449719SXin LI 		return (until_hilite ? A_F_UNTIL_HILITE : A_F_FOREVER);
1290e2449719SXin LI 
129196e55cc7SXin LI 	return (A_NOACTION);
129296e55cc7SXin LI }
129396e55cc7SXin LI 
129496e55cc7SXin LI /*
1295a5f0fb15SPaul Saab  * Main command processor.
1296a5f0fb15SPaul Saab  * Accept and execute commands until a quit command.
1297a5f0fb15SPaul Saab  */
1298d713e089SXin LI public void commands(void)
1299a5f0fb15SPaul Saab {
1300*c77c4889SXin LI 	char c;
13011ea31627SRobert Watson 	int action;
1302*c77c4889SXin LI 	constant char *cbuf;
1303*c77c4889SXin LI 	constant char *msg;
1304a5f0fb15SPaul Saab 	int newaction;
13052235c7feSXin LI 	int save_jump_sline;
1306a5f0fb15SPaul Saab 	int save_search_type;
1307*c77c4889SXin LI 	constant char *extra;
1308a5f0fb15SPaul Saab 	PARG parg;
1309a5f0fb15SPaul Saab 	IFILE old_ifile;
1310a5f0fb15SPaul Saab 	IFILE new_ifile;
1311*c77c4889SXin LI 	constant char *tagfile;
1312a5f0fb15SPaul Saab 
1313a5f0fb15SPaul Saab 	search_type = SRCH_FORW;
1314a5f0fb15SPaul Saab 	wscroll = (sc_height + 1) / 2;
1315a5f0fb15SPaul Saab 	newaction = A_NOACTION;
1316a5f0fb15SPaul Saab 
1317a5f0fb15SPaul Saab 	for (;;)
1318a5f0fb15SPaul Saab 	{
1319b7780dbeSXin LI 		clear_mca();
1320a5f0fb15SPaul Saab 		cmd_accept();
1321a5f0fb15SPaul Saab 		number = 0;
132233096f16SXin LI 		curropt = NULL;
1323a5f0fb15SPaul Saab 
1324a5f0fb15SPaul Saab 		/*
1325a5f0fb15SPaul Saab 		 * See if any signals need processing.
1326a5f0fb15SPaul Saab 		 */
1327a5f0fb15SPaul Saab 		if (sigs)
1328a5f0fb15SPaul Saab 		{
1329a5f0fb15SPaul Saab 			psignals();
1330a5f0fb15SPaul Saab 			if (quitting)
1331a5f0fb15SPaul Saab 				quit(QUIT_SAVED_STATUS);
1332a5f0fb15SPaul Saab 		}
1333a5f0fb15SPaul Saab 
1334a5f0fb15SPaul Saab 		/*
1335a5f0fb15SPaul Saab 		 * See if window size changed, for systems that don't
1336a5f0fb15SPaul Saab 		 * generate SIGWINCH.
1337a5f0fb15SPaul Saab 		 */
1338a5f0fb15SPaul Saab 		check_winch();
1339a5f0fb15SPaul Saab 
1340a5f0fb15SPaul Saab 		/*
1341a5f0fb15SPaul Saab 		 * Display prompt and accept a character.
1342a5f0fb15SPaul Saab 		 */
1343a5f0fb15SPaul Saab 		cmd_reset();
1344a5f0fb15SPaul Saab 		prompt();
1345a5f0fb15SPaul Saab 		if (sigs)
1346a5f0fb15SPaul Saab 			continue;
1347a5f0fb15SPaul Saab 		if (newaction == A_NOACTION)
1348a5f0fb15SPaul Saab 			c = getcc();
1349a5f0fb15SPaul Saab 
1350a5f0fb15SPaul Saab 	again:
1351a5f0fb15SPaul Saab 		if (sigs)
1352a5f0fb15SPaul Saab 			continue;
1353a5f0fb15SPaul Saab 
1354a5f0fb15SPaul Saab 		if (newaction != A_NOACTION)
1355a5f0fb15SPaul Saab 		{
1356a5f0fb15SPaul Saab 			action = newaction;
1357a5f0fb15SPaul Saab 			newaction = A_NOACTION;
1358a5f0fb15SPaul Saab 		} else
1359a5f0fb15SPaul Saab 		{
1360a5f0fb15SPaul Saab 			/*
1361a5f0fb15SPaul Saab 			 * If we are in a multicharacter command, call mca_char.
1362a5f0fb15SPaul Saab 			 * Otherwise we call fcmd_decode to determine the
1363a5f0fb15SPaul Saab 			 * action to be performed.
1364a5f0fb15SPaul Saab 			 */
1365a5f0fb15SPaul Saab 			if (mca)
1366a5f0fb15SPaul Saab 				switch (mca_char(c))
1367a5f0fb15SPaul Saab 				{
1368a5f0fb15SPaul Saab 				case MCA_MORE:
1369a5f0fb15SPaul Saab 					/*
1370a5f0fb15SPaul Saab 					 * Need another character.
1371a5f0fb15SPaul Saab 					 */
1372a5f0fb15SPaul Saab 					c = getcc();
1373a5f0fb15SPaul Saab 					goto again;
1374a5f0fb15SPaul Saab 				case MCA_DONE:
1375a5f0fb15SPaul Saab 					/*
1376a5f0fb15SPaul Saab 					 * Command has been handled by mca_char.
1377a5f0fb15SPaul Saab 					 * Start clean with a prompt.
1378a5f0fb15SPaul Saab 					 */
1379a5f0fb15SPaul Saab 					continue;
1380a5f0fb15SPaul Saab 				case NO_MCA:
1381a5f0fb15SPaul Saab 					/*
1382a5f0fb15SPaul Saab 					 * Not a multi-char command
1383a5f0fb15SPaul Saab 					 * (at least, not anymore).
1384a5f0fb15SPaul Saab 					 */
1385a5f0fb15SPaul Saab 					break;
1386a5f0fb15SPaul Saab 				}
1387a5f0fb15SPaul Saab 
1388a5f0fb15SPaul Saab 			/*
1389a5f0fb15SPaul Saab 			 * Decode the command character and decide what to do.
1390a5f0fb15SPaul Saab 			 */
1391*c77c4889SXin LI 			extra = NULL;
1392a5f0fb15SPaul Saab 			if (mca)
1393a5f0fb15SPaul Saab 			{
1394a5f0fb15SPaul Saab 				/*
1395a5f0fb15SPaul Saab 				 * We're in a multichar command.
1396a5f0fb15SPaul Saab 				 * Add the character to the command buffer
1397a5f0fb15SPaul Saab 				 * and display it on the screen.
1398a5f0fb15SPaul Saab 				 * If the user backspaces past the start
1399a5f0fb15SPaul Saab 				 * of the line, abort the command.
1400a5f0fb15SPaul Saab 				 */
1401a5f0fb15SPaul Saab 				if (cmd_char(c) == CC_QUIT || len_cmdbuf() == 0)
1402a5f0fb15SPaul Saab 					continue;
1403a5f0fb15SPaul Saab 				cbuf = get_cmdbuf();
140495270f73SXin LI 				if (cbuf == NULL)
140595270f73SXin LI 					continue;
1406*c77c4889SXin LI 				action = fcmd_decode(cbuf, &extra);
1407a5f0fb15SPaul Saab 			} else
1408a5f0fb15SPaul Saab 			{
1409a5f0fb15SPaul Saab 				/*
1410a5f0fb15SPaul Saab 				 * Don't use cmd_char if we're starting fresh
1411a5f0fb15SPaul Saab 				 * at the beginning of a command, because we
1412a5f0fb15SPaul Saab 				 * don't want to echo the command until we know
1413a5f0fb15SPaul Saab 				 * it is a multichar command.  We also don't
1414a5f0fb15SPaul Saab 				 * want erase_char/kill_char to be treated
1415a5f0fb15SPaul Saab 				 * as line editing characters.
1416a5f0fb15SPaul Saab 				 */
1417*c77c4889SXin LI 				constant char tbuf[2] = { c, '\0' };
1418*c77c4889SXin LI 				action = fcmd_decode(tbuf, &extra);
1419a5f0fb15SPaul Saab 			}
1420a5f0fb15SPaul Saab 			/*
1421a5f0fb15SPaul Saab 			 * If an "extra" string was returned,
1422a5f0fb15SPaul Saab 			 * process it as a string of command characters.
1423a5f0fb15SPaul Saab 			 */
1424a5f0fb15SPaul Saab 			if (extra != NULL)
1425a5f0fb15SPaul Saab 				ungetsc(extra);
1426a5f0fb15SPaul Saab 		}
1427a5f0fb15SPaul Saab 		/*
1428a5f0fb15SPaul Saab 		 * Clear the cmdbuf string.
1429a5f0fb15SPaul Saab 		 * (But not if we're in the prefix of a command,
1430a5f0fb15SPaul Saab 		 * because the partial command string is kept there.)
1431a5f0fb15SPaul Saab 		 */
1432a5f0fb15SPaul Saab 		if (action != A_PREFIX)
1433a5f0fb15SPaul Saab 			cmd_reset();
1434a5f0fb15SPaul Saab 
1435a5f0fb15SPaul Saab 		switch (action)
1436a5f0fb15SPaul Saab 		{
1437a5f0fb15SPaul Saab 		case A_DIGIT:
1438a5f0fb15SPaul Saab 			/*
1439a5f0fb15SPaul Saab 			 * First digit of a number.
1440a5f0fb15SPaul Saab 			 */
1441*c77c4889SXin LI 			start_mca(A_DIGIT, ":", NULL, CF_QUIT_ON_ERASE);
1442a5f0fb15SPaul Saab 			goto again;
1443a5f0fb15SPaul Saab 
1444a5f0fb15SPaul Saab 		case A_F_WINDOW:
1445a5f0fb15SPaul Saab 			/*
1446a5f0fb15SPaul Saab 			 * Forward one window (and set the window size).
1447a5f0fb15SPaul Saab 			 */
1448a5f0fb15SPaul Saab 			if (number > 0)
14491ede1615STim J. Robbins 				swindow = (int) number;
1450a5f0fb15SPaul Saab 			/* FALLTHRU */
1451a5f0fb15SPaul Saab 		case A_F_SCREEN:
1452a5f0fb15SPaul Saab 			/*
1453a5f0fb15SPaul Saab 			 * Forward one screen.
1454a5f0fb15SPaul Saab 			 */
1455a5f0fb15SPaul Saab 			if (number <= 0)
1456a5f0fb15SPaul Saab 				number = get_swindow();
1457a5f0fb15SPaul Saab 			cmd_exec();
1458a5f0fb15SPaul Saab 			if (show_attn)
1459a5f0fb15SPaul Saab 				set_attnpos(bottompos);
14601ede1615STim J. Robbins 			forward((int) number, 0, 1);
1461a5f0fb15SPaul Saab 			break;
1462a5f0fb15SPaul Saab 
1463a5f0fb15SPaul Saab 		case A_B_WINDOW:
1464a5f0fb15SPaul Saab 			/*
1465a5f0fb15SPaul Saab 			 * Backward one window (and set the window size).
1466a5f0fb15SPaul Saab 			 */
1467a5f0fb15SPaul Saab 			if (number > 0)
14681ede1615STim J. Robbins 				swindow = (int) number;
1469a5f0fb15SPaul Saab 			/* FALLTHRU */
1470a5f0fb15SPaul Saab 		case A_B_SCREEN:
1471a5f0fb15SPaul Saab 			/*
1472a5f0fb15SPaul Saab 			 * Backward one screen.
1473a5f0fb15SPaul Saab 			 */
1474a5f0fb15SPaul Saab 			if (number <= 0)
1475a5f0fb15SPaul Saab 				number = get_swindow();
1476a5f0fb15SPaul Saab 			cmd_exec();
14771ede1615STim J. Robbins 			backward((int) number, 0, 1);
1478a5f0fb15SPaul Saab 			break;
1479a5f0fb15SPaul Saab 
1480a5f0fb15SPaul Saab 		case A_F_LINE:
1481a5f0fb15SPaul Saab 			/*
1482a5f0fb15SPaul Saab 			 * Forward N (default 1) line.
1483a5f0fb15SPaul Saab 			 */
1484a5f0fb15SPaul Saab 			if (number <= 0)
1485a5f0fb15SPaul Saab 				number = 1;
1486a5f0fb15SPaul Saab 			cmd_exec();
1487a5f0fb15SPaul Saab 			if (show_attn == OPT_ONPLUS && number > 1)
1488a5f0fb15SPaul Saab 				set_attnpos(bottompos);
14891ede1615STim J. Robbins 			forward((int) number, 0, 0);
1490a5f0fb15SPaul Saab 			break;
1491a5f0fb15SPaul Saab 
1492a5f0fb15SPaul Saab 		case A_B_LINE:
1493a5f0fb15SPaul Saab 			/*
1494a5f0fb15SPaul Saab 			 * Backward N (default 1) line.
1495a5f0fb15SPaul Saab 			 */
1496a5f0fb15SPaul Saab 			if (number <= 0)
1497a5f0fb15SPaul Saab 				number = 1;
1498a5f0fb15SPaul Saab 			cmd_exec();
14991ede1615STim J. Robbins 			backward((int) number, 0, 0);
1500a5f0fb15SPaul Saab 			break;
1501a5f0fb15SPaul Saab 
1502b7780dbeSXin LI 		case A_F_MOUSE:
1503b7780dbeSXin LI 			/*
1504b7780dbeSXin LI 			 * Forward wheel_lines lines.
1505b7780dbeSXin LI 			 */
1506b7780dbeSXin LI 			cmd_exec();
1507b7780dbeSXin LI 			forward(wheel_lines, 0, 0);
1508b7780dbeSXin LI 			break;
1509b7780dbeSXin LI 
1510b7780dbeSXin LI 		case A_B_MOUSE:
1511b7780dbeSXin LI 			/*
1512b7780dbeSXin LI 			 * Backward wheel_lines lines.
1513b7780dbeSXin LI 			 */
1514b7780dbeSXin LI 			cmd_exec();
1515b7780dbeSXin LI 			backward(wheel_lines, 0, 0);
1516b7780dbeSXin LI 			break;
1517b7780dbeSXin LI 
1518a5f0fb15SPaul Saab 		case A_FF_LINE:
1519a5f0fb15SPaul Saab 			/*
1520a5f0fb15SPaul Saab 			 * Force forward N (default 1) line.
1521a5f0fb15SPaul Saab 			 */
1522a5f0fb15SPaul Saab 			if (number <= 0)
1523a5f0fb15SPaul Saab 				number = 1;
1524a5f0fb15SPaul Saab 			cmd_exec();
1525a5f0fb15SPaul Saab 			if (show_attn == OPT_ONPLUS && number > 1)
1526a5f0fb15SPaul Saab 				set_attnpos(bottompos);
15271ede1615STim J. Robbins 			forward((int) number, 1, 0);
1528a5f0fb15SPaul Saab 			break;
1529a5f0fb15SPaul Saab 
1530a5f0fb15SPaul Saab 		case A_BF_LINE:
1531a5f0fb15SPaul Saab 			/*
1532a5f0fb15SPaul Saab 			 * Force backward N (default 1) line.
1533a5f0fb15SPaul Saab 			 */
1534a5f0fb15SPaul Saab 			if (number <= 0)
1535a5f0fb15SPaul Saab 				number = 1;
1536a5f0fb15SPaul Saab 			cmd_exec();
15371ede1615STim J. Robbins 			backward((int) number, 1, 0);
1538a5f0fb15SPaul Saab 			break;
1539a5f0fb15SPaul Saab 
1540a5f0fb15SPaul Saab 		case A_FF_SCREEN:
1541a5f0fb15SPaul Saab 			/*
1542a5f0fb15SPaul Saab 			 * Force forward one screen.
1543a5f0fb15SPaul Saab 			 */
1544a5f0fb15SPaul Saab 			if (number <= 0)
1545a5f0fb15SPaul Saab 				number = get_swindow();
1546a5f0fb15SPaul Saab 			cmd_exec();
1547a5f0fb15SPaul Saab 			if (show_attn == OPT_ONPLUS)
1548a5f0fb15SPaul Saab 				set_attnpos(bottompos);
15491ede1615STim J. Robbins 			forward((int) number, 1, 0);
1550a5f0fb15SPaul Saab 			break;
1551a5f0fb15SPaul Saab 
1552a5f0fb15SPaul Saab 		case A_F_FOREVER:
1553a5f0fb15SPaul Saab 			/*
1554a5f0fb15SPaul Saab 			 * Forward forever, ignoring EOF.
1555a5f0fb15SPaul Saab 			 */
1556a15691bfSXin LI 			if (show_attn)
1557a15691bfSXin LI 				set_attnpos(bottompos);
155896e55cc7SXin LI 			newaction = forw_loop(0);
1559a5f0fb15SPaul Saab 			break;
156096e55cc7SXin LI 
156196e55cc7SXin LI 		case A_F_UNTIL_HILITE:
156296e55cc7SXin LI 			newaction = forw_loop(1);
1563a5f0fb15SPaul Saab 			break;
1564a5f0fb15SPaul Saab 
1565a5f0fb15SPaul Saab 		case A_F_SCROLL:
1566a5f0fb15SPaul Saab 			/*
1567a5f0fb15SPaul Saab 			 * Forward N lines
1568a5f0fb15SPaul Saab 			 * (default same as last 'd' or 'u' command).
1569a5f0fb15SPaul Saab 			 */
1570a5f0fb15SPaul Saab 			if (number > 0)
15711ede1615STim J. Robbins 				wscroll = (int) number;
1572a5f0fb15SPaul Saab 			cmd_exec();
1573a5f0fb15SPaul Saab 			if (show_attn == OPT_ONPLUS)
1574a5f0fb15SPaul Saab 				set_attnpos(bottompos);
1575a5f0fb15SPaul Saab 			forward(wscroll, 0, 0);
1576a5f0fb15SPaul Saab 			break;
1577a5f0fb15SPaul Saab 
1578a5f0fb15SPaul Saab 		case A_B_SCROLL:
1579a5f0fb15SPaul Saab 			/*
1580a5f0fb15SPaul Saab 			 * Forward N lines
1581a5f0fb15SPaul Saab 			 * (default same as last 'd' or 'u' command).
1582a5f0fb15SPaul Saab 			 */
1583a5f0fb15SPaul Saab 			if (number > 0)
15841ede1615STim J. Robbins 				wscroll = (int) number;
1585a5f0fb15SPaul Saab 			cmd_exec();
1586a5f0fb15SPaul Saab 			backward(wscroll, 0, 0);
1587a5f0fb15SPaul Saab 			break;
1588a5f0fb15SPaul Saab 
1589a5f0fb15SPaul Saab 		case A_FREPAINT:
1590a5f0fb15SPaul Saab 			/*
1591a5f0fb15SPaul Saab 			 * Flush buffers, then repaint screen.
1592a5f0fb15SPaul Saab 			 * Don't flush the buffers on a pipe!
1593a5f0fb15SPaul Saab 			 */
1594423c5ce5SXin LI 			clear_buffers();
1595a5f0fb15SPaul Saab 			/* FALLTHRU */
1596a5f0fb15SPaul Saab 		case A_REPAINT:
1597a5f0fb15SPaul Saab 			/*
1598a5f0fb15SPaul Saab 			 * Repaint screen.
1599a5f0fb15SPaul Saab 			 */
1600a5f0fb15SPaul Saab 			cmd_exec();
1601a5f0fb15SPaul Saab 			repaint();
1602a5f0fb15SPaul Saab 			break;
1603a5f0fb15SPaul Saab 
1604a5f0fb15SPaul Saab 		case A_GOLINE:
1605a5f0fb15SPaul Saab 			/*
1606a5f0fb15SPaul Saab 			 * Go to line N, default beginning of file.
16072235c7feSXin LI 			 * If N <= 0, ignore jump_sline in order to avoid
16082235c7feSXin LI 			 * empty lines before the beginning of the file.
1609a5f0fb15SPaul Saab 			 */
16102235c7feSXin LI 			save_jump_sline = jump_sline;
1611a5f0fb15SPaul Saab 			if (number <= 0)
16122235c7feSXin LI 			{
1613a5f0fb15SPaul Saab 				number = 1;
16142235c7feSXin LI 				jump_sline = 0;
16152235c7feSXin LI 			}
1616a5f0fb15SPaul Saab 			cmd_exec();
1617a5f0fb15SPaul Saab 			jump_back(number);
16182235c7feSXin LI 			jump_sline = save_jump_sline;
1619a5f0fb15SPaul Saab 			break;
1620a5f0fb15SPaul Saab 
1621a5f0fb15SPaul Saab 		case A_PERCENT:
1622a5f0fb15SPaul Saab 			/*
1623a5f0fb15SPaul Saab 			 * Go to a specified percentage into the file.
1624a5f0fb15SPaul Saab 			 */
1625a5f0fb15SPaul Saab 			if (number < 0)
1626720c436cSXin LI 			{
1627a5f0fb15SPaul Saab 				number = 0;
1628720c436cSXin LI 				fraction = 0;
1629720c436cSXin LI 			}
1630b7780dbeSXin LI 			if (number > 100 || (number == 100 && fraction != 0))
1631720c436cSXin LI 			{
1632a5f0fb15SPaul Saab 				number = 100;
1633720c436cSXin LI 				fraction = 0;
1634720c436cSXin LI 			}
1635a5f0fb15SPaul Saab 			cmd_exec();
1636720c436cSXin LI 			jump_percent((int) number, fraction);
1637a5f0fb15SPaul Saab 			break;
1638a5f0fb15SPaul Saab 
1639a5f0fb15SPaul Saab 		case A_GOEND:
1640a5f0fb15SPaul Saab 			/*
1641a5f0fb15SPaul Saab 			 * Go to line N, default end of file.
1642a5f0fb15SPaul Saab 			 */
1643a5f0fb15SPaul Saab 			cmd_exec();
1644a5f0fb15SPaul Saab 			if (number <= 0)
1645a5f0fb15SPaul Saab 				jump_forw();
1646a5f0fb15SPaul Saab 			else
1647a5f0fb15SPaul Saab 				jump_back(number);
1648a5f0fb15SPaul Saab 			break;
1649a5f0fb15SPaul Saab 
1650a15691bfSXin LI 		case A_GOEND_BUF:
1651a15691bfSXin LI 			/*
1652a15691bfSXin LI 			 * Go to line N, default last buffered byte.
1653a15691bfSXin LI 			 */
1654a15691bfSXin LI 			cmd_exec();
1655a15691bfSXin LI 			if (number <= 0)
1656a15691bfSXin LI 				jump_forw_buffered();
1657a15691bfSXin LI 			else
1658a15691bfSXin LI 				jump_back(number);
1659a15691bfSXin LI 			break;
1660a15691bfSXin LI 
1661a5f0fb15SPaul Saab 		case A_GOPOS:
1662a5f0fb15SPaul Saab 			/*
1663a5f0fb15SPaul Saab 			 * Go to a specified byte position in the file.
1664a5f0fb15SPaul Saab 			 */
1665a5f0fb15SPaul Saab 			cmd_exec();
1666a5f0fb15SPaul Saab 			if (number < 0)
1667a5f0fb15SPaul Saab 				number = 0;
1668a5f0fb15SPaul Saab 			jump_line_loc((POSITION) number, jump_sline);
1669a5f0fb15SPaul Saab 			break;
1670a5f0fb15SPaul Saab 
1671a5f0fb15SPaul Saab 		case A_STAT:
1672a5f0fb15SPaul Saab 			/*
1673a5f0fb15SPaul Saab 			 * Print file name, etc.
1674a5f0fb15SPaul Saab 			 */
1675a5f0fb15SPaul Saab 			if (ch_getflags() & CH_HELPFILE)
1676a5f0fb15SPaul Saab 				break;
1677a5f0fb15SPaul Saab 			cmd_exec();
1678a5f0fb15SPaul Saab 			parg.p_string = eq_message();
1679a5f0fb15SPaul Saab 			error("%s", &parg);
1680a5f0fb15SPaul Saab 			break;
1681a5f0fb15SPaul Saab 
1682a5f0fb15SPaul Saab 		case A_VERSION:
1683a5f0fb15SPaul Saab 			/*
16842235c7feSXin LI 			 * Print version number.
1685a5f0fb15SPaul Saab 			 */
1686a5f0fb15SPaul Saab 			cmd_exec();
1687a5f0fb15SPaul Saab 			dispversion();
1688a5f0fb15SPaul Saab 			break;
1689a5f0fb15SPaul Saab 
1690a5f0fb15SPaul Saab 		case A_QUIT:
1691a5f0fb15SPaul Saab 			/*
1692a5f0fb15SPaul Saab 			 * Exit.
1693a5f0fb15SPaul Saab 			 */
1694a5f0fb15SPaul Saab 			if (curr_ifile != NULL_IFILE &&
1695a5f0fb15SPaul Saab 			    ch_getflags() & CH_HELPFILE)
1696a5f0fb15SPaul Saab 			{
1697a5f0fb15SPaul Saab 				/*
1698a5f0fb15SPaul Saab 				 * Quit while viewing the help file
1699a5f0fb15SPaul Saab 				 * just means return to viewing the
1700a5f0fb15SPaul Saab 				 * previous file.
1701a5f0fb15SPaul Saab 				 */
170289dd99dcSXin LI 				hshift = save_hshift;
1703a15691bfSXin LI 				bs_mode = save_bs_mode;
1704d713e089SXin LI 				proc_backspace = save_proc_backspace;
1705a5f0fb15SPaul Saab 				if (edit_prev(1) == 0)
1706a5f0fb15SPaul Saab 					break;
1707a5f0fb15SPaul Saab 			}
1708a5f0fb15SPaul Saab 			if (extra != NULL)
1709a5f0fb15SPaul Saab 				quit(*extra);
1710a5f0fb15SPaul Saab 			quit(QUIT_OK);
1711a5f0fb15SPaul Saab 			break;
1712a5f0fb15SPaul Saab 
1713a5f0fb15SPaul Saab /*
1714a5f0fb15SPaul Saab  * Define abbreviation for a commonly used sequence below.
1715a5f0fb15SPaul Saab  */
1716423c5ce5SXin LI #define DO_SEARCH() \
1717423c5ce5SXin LI 			if (number <= 0) number = 1;    \
1718a5f0fb15SPaul Saab 			mca_search();                   \
1719a5f0fb15SPaul Saab 			cmd_exec();                     \
1720*c77c4889SXin LI 			multi_search(NULL, (int) number, 0);
1721a5f0fb15SPaul Saab 
1722a5f0fb15SPaul Saab 		case A_F_SEARCH:
1723a5f0fb15SPaul Saab 			/*
1724a5f0fb15SPaul Saab 			 * Search forward for a pattern.
1725a5f0fb15SPaul Saab 			 * Get the first char of the pattern.
1726a5f0fb15SPaul Saab 			 */
172795270f73SXin LI 			search_type = SRCH_FORW | def_search_type;
1728a5f0fb15SPaul Saab 			if (number <= 0)
1729a5f0fb15SPaul Saab 				number = 1;
1730*c77c4889SXin LI 			literal_char = FALSE;
1731a5f0fb15SPaul Saab 			mca_search();
1732a5f0fb15SPaul Saab 			c = getcc();
1733a5f0fb15SPaul Saab 			goto again;
1734a5f0fb15SPaul Saab 
1735a5f0fb15SPaul Saab 		case A_B_SEARCH:
1736a5f0fb15SPaul Saab 			/*
1737a5f0fb15SPaul Saab 			 * Search backward for a pattern.
1738a5f0fb15SPaul Saab 			 * Get the first char of the pattern.
1739a5f0fb15SPaul Saab 			 */
174095270f73SXin LI 			search_type = SRCH_BACK | def_search_type;
1741a5f0fb15SPaul Saab 			if (number <= 0)
1742a5f0fb15SPaul Saab 				number = 1;
1743*c77c4889SXin LI 			literal_char = FALSE;
1744a5f0fb15SPaul Saab 			mca_search();
1745a5f0fb15SPaul Saab 			c = getcc();
1746a5f0fb15SPaul Saab 			goto again;
1747a5f0fb15SPaul Saab 
1748*c77c4889SXin LI 		case A_OSC8_F_SEARCH:
1749*c77c4889SXin LI #if OSC8_LINK
1750*c77c4889SXin LI 			cmd_exec();
1751*c77c4889SXin LI 			if (number <= 0)
1752*c77c4889SXin LI 				number = 1;
1753*c77c4889SXin LI 			osc8_search(SRCH_FORW, NULL, number);
1754*c77c4889SXin LI #else
1755*c77c4889SXin LI 			error("Command not available", NULL_PARG);
1756*c77c4889SXin LI #endif
1757*c77c4889SXin LI 			break;
1758*c77c4889SXin LI 
1759*c77c4889SXin LI 		case A_OSC8_B_SEARCH:
1760*c77c4889SXin LI #if OSC8_LINK
1761*c77c4889SXin LI 			cmd_exec();
1762*c77c4889SXin LI 			if (number <= 0)
1763*c77c4889SXin LI 				number = 1;
1764*c77c4889SXin LI 			osc8_search(SRCH_BACK, NULL, number);
1765*c77c4889SXin LI #else
1766*c77c4889SXin LI 			error("Command not available", NULL_PARG);
1767*c77c4889SXin LI #endif
1768*c77c4889SXin LI 			break;
1769*c77c4889SXin LI 
1770*c77c4889SXin LI 		case A_OSC8_OPEN:
1771*c77c4889SXin LI #if OSC8_LINK
1772*c77c4889SXin LI 			if (secure_allow(SF_OSC8_OPEN))
1773*c77c4889SXin LI 			{
1774*c77c4889SXin LI 				cmd_exec();
1775*c77c4889SXin LI 				osc8_open();
1776*c77c4889SXin LI 				break;
1777*c77c4889SXin LI 			}
1778*c77c4889SXin LI #endif
1779*c77c4889SXin LI 			error("Command not available", NULL_PARG);
1780*c77c4889SXin LI 			break;
1781*c77c4889SXin LI 
1782*c77c4889SXin LI 		case A_OSC8_JUMP:
1783*c77c4889SXin LI #if OSC8_LINK
1784*c77c4889SXin LI 			cmd_exec();
1785*c77c4889SXin LI 			osc8_jump();
1786*c77c4889SXin LI #else
1787*c77c4889SXin LI 			error("Command not available", NULL_PARG);
1788*c77c4889SXin LI #endif
1789*c77c4889SXin LI 			break;
1790*c77c4889SXin LI 
17917374caaaSXin LI 		case A_FILTER:
17927374caaaSXin LI #if HILITE_SEARCH
17937374caaaSXin LI 			search_type = SRCH_FORW | SRCH_FILTER;
1794*c77c4889SXin LI 			literal_char = FALSE;
17957374caaaSXin LI 			mca_search();
17967374caaaSXin LI 			c = getcc();
17977374caaaSXin LI 			goto again;
17987374caaaSXin LI #else
17997374caaaSXin LI 			error("Command not available", NULL_PARG);
18007374caaaSXin LI 			break;
18017374caaaSXin LI #endif
18027374caaaSXin LI 
1803a5f0fb15SPaul Saab 		case A_AGAIN_SEARCH:
1804a5f0fb15SPaul Saab 			/*
1805a5f0fb15SPaul Saab 			 * Repeat previous search.
1806a5f0fb15SPaul Saab 			 */
1807d713e089SXin LI 			search_type = last_search_type;
1808a5f0fb15SPaul Saab 			DO_SEARCH();
1809a5f0fb15SPaul Saab 			break;
1810a5f0fb15SPaul Saab 
1811a5f0fb15SPaul Saab 		case A_T_AGAIN_SEARCH:
1812a5f0fb15SPaul Saab 			/*
1813a5f0fb15SPaul Saab 			 * Repeat previous search, multiple files.
1814a5f0fb15SPaul Saab 			 */
1815d713e089SXin LI 			search_type = last_search_type | SRCH_PAST_EOF;
1816a5f0fb15SPaul Saab 			DO_SEARCH();
1817a5f0fb15SPaul Saab 			break;
1818a5f0fb15SPaul Saab 
1819a5f0fb15SPaul Saab 		case A_REVERSE_SEARCH:
1820a5f0fb15SPaul Saab 			/*
1821a5f0fb15SPaul Saab 			 * Repeat previous search, in reverse direction.
1822a5f0fb15SPaul Saab 			 */
1823d713e089SXin LI 			save_search_type = search_type = last_search_type;
1824a5f0fb15SPaul Saab 			search_type = SRCH_REVERSE(search_type);
1825a5f0fb15SPaul Saab 			DO_SEARCH();
1826d713e089SXin LI 			last_search_type = save_search_type;
1827a5f0fb15SPaul Saab 			break;
1828a5f0fb15SPaul Saab 
1829a5f0fb15SPaul Saab 		case A_T_REVERSE_SEARCH:
1830a5f0fb15SPaul Saab 			/*
1831a5f0fb15SPaul Saab 			 * Repeat previous search,
1832a5f0fb15SPaul Saab 			 * multiple files in reverse direction.
1833a5f0fb15SPaul Saab 			 */
1834d713e089SXin LI 			save_search_type = search_type = last_search_type;
1835d713e089SXin LI 			search_type = SRCH_REVERSE(search_type) | SRCH_PAST_EOF;
1836a5f0fb15SPaul Saab 			DO_SEARCH();
1837d713e089SXin LI 			last_search_type = save_search_type;
1838a5f0fb15SPaul Saab 			break;
1839a5f0fb15SPaul Saab 
1840a5f0fb15SPaul Saab 		case A_UNDO_SEARCH:
18412235c7feSXin LI 		case A_CLR_SEARCH:
1842b2ea2440SXin LI 			/*
1843b2ea2440SXin LI 			 * Clear search string highlighting.
1844b2ea2440SXin LI 			 */
18452235c7feSXin LI 			undo_search(action == A_CLR_SEARCH);
1846a5f0fb15SPaul Saab 			break;
1847a5f0fb15SPaul Saab 
1848a5f0fb15SPaul Saab 		case A_HELP:
1849a5f0fb15SPaul Saab 			/*
1850a5f0fb15SPaul Saab 			 * Help.
1851a5f0fb15SPaul Saab 			 */
1852a5f0fb15SPaul Saab 			if (ch_getflags() & CH_HELPFILE)
1853a5f0fb15SPaul Saab 				break;
1854a5f0fb15SPaul Saab 			cmd_exec();
185589dd99dcSXin LI 			save_hshift = hshift;
185689dd99dcSXin LI 			hshift = 0;
1857a15691bfSXin LI 			save_bs_mode = bs_mode;
1858a15691bfSXin LI 			bs_mode = BS_SPECIAL;
1859d713e089SXin LI 			save_proc_backspace = proc_backspace;
1860d713e089SXin LI 			proc_backspace = OPT_OFF;
1861a5f0fb15SPaul Saab 			(void) edit(FAKE_HELPFILE);
1862a5f0fb15SPaul Saab 			break;
1863a5f0fb15SPaul Saab 
1864a5f0fb15SPaul Saab 		case A_EXAMINE:
1865a5f0fb15SPaul Saab 			/*
1866a5f0fb15SPaul Saab 			 * Edit a new file.  Get the filename.
1867a5f0fb15SPaul Saab 			 */
1868b2ea2440SXin LI #if EXAMINE
1869*c77c4889SXin LI 			if (secure_allow(SF_EXAMINE))
1870a5f0fb15SPaul Saab 			{
1871dd3bd0edSDimitry Andric 				start_mca(A_EXAMINE, "Examine: ", ml_examine, 0);
1872a5f0fb15SPaul Saab 				c = getcc();
1873a5f0fb15SPaul Saab 				goto again;
1874b2ea2440SXin LI 			}
1875b2ea2440SXin LI #endif
1876a5f0fb15SPaul Saab 			error("Command not available", NULL_PARG);
1877a5f0fb15SPaul Saab 			break;
1878a5f0fb15SPaul Saab 
1879a5f0fb15SPaul Saab 		case A_VISUAL:
1880a5f0fb15SPaul Saab 			/*
1881a5f0fb15SPaul Saab 			 * Invoke an editor on the input file.
1882a5f0fb15SPaul Saab 			 */
1883a5f0fb15SPaul Saab #if EDITOR
1884*c77c4889SXin LI 			if (secure_allow(SF_EDIT))
1885a5f0fb15SPaul Saab 			{
1886a5f0fb15SPaul Saab 				if (ch_getflags() & CH_HELPFILE)
1887a5f0fb15SPaul Saab 					break;
1888a5f0fb15SPaul Saab 				if (strcmp(get_filename(curr_ifile), "-") == 0)
1889a5f0fb15SPaul Saab 				{
1890a5f0fb15SPaul Saab 					error("Cannot edit standard input", NULL_PARG);
1891a5f0fb15SPaul Saab 					break;
1892a5f0fb15SPaul Saab 				}
1893b2ea2440SXin LI 				if (get_altfilename(curr_ifile) != NULL)
1894a5f0fb15SPaul Saab 				{
189589dd99dcSXin LI 					error("WARNING: This file was viewed via LESSOPEN",
1896a5f0fb15SPaul Saab 						NULL_PARG);
1897a5f0fb15SPaul Saab 				}
1898dd3bd0edSDimitry Andric 				start_mca(A_SHELL, "!", ml_shell, 0);
1899a5f0fb15SPaul Saab 				/*
1900a5f0fb15SPaul Saab 				 * Expand the editor prototype string
1901a5f0fb15SPaul Saab 				 * and pass it to the system to execute.
1902a5f0fb15SPaul Saab 				 * (Make sure the screen is displayed so the
1903a5f0fb15SPaul Saab 				 * expansion of "+%lm" works.)
1904a5f0fb15SPaul Saab 				 */
1905a5f0fb15SPaul Saab 				make_display();
1906a5f0fb15SPaul Saab 				cmd_exec();
1907*c77c4889SXin LI 				lsystem(pr_expand(editproto), NULL);
1908a5f0fb15SPaul Saab 				break;
1909b2ea2440SXin LI 			}
1910b2ea2440SXin LI #endif
1911a5f0fb15SPaul Saab 			error("Command not available", NULL_PARG);
1912a5f0fb15SPaul Saab 			break;
1913a5f0fb15SPaul Saab 
1914a5f0fb15SPaul Saab 		case A_NEXT_FILE:
1915a5f0fb15SPaul Saab 			/*
1916a5f0fb15SPaul Saab 			 * Examine next file.
1917a5f0fb15SPaul Saab 			 */
19181ede1615STim J. Robbins #if TAGS
19198fd4165cSPaul Saab 			if (ntags())
19208fd4165cSPaul Saab 			{
19218fd4165cSPaul Saab 				error("No next file", NULL_PARG);
19228fd4165cSPaul Saab 				break;
19238fd4165cSPaul Saab 			}
19241ede1615STim J. Robbins #endif
1925a5f0fb15SPaul Saab 			if (number <= 0)
1926a5f0fb15SPaul Saab 				number = 1;
19271ede1615STim J. Robbins 			if (edit_next((int) number))
1928a5f0fb15SPaul Saab 			{
19297374caaaSXin LI 				if (get_quit_at_eof() && eof_displayed() &&
1930a5f0fb15SPaul Saab 				    !(ch_getflags() & CH_HELPFILE))
1931a5f0fb15SPaul Saab 					quit(QUIT_OK);
1932a5f0fb15SPaul Saab 				parg.p_string = (number > 1) ? "(N-th) " : "";
1933a5f0fb15SPaul Saab 				error("No %snext file", &parg);
1934a5f0fb15SPaul Saab 			}
1935a5f0fb15SPaul Saab 			break;
1936a5f0fb15SPaul Saab 
1937a5f0fb15SPaul Saab 		case A_PREV_FILE:
1938a5f0fb15SPaul Saab 			/*
1939a5f0fb15SPaul Saab 			 * Examine previous file.
1940a5f0fb15SPaul Saab 			 */
19411ede1615STim J. Robbins #if TAGS
19428fd4165cSPaul Saab 			if (ntags())
19438fd4165cSPaul Saab 			{
19448fd4165cSPaul Saab 				error("No previous file", NULL_PARG);
19458fd4165cSPaul Saab 				break;
19468fd4165cSPaul Saab 			}
19471ede1615STim J. Robbins #endif
1948a5f0fb15SPaul Saab 			if (number <= 0)
1949a5f0fb15SPaul Saab 				number = 1;
19501ede1615STim J. Robbins 			if (edit_prev((int) number))
1951a5f0fb15SPaul Saab 			{
1952a5f0fb15SPaul Saab 				parg.p_string = (number > 1) ? "(N-th) " : "";
1953a5f0fb15SPaul Saab 				error("No %sprevious file", &parg);
1954a5f0fb15SPaul Saab 			}
1955a5f0fb15SPaul Saab 			break;
1956a5f0fb15SPaul Saab 
19578fd4165cSPaul Saab 		case A_NEXT_TAG:
1958b2ea2440SXin LI 			/*
1959b2ea2440SXin LI 			 * Jump to the next tag in the current tag list.
1960b2ea2440SXin LI 			 */
19611ede1615STim J. Robbins #if TAGS
19628fd4165cSPaul Saab 			if (number <= 0)
19638fd4165cSPaul Saab 				number = 1;
19641ede1615STim J. Robbins 			tagfile = nexttag((int) number);
19658fd4165cSPaul Saab 			if (tagfile == NULL)
19668fd4165cSPaul Saab 			{
19678fd4165cSPaul Saab 				error("No next tag", NULL_PARG);
19688fd4165cSPaul Saab 				break;
19698fd4165cSPaul Saab 			}
1970b2ea2440SXin LI 			cmd_exec();
19718fd4165cSPaul Saab 			if (edit(tagfile) == 0)
19728fd4165cSPaul Saab 			{
19738fd4165cSPaul Saab 				POSITION pos = tagsearch();
19748fd4165cSPaul Saab 				if (pos != NULL_POSITION)
19758fd4165cSPaul Saab 					jump_loc(pos, jump_sline);
19768fd4165cSPaul Saab 			}
19771ede1615STim J. Robbins #else
19781ede1615STim J. Robbins 			error("Command not available", NULL_PARG);
19791ede1615STim J. Robbins #endif
19808fd4165cSPaul Saab 			break;
19818fd4165cSPaul Saab 
19828fd4165cSPaul Saab 		case A_PREV_TAG:
1983b2ea2440SXin LI 			/*
1984b2ea2440SXin LI 			 * Jump to the previous tag in the current tag list.
1985b2ea2440SXin LI 			 */
19861ede1615STim J. Robbins #if TAGS
19878fd4165cSPaul Saab 			if (number <= 0)
19888fd4165cSPaul Saab 				number = 1;
19891ede1615STim J. Robbins 			tagfile = prevtag((int) number);
19908fd4165cSPaul Saab 			if (tagfile == NULL)
19918fd4165cSPaul Saab 			{
19928fd4165cSPaul Saab 				error("No previous tag", NULL_PARG);
19938fd4165cSPaul Saab 				break;
19948fd4165cSPaul Saab 			}
1995b2ea2440SXin LI 			cmd_exec();
19968fd4165cSPaul Saab 			if (edit(tagfile) == 0)
19978fd4165cSPaul Saab 			{
19988fd4165cSPaul Saab 				POSITION pos = tagsearch();
19998fd4165cSPaul Saab 				if (pos != NULL_POSITION)
20008fd4165cSPaul Saab 					jump_loc(pos, jump_sline);
20018fd4165cSPaul Saab 			}
20021ede1615STim J. Robbins #else
20031ede1615STim J. Robbins 			error("Command not available", NULL_PARG);
20041ede1615STim J. Robbins #endif
20058fd4165cSPaul Saab 			break;
20068fd4165cSPaul Saab 
2007a5f0fb15SPaul Saab 		case A_INDEX_FILE:
2008a5f0fb15SPaul Saab 			/*
2009a5f0fb15SPaul Saab 			 * Examine a particular file.
2010a5f0fb15SPaul Saab 			 */
2011a5f0fb15SPaul Saab 			if (number <= 0)
2012a5f0fb15SPaul Saab 				number = 1;
20131ede1615STim J. Robbins 			if (edit_index((int) number))
2014a5f0fb15SPaul Saab 				error("No such file", NULL_PARG);
2015a5f0fb15SPaul Saab 			break;
2016a5f0fb15SPaul Saab 
2017a5f0fb15SPaul Saab 		case A_REMOVE_FILE:
2018b2ea2440SXin LI 			/*
2019b2ea2440SXin LI 			 * Remove a file from the input file list.
2020b2ea2440SXin LI 			 */
2021a5f0fb15SPaul Saab 			if (ch_getflags() & CH_HELPFILE)
2022a5f0fb15SPaul Saab 				break;
2023a5f0fb15SPaul Saab 			old_ifile = curr_ifile;
2024a5f0fb15SPaul Saab 			new_ifile = getoff_ifile(curr_ifile);
2025a5f0fb15SPaul Saab 			if (new_ifile == NULL_IFILE)
2026a5f0fb15SPaul Saab 			{
2027a5f0fb15SPaul Saab 				bell();
2028a5f0fb15SPaul Saab 				break;
2029a5f0fb15SPaul Saab 			}
2030a5f0fb15SPaul Saab 			if (edit_ifile(new_ifile) != 0)
2031a5f0fb15SPaul Saab 			{
2032a5f0fb15SPaul Saab 				reedit_ifile(old_ifile);
2033a5f0fb15SPaul Saab 				break;
2034a5f0fb15SPaul Saab 			}
2035a5f0fb15SPaul Saab 			del_ifile(old_ifile);
2036a5f0fb15SPaul Saab 			break;
2037a5f0fb15SPaul Saab 
2038a5f0fb15SPaul Saab 		case A_OPT_TOGGLE:
2039b2ea2440SXin LI 			/*
2040b2ea2440SXin LI 			 * Change the setting of an  option.
2041b2ea2440SXin LI 			 */
2042a5f0fb15SPaul Saab 			optflag = OPT_TOGGLE;
2043a5f0fb15SPaul Saab 			optgetname = FALSE;
2044a5f0fb15SPaul Saab 			mca_opt_toggle();
2045a5f0fb15SPaul Saab 			c = getcc();
2046*c77c4889SXin LI 			msg = opt_toggle_disallowed(c);
2047*c77c4889SXin LI 			if (msg != NULL)
20486f26c71dSXin LI 			{
2049*c77c4889SXin LI 				error(msg, NULL_PARG);
20506f26c71dSXin LI 				break;
20516f26c71dSXin LI 			}
2052a5f0fb15SPaul Saab 			goto again;
2053a5f0fb15SPaul Saab 
2054a5f0fb15SPaul Saab 		case A_DISP_OPTION:
2055a5f0fb15SPaul Saab 			/*
2056b2ea2440SXin LI 			 * Report the setting of an option.
2057a5f0fb15SPaul Saab 			 */
2058a5f0fb15SPaul Saab 			optflag = OPT_NO_TOGGLE;
2059a5f0fb15SPaul Saab 			optgetname = FALSE;
2060a5f0fb15SPaul Saab 			mca_opt_toggle();
2061a5f0fb15SPaul Saab 			c = getcc();
2062a5f0fb15SPaul Saab 			goto again;
2063a5f0fb15SPaul Saab 
2064a5f0fb15SPaul Saab 		case A_FIRSTCMD:
2065a5f0fb15SPaul Saab 			/*
2066a5f0fb15SPaul Saab 			 * Set an initial command for new files.
2067a5f0fb15SPaul Saab 			 */
2068*c77c4889SXin LI 			start_mca(A_FIRSTCMD, "+", NULL, 0);
2069a5f0fb15SPaul Saab 			c = getcc();
2070a5f0fb15SPaul Saab 			goto again;
2071a5f0fb15SPaul Saab 
2072a5f0fb15SPaul Saab 		case A_SHELL:
2073d713e089SXin LI 		case A_PSHELL:
2074a5f0fb15SPaul Saab 			/*
2075a5f0fb15SPaul Saab 			 * Shell escape.
2076a5f0fb15SPaul Saab 			 */
2077a5f0fb15SPaul Saab #if SHELL_ESCAPE
2078*c77c4889SXin LI 			if (secure_allow(SF_SHELL))
2079a5f0fb15SPaul Saab 			{
2080d713e089SXin LI 				start_mca(action, (action == A_SHELL) ? "!" : "#", ml_shell, 0);
2081a5f0fb15SPaul Saab 				c = getcc();
2082a5f0fb15SPaul Saab 				goto again;
2083b2ea2440SXin LI 			}
2084b2ea2440SXin LI #endif
2085a5f0fb15SPaul Saab 			error("Command not available", NULL_PARG);
2086a5f0fb15SPaul Saab 			break;
2087a5f0fb15SPaul Saab 
2088a5f0fb15SPaul Saab 		case A_SETMARK:
2089b2ea2440SXin LI 		case A_SETMARKBOT:
2090a5f0fb15SPaul Saab 			/*
2091a5f0fb15SPaul Saab 			 * Set a mark.
2092a5f0fb15SPaul Saab 			 */
2093a5f0fb15SPaul Saab 			if (ch_getflags() & CH_HELPFILE)
2094a5f0fb15SPaul Saab 				break;
2095*c77c4889SXin LI 			start_mca(A_SETMARK, "set mark: ", NULL, 0);
2096a5f0fb15SPaul Saab 			c = getcc();
2097b2ea2440SXin LI 			if (is_erase_char(c) || is_newline_char(c))
2098a5f0fb15SPaul Saab 				break;
2099b2ea2440SXin LI 			setmark(c, action == A_SETMARKBOT ? BOTTOM : TOP);
2100b2ea2440SXin LI 			repaint();
2101b2ea2440SXin LI 			break;
2102b2ea2440SXin LI 
2103b2ea2440SXin LI 		case A_CLRMARK:
2104b2ea2440SXin LI 			/*
2105b2ea2440SXin LI 			 * Clear a mark.
2106b2ea2440SXin LI 			 */
2107*c77c4889SXin LI 			start_mca(A_CLRMARK, "clear mark: ", NULL, 0);
2108b2ea2440SXin LI 			c = getcc();
2109b2ea2440SXin LI 			if (is_erase_char(c) || is_newline_char(c))
2110b2ea2440SXin LI 				break;
2111b2ea2440SXin LI 			clrmark(c);
2112b2ea2440SXin LI 			repaint();
2113a5f0fb15SPaul Saab 			break;
2114a5f0fb15SPaul Saab 
2115a5f0fb15SPaul Saab 		case A_GOMARK:
2116a5f0fb15SPaul Saab 			/*
2117b2ea2440SXin LI 			 * Jump to a marked position.
2118a5f0fb15SPaul Saab 			 */
2119*c77c4889SXin LI 			start_mca(A_GOMARK, "goto mark: ", NULL, 0);
2120a5f0fb15SPaul Saab 			c = getcc();
2121b2ea2440SXin LI 			if (is_erase_char(c) || is_newline_char(c))
2122a5f0fb15SPaul Saab 				break;
21237374caaaSXin LI 			cmd_exec();
2124a5f0fb15SPaul Saab 			gomark(c);
2125a5f0fb15SPaul Saab 			break;
2126a5f0fb15SPaul Saab 
2127a5f0fb15SPaul Saab 		case A_PIPE:
2128b2ea2440SXin LI 			/*
2129b2ea2440SXin LI 			 * Write part of the input to a pipe to a shell command.
2130b2ea2440SXin LI 			 */
2131a5f0fb15SPaul Saab #if PIPEC
2132*c77c4889SXin LI 			if (secure_allow(SF_PIPE))
2133a5f0fb15SPaul Saab 			{
2134*c77c4889SXin LI 				start_mca(A_PIPE, "|mark: ", NULL, 0);
2135a5f0fb15SPaul Saab 				c = getcc();
2136b2ea2440SXin LI 				if (is_erase_char(c))
2137a5f0fb15SPaul Saab 					break;
2138b2ea2440SXin LI 				if (is_newline_char(c))
2139a5f0fb15SPaul Saab 					c = '.';
2140a5f0fb15SPaul Saab 				if (badmark(c))
2141a5f0fb15SPaul Saab 					break;
2142a5f0fb15SPaul Saab 				pipec = c;
2143dd3bd0edSDimitry Andric 				start_mca(A_PIPE, "!", ml_shell, 0);
2144a5f0fb15SPaul Saab 				c = getcc();
2145a5f0fb15SPaul Saab 				goto again;
2146b2ea2440SXin LI 			}
2147b2ea2440SXin LI #endif
2148a5f0fb15SPaul Saab 			error("Command not available", NULL_PARG);
2149a5f0fb15SPaul Saab 			break;
2150a5f0fb15SPaul Saab 
2151a5f0fb15SPaul Saab 		case A_B_BRACKET:
2152a5f0fb15SPaul Saab 		case A_F_BRACKET:
2153*c77c4889SXin LI 			start_mca(action, "Brackets: ", NULL, 0);
2154a5f0fb15SPaul Saab 			c = getcc();
2155a5f0fb15SPaul Saab 			goto again;
2156a5f0fb15SPaul Saab 
2157a5f0fb15SPaul Saab 		case A_LSHIFT:
2158b2ea2440SXin LI 			/*
2159b2ea2440SXin LI 			 * Shift view left.
2160b2ea2440SXin LI 			 */
21618fd4165cSPaul Saab 			if (number > 0)
2162*c77c4889SXin LI 				shift_count = (int) number;
21638fd4165cSPaul Saab 			else
2164*c77c4889SXin LI 				number = (shift_count > 0) ? shift_count : sc_width / 2;
2165a5f0fb15SPaul Saab 			if (number > hshift)
2166a5f0fb15SPaul Saab 				number = hshift;
2167*c77c4889SXin LI 			pos_rehead();
2168*c77c4889SXin LI 			hshift -= (int) number;
2169*c77c4889SXin LI 			screen_trashed();
2170a5f0fb15SPaul Saab 			break;
2171a5f0fb15SPaul Saab 
2172a5f0fb15SPaul Saab 		case A_RSHIFT:
2173b2ea2440SXin LI 			/*
2174b2ea2440SXin LI 			 * Shift view right.
2175b2ea2440SXin LI 			 */
21768fd4165cSPaul Saab 			if (number > 0)
2177*c77c4889SXin LI 				shift_count = (int) number;
21788fd4165cSPaul Saab 			else
2179*c77c4889SXin LI 				number = (shift_count > 0) ? shift_count : sc_width / 2;
2180*c77c4889SXin LI 			pos_rehead();
2181*c77c4889SXin LI 			hshift += (int) number;
2182*c77c4889SXin LI 			screen_trashed();
2183a5f0fb15SPaul Saab 			break;
2184a5f0fb15SPaul Saab 
2185f6b74a7dSXin LI 		case A_LLSHIFT:
2186b2ea2440SXin LI 			/*
2187b2ea2440SXin LI 			 * Shift view left to margin.
2188b2ea2440SXin LI 			 */
2189*c77c4889SXin LI 			pos_rehead();
2190f6b74a7dSXin LI 			hshift = 0;
2191*c77c4889SXin LI 			screen_trashed();
2192f6b74a7dSXin LI 			break;
2193f6b74a7dSXin LI 
2194f6b74a7dSXin LI 		case A_RRSHIFT:
2195b2ea2440SXin LI 			/*
2196b2ea2440SXin LI 			 * Shift view right to view rightmost char on screen.
2197b2ea2440SXin LI 			 */
2198*c77c4889SXin LI 			pos_rehead();
2199f6b74a7dSXin LI 			hshift = rrshift();
2200*c77c4889SXin LI 			screen_trashed();
2201f6b74a7dSXin LI 			break;
2202f6b74a7dSXin LI 
2203a5f0fb15SPaul Saab 		case A_PREFIX:
2204a5f0fb15SPaul Saab 			/*
2205a5f0fb15SPaul Saab 			 * The command is incomplete (more chars are needed).
2206a5f0fb15SPaul Saab 			 * Display the current char, so the user knows
2207a5f0fb15SPaul Saab 			 * what's going on, and get another character.
2208a5f0fb15SPaul Saab 			 */
2209a5f0fb15SPaul Saab 			if (mca != A_PREFIX)
2210a5f0fb15SPaul Saab 			{
2211a5f0fb15SPaul Saab 				cmd_reset();
2212*c77c4889SXin LI 				start_mca(A_PREFIX, " ", NULL, CF_QUIT_ON_ERASE);
2213a5f0fb15SPaul Saab 				(void) cmd_char(c);
2214a5f0fb15SPaul Saab 			}
2215a5f0fb15SPaul Saab 			c = getcc();
2216a5f0fb15SPaul Saab 			goto again;
2217a5f0fb15SPaul Saab 
2218a5f0fb15SPaul Saab 		case A_NOACTION:
2219a5f0fb15SPaul Saab 			break;
2220a5f0fb15SPaul Saab 
2221a5f0fb15SPaul Saab 		default:
2222a5f0fb15SPaul Saab 			bell();
2223a5f0fb15SPaul Saab 			break;
2224a5f0fb15SPaul Saab 		}
2225a5f0fb15SPaul Saab 	}
2226a5f0fb15SPaul Saab }
2227