diff miscellany/less-177/command.c @ 0:bce86c4163a3

Initial revision
author kono
date Mon, 18 Apr 2005 23:46:02 +0900
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/miscellany/less-177/command.c	Mon Apr 18 23:46:02 2005 +0900
@@ -0,0 +1,1192 @@
+/*
+ * User-level command processor.
+ */
+
+#include "less.h"
+#include "position.h"
+#include "option.h"
+#include "cmd.h"
+
+#define	NO_MCA		0
+#define	MCA_DONE	1
+#define	MCA_MORE	2
+
+extern int erase_char, kill_char;
+extern int ispipe;
+extern int sigs;
+extern int quit_at_eof;
+extern int hit_eof;
+extern int sc_width;
+extern int sc_height;
+extern int swindow;
+extern int jump_sline;
+extern int quitting;
+extern int scroll;
+extern int nohelp;
+extern int ignore_eoi;
+extern char *every_first_cmd;
+extern char version[];
+extern struct scrpos initial_scrpos;
+extern IFILE curr_ifile;
+#if EDITOR
+extern char *editor;
+extern char *editproto;
+#endif
+extern int screen_trashed;	/* The screen has been overwritten */
+
+static char ungot[100];
+static char *ungotp = NULL;
+#if SHELL_ESCAPE
+static char *shellcmd = NULL;	/* For holding last shell command for "!!" */
+#endif
+static int mca;			/* The multicharacter command (action) */
+static int search_type;		/* The previous type of search */
+static int number;		/* The number typed by the user */
+static char optchar;
+static int optflag;
+#if PIPEC
+static char pipec;
+#endif
+
+static void multi_search();
+
+/*
+ * Move the cursor to lower left before executing a command.
+ * This looks nicer if the command takes a long time before
+ * updating the screen.
+ */
+	static void
+cmd_exec()
+{
+	lower_left();
+	flush();
+}
+
+/*
+ * Set up the display to start a new multi-character command.
+ */
+	static void
+start_mca(action, prompt)
+	int action;
+	char *prompt;
+{
+	mca = action;
+	lower_left();
+	clear_eol();
+	cmd_putstr(prompt);
+}
+
+/*
+ * Set up the display to start a new search command.
+ */
+	static void
+mca_search()
+{
+	switch (SRCH_DIR(search_type))
+	{
+	case SRCH_FORW:
+		mca = A_F_SEARCH;
+		break;
+	case SRCH_BACK:
+		mca = A_B_SEARCH;
+		break;
+	}
+
+	lower_left();
+	clear_eol();
+
+	if (search_type & SRCH_FIRST_FILE)
+		cmd_putstr("@");
+
+	if (search_type & SRCH_PAST_EOF)
+		cmd_putstr("*");
+
+	if (search_type & SRCH_NOMATCH)
+		cmd_putstr("!");
+
+	switch (SRCH_DIR(search_type))
+	{
+	case SRCH_FORW:
+		cmd_putstr("/");
+		break;
+	case SRCH_BACK:
+		cmd_putstr("?");
+		break;
+	}
+}
+
+/*
+ * Execute a multicharacter command.
+ */
+	static void
+exec_mca()
+{
+	register char *cbuf;
+	register char *s;
+
+	cmd_exec();
+	cbuf = get_cmdbuf();
+
+	switch (mca)
+	{
+	case A_F_SEARCH:
+	case A_B_SEARCH:
+		multi_search(cbuf, number);
+		break;
+	case A_FIRSTCMD:
+		/*
+		 * Skip leading spaces or + signs in the string.
+		 */
+		while (*cbuf == '+' || *cbuf == ' ')
+			cbuf++;
+		if (every_first_cmd != NULL)
+			free(every_first_cmd);
+		if (*cbuf == '\0')
+			every_first_cmd = NULL;
+		else
+			every_first_cmd = save(cbuf);
+		break;
+	case A_OPT_TOGGLE:
+		toggle_option(optchar, cbuf, optflag);
+		optchar = '\0';
+		break;
+	case A_F_BRACKET:
+		match_brac(cbuf[0], cbuf[1], 1, number);
+		break;
+	case A_B_BRACKET:
+		match_brac(cbuf[1], cbuf[0], 0, number);
+		break;
+	case A_EXAMINE:
+		/*
+		 * Ignore leading spaces and glob the filename.
+		 */
+		cbuf = skipsp(cbuf);
+		s = glob(cbuf);
+		if (s != NULL)
+		{
+			edit_list(s);
+			free(s);
+		} else
+			edit_list(cbuf);
+		break;
+#if SHELL_ESCAPE
+	case A_SHELL:
+		/*
+		 * !! just uses whatever is in shellcmd.
+		 * Otherwise, copy cmdbuf to shellcmd,
+		 * expanding any special characters ("%" or "#").
+		 */
+		if (*cbuf != '!')
+		{
+			if (shellcmd != NULL)
+				free(shellcmd);
+			shellcmd = fexpand(cbuf);
+			if (shellcmd == NULL)
+				break;
+		}
+
+		if (shellcmd == NULL)
+			lsystem("");
+		else
+			lsystem(shellcmd);
+		error("!done", NULL_PARG);
+		break;
+#endif
+#if PIPEC
+	case A_PIPE:
+		(void) pipe_mark(pipec, cbuf);
+		error("|done", NULL_PARG);
+		break;
+#endif
+	}
+}
+
+/*
+ * Add a character to a multi-character command.
+ */
+	static int
+mca_char(c)
+	int c;
+{
+	char *p;
+	int flag;
+	char buf[3];
+
+	switch (mca)
+	{
+	case 0:
+		/*
+		 * Not in a multicharacter command.
+		 */
+		return (NO_MCA);
+
+	case A_PREFIX:
+		/*
+		 * In the prefix of a command.
+		 * This not considered a multichar command
+		 * (even tho it uses cmdbuf, etc.).
+		 * It is handled in the commands() switch.
+		 */
+		return (NO_MCA);
+
+	case A_DIGIT:
+		/*
+		 * Entering digits of a number.
+		 * Terminated by a non-digit.
+		 */
+		if ((c < '0' || c > '9') &&
+			c != erase_char && c != kill_char)
+		{
+			/*
+			 * Not part of the number.
+			 * Treat as a normal command character.
+			 */
+			number = cmd_int();
+			mca = 0;
+			return (NO_MCA);
+		}
+		break;
+
+	case A_OPT_TOGGLE:
+		/*
+		 * Special case for the TOGGLE_OPTION command.
+		 * If the option letter which was entered is a
+		 * single-char option, execute the command immediately,
+		 * so user doesn't have to hit RETURN.
+		 * If the first char is + or -, this indicates
+		 * OPT_UNSET or OPT_SET respectively, instead of OPT_TOGGLE.
+		 */
+		if (c == erase_char || c == kill_char)
+			break;
+		if (optchar != '\0' && optchar != '+' && optchar != '-')
+			/*
+			 * We already have the option letter.
+			 */
+			break;
+		switch (c)
+		{
+		case '+':
+			optflag = OPT_UNSET;
+			break;
+		case '-':
+			optflag = OPT_SET;
+			break;
+		default:
+			optchar = c;
+			if (optflag != OPT_TOGGLE || single_char_option(c))
+			{
+				toggle_option(c, "", optflag);
+				return (MCA_DONE);
+			}
+			break;
+		}
+		if (optchar == '+' || optchar == '-')
+		{
+			optchar = c;
+			break;
+		}
+		/*
+		 * Display a prompt appropriate for the option letter.
+		 */
+		if ((p = opt_prompt(c)) == NULL)
+		{
+			buf[0] = '-';
+			buf[1] = c;
+			buf[2] = '\0';
+			p = buf;
+		}
+		start_mca(A_OPT_TOGGLE, p);
+		return (MCA_MORE);
+
+	case A_F_SEARCH:
+	case A_B_SEARCH:
+		/*
+		 * Special case for search commands.
+		 * Certain characters as the first char of 
+		 * the pattern have special meaning:
+		 *	!  Toggle the NOMATCH flag
+		 *	*  Toggle the PAST_EOF flag
+		 *	@  Toggle the FIRST_FILE flag
+		 */
+		if (len_cmdbuf() > 0)
+			/*
+			 * Only works for the first char of the pattern.
+			 */
+			break;
+
+		flag = 0;
+		switch (c)
+		{
+		case '!':
+			flag = SRCH_NOMATCH;
+			break;
+		case '@':
+			flag = SRCH_FIRST_FILE;
+			break;
+		case '*':
+			flag = SRCH_PAST_EOF;
+			break;
+		}
+		if (flag != 0)
+		{
+			search_type ^= flag;
+			mca_search();
+			return (MCA_MORE);
+		}
+		break;
+	}
+
+	/*
+	 * Any other multicharacter command
+	 * is terminated by a newline.
+	 */
+	if (c == '\n' || c == '\r')
+	{
+		/*
+		 * Execute the command.
+		 */
+		exec_mca();
+		return (MCA_DONE);
+	}
+	/*
+	 * Append the char to the command buffer.
+	 */
+	if (cmd_char(c))
+		/*
+		 * Abort the multi-char command.
+		 */
+		return (MCA_DONE);
+
+	if ((mca == A_F_BRACKET || mca == A_B_BRACKET) && len_cmdbuf() >= 2)
+	{
+		/*
+		 * Special case for the bracket-matching commands.
+		 * Execute the command after getting exactly two
+		 * characters from the user.
+		 */
+		exec_mca();
+		return (MCA_DONE);
+	}
+
+	/*
+	 * Need another character.
+	 */
+	return (MCA_MORE);
+}
+
+/*
+ * Display the appropriate prompt.
+ */
+	static void
+prompt()
+{
+	register char *p;
+
+	if (ungotp != NULL && ungotp > ungot)
+	{
+		/*
+		 * No prompt necessary if commands are from 
+		 * ungotten chars rather than from the user.
+		 */
+		return;
+	}
+
+	/*
+	 * If nothing is displayed yet, display starting from initial_scrpos.
+	 */
+	if (empty_screen())
+	{
+		if (initial_scrpos.pos == NULL_POSITION)
+			/*
+			 * {{ Maybe this should be:
+			 *    jump_loc(ch_zero(), jump_sline);
+			 *    but this behavior seems rather unexpected 
+			 *    on the first screen. }}
+			 */
+			jump_loc(ch_zero(), 1);
+		else
+			jump_loc(initial_scrpos.pos, initial_scrpos.ln);
+	} else if (screen_trashed)
+		repaint();
+
+	/*
+	 * If the -E flag is set and we've hit EOF on the last file, quit.
+	 */
+	if (quit_at_eof == 2 && hit_eof && 
+	    next_ifile(curr_ifile) == NULL_IFILE)
+		quit(0);
+
+	/*
+	 * Select the proper prompt and display it.
+	 */
+	lower_left();
+	clear_eol();
+	p = pr_string();
+	if (p == NULL)
+		putchr(':');
+	else
+	{
+		so_enter();
+		putstr(p);
+		so_exit();
+	}
+#if __MSDOS__
+	scroll_bar();
+#endif
+}
+
+/*
+ * Get command character.
+ * The character normally comes from the keyboard,
+ * but may come from ungotten characters
+ * (characters previously given to ungetcc or ungetsc).
+ */
+	static int
+getcc()
+{
+	if (ungotp == NULL)
+		/*
+		 * Normal case: no ungotten chars, so get one from the user.
+		 */
+		return (getchr());
+
+	if (ungotp > ungot)
+		/*
+		 * Return the next ungotten char.
+		 */
+		return (*--ungotp);
+
+	/*
+	 * We have just run out of ungotten chars.
+	 */
+	ungotp = NULL;
+	if (len_cmdbuf() == 0 || !empty_screen())
+		return (getchr());
+	/*
+	 * Command is incomplete, so try to complete it.
+	 */
+	switch (mca)
+	{
+	case A_DIGIT:
+		/*
+		 * We have a number but no command.  Treat as #g.
+		 */
+		return ('g');
+
+	case A_F_SEARCH:
+	case A_B_SEARCH:
+		/*
+		 * We have "/string" but no newline.  Add the \n.
+		 */
+		return ('\n'); 
+
+	default:
+		/*
+		 * Some other incomplete command.  Let user complete it.
+		 */
+		return (getchr());
+	}
+}
+
+/*
+ * "Unget" a command character.
+ * The next getcc() will return this character.
+ */
+	public void
+ungetcc(c)
+	int c;
+{
+	if (ungotp == NULL)
+		ungotp = ungot;
+	if (ungotp >= ungot + sizeof(ungot))
+	{
+		error("ungetcc overflow", NULL_PARG);
+		quit(1);
+	}
+	*ungotp++ = c;
+}
+
+/*
+ * Unget a whole string of command characters.
+ * The next sequence of getcc()'s will return this string.
+ */
+	public void
+ungetsc(s)
+	char *s;
+{
+	register char *p;
+
+	for (p = s + strlen(s) - 1;  p >= s;  p--)
+		ungetcc(*p);
+}
+
+/*
+ * Search for a pattern, possibly in multiple files.
+ * If SRCH_FIRST_FILE is set, begin searching at the first file.
+ * If SRCH_PAST_EOF is set, continue the search thru multiple files.
+ */
+	static void
+multi_search(pattern, n)
+	char *pattern;
+	int n;
+{
+	register int nomore;
+	char *curr_filename;
+	int changed_file;
+
+	changed_file = 0;
+	curr_filename = get_filename(curr_ifile);
+
+	if (search_type & SRCH_FIRST_FILE)
+	{
+		/*
+		 * Start at the first (or last) file 
+		 * in the command line list.
+		 */
+		if (SRCH_DIR(search_type) == SRCH_FORW)
+			nomore = edit_first();
+		else
+			nomore = edit_last();
+		if (nomore)
+			return;
+		changed_file = 1;
+		search_type &= ~SRCH_FIRST_FILE;
+	}
+
+	for (;;)
+	{
+		if ((n = search(search_type, pattern, n)) == 0)
+			/*
+			 * Found it.
+			 */
+			return;
+
+		if (n < 0)
+			/*
+			 * Some kind of error in the search.
+			 * Error message has been printed by search().
+			 */
+			break;
+
+		if ((search_type & SRCH_PAST_EOF) == 0)
+			/*
+			 * We didn't find a match, but we're
+			 * supposed to search only one file.
+			 */
+			break;
+		/*
+		 * Move on to the next file.
+		 */
+		if (SRCH_DIR(search_type) == SRCH_BACK)
+			nomore = edit_prev(1);
+		else
+			nomore = edit_next(1);
+		if (nomore)
+			break;
+		changed_file = 1;
+	}
+
+	/*
+	 * Didn't find it.
+	 * Print an error message if we haven't already.
+	 */
+	if (n > 0)
+		error("Pattern not found", NULL_PARG);
+
+	if (changed_file)
+		/*
+		 * Restore the file we were originally viewing.
+		 */
+		(void) edit(curr_filename, 0);
+}
+
+/*
+ * Main command processor.
+ * Accept and execute commands until a quit command.
+ */
+	public void
+commands()
+{
+	register int c;
+	register int action;
+	register char *cbuf;
+	int save_search_type;
+	char *s;
+	char tbuf[2];
+	PARG parg;
+
+	search_type = SRCH_FORW;
+	scroll = (sc_height + 1) / 2;
+
+	for (;;)
+	{
+		mca = 0;
+		number = 0;
+		optchar = '\0';
+
+		/*
+		 * See if any signals need processing.
+		 */
+		if (sigs)
+		{
+			psignals();
+			if (quitting)
+				quit(-1);
+		}
+			
+		/*
+		 * Display prompt and accept a character.
+		 */
+		cmd_reset();
+		prompt();
+		if (sigs)
+			continue;
+		c = getcc();
+
+	again:
+		if (sigs)
+			continue;
+
+		/*
+		 * If we are in a multicharacter command, call mca_char.
+		 * Otherwise we call cmd_decode to determine the
+		 * action to be performed.
+		 */
+		if (mca)
+			switch (mca_char(c))
+			{
+			case MCA_MORE:
+				/*
+				 * Need another character.
+				 */
+				c = getcc();
+				goto again;
+			case MCA_DONE:
+				/*
+				 * Command has been handled by mca_char.
+				 * Start clean with a prompt.
+				 */
+				continue;
+			case NO_MCA:
+				/*
+				 * Not a multi-char command
+				 * (at least, not anymore).
+				 */
+				break;
+			}
+
+		/*
+		 * Decode the command character and decide what to do.
+		 */
+		if (mca)
+		{
+			/*
+			 * We're in a multichar command.
+			 * Add the character to the command buffer
+			 * and display it on the screen.
+			 * If the user backspaces past the start 
+			 * of the line, abort the command.
+			 */
+			if (cmd_char(c) || len_cmdbuf() == 0)
+				continue;
+			cbuf = get_cmdbuf();
+		} else
+		{
+			/*
+			 * Don't use cmd_char if we're starting fresh
+			 * at the beginning of a command, because we
+			 * don't want to echo the command until we know
+			 * it is a multichar command.  We also don't
+			 * want erase_char/kill_char to be treated
+			 * as line editing characters.
+			 */
+			tbuf[0] = c;
+			tbuf[1] = '\0';
+			cbuf = tbuf;
+		}
+		s = NULL;
+		action = cmd_decode(cbuf, &s);
+		/*
+		 * If an "extra" string was returned,
+		 * process it as a string of command characters.
+		 */
+		if (s != NULL)
+			ungetsc(s);
+		/*
+		 * Clear the cmdbuf string.
+		 * (But not if we're in the prefix of a command,
+		 * because the partial command string is kept there.)
+		 */
+		if (action != A_PREFIX)
+			cmd_reset();
+
+		switch (action)
+		{
+		case A_DIGIT:
+			/*
+			 * First digit of a number.
+			 */
+			start_mca(A_DIGIT, ":");
+			goto again;
+
+		case A_F_WINDOW:
+			/*
+			 * Forward one window (and set the window size).
+			 */
+			if (number > 0)
+				swindow = number;
+			/* FALLTHRU */
+		case A_F_SCREEN:
+			/*
+			 * Forward one screen.
+			 */
+			if (number <= 0)
+				number = swindow;
+			cmd_exec();
+			forward(number, 0, 1);
+			break;
+
+		case A_B_WINDOW:
+			/*
+			 * Backward one window (and set the window size).
+			 */
+			if (number > 0)
+				swindow = number;
+			/* FALLTHRU */
+		case A_B_SCREEN:
+			/*
+			 * Backward one screen.
+			 */
+			if (number <= 0)
+				number = swindow;
+			cmd_exec();
+			backward(number, 0, 1);
+			break;
+
+		case A_F_LINE:
+			/*
+			 * Forward N (default 1) line.
+			 */
+			if (number <= 0)
+				number = 1;
+			cmd_exec();
+			forward(number, 0, 0);
+			break;
+
+		case A_B_LINE:
+			/*
+			 * Backward N (default 1) line.
+			 */
+			if (number <= 0)
+				number = 1;
+			cmd_exec();
+			backward(number, 0, 0);
+			break;
+
+		case A_FF_LINE:
+			/*
+			 * Force forward N (default 1) line.
+			 */
+			if (number <= 0)
+				number = 1;
+			cmd_exec();
+			forward(number, 1, 0);
+			break;
+
+		case A_BF_LINE:
+			/*
+			 * Force backward N (default 1) line.
+			 */
+			if (number <= 0)
+				number = 1;
+			cmd_exec();
+			backward(number, 1, 0);
+			break;
+		
+		case A_F_FOREVER:
+			/*
+			 * Forward forever, ignoring EOF.
+			 */
+			cmd_exec();
+			jump_forw();
+			ignore_eoi = 1;
+			hit_eof = 0;
+			while (sigs == 0)
+				forward(1, 0, 0);
+			ignore_eoi = 0;
+			break;
+
+		case A_F_SCROLL:
+			/*
+			 * Forward N lines 
+			 * (default same as last 'd' or 'u' command).
+			 */
+			if (number > 0)
+				scroll = number;
+			cmd_exec();
+			forward(scroll, 0, 0);
+			break;
+
+		case A_B_SCROLL:
+			/*
+			 * Forward N lines 
+			 * (default same as last 'd' or 'u' command).
+			 */
+			if (number > 0)
+				scroll = number;
+			cmd_exec();
+			backward(scroll, 0, 0);
+			break;
+
+		case A_FREPAINT:
+			/*
+			 * Flush buffers, then repaint screen.
+			 * Don't flush the buffers on a pipe!
+			 */
+			ch_flush();
+			if (!ispipe)
+				clr_linenum();
+			/* FALLTHRU */
+		case A_REPAINT:
+			/*
+			 * Repaint screen.
+			 */
+			cmd_exec();
+			repaint();
+			break;
+
+		case A_GOLINE:
+			/*
+			 * Go to line N, default beginning of file.
+			 */
+			if (number <= 0)
+				number = 1;
+			cmd_exec();
+			jump_back(number);
+			break;
+
+		case A_PERCENT:
+			/*
+			 * Go to a specified percentage into the file.
+			 */
+			if (number < 0)
+				number = 0;
+			if (number > 100)
+				number = 100;
+			cmd_exec();
+			jump_percent(number);
+			break;
+
+		case A_GOEND:
+			/*
+			 * Go to line N, default end of file.
+			 */
+			cmd_exec();
+			if (number <= 0)
+				jump_forw();
+			else
+				jump_back(number);
+			break;
+
+		case A_GOPOS:
+			/*
+			 * Go to a specified byte position in the file.
+			 */
+			cmd_exec();
+			if (number < 0)
+				number = 0;
+			jump_line_loc((POSITION)number, jump_sline);
+			break;
+
+		case A_STAT:
+			/*
+			 * Print file name, etc.
+			 */
+			cmd_exec();
+			parg.p_string = eq_message();
+			error("%s", &parg);
+			break;
+			
+		case A_VERSION:
+			/*
+			 * Print version number, without the "@(#)".
+			 */
+			cmd_exec();
+			parg.p_string = version+4;
+			error("%s", &parg);
+			break;
+
+		case A_QUIT:
+			/*
+			 * Exit.
+			 */
+			quit(0);
+
+/*
+ * Define abbreviation for a commonly used sequence below.
+ */
+#define	DO_SEARCH()	if (number <= 0) number = 1;	\
+			mca_search();			\
+			cmd_exec();			\
+			multi_search((char *)NULL, number);
+
+
+		case A_F_SEARCH:
+			/*
+			 * Search forward for a pattern.
+			 * Get the first char of the pattern.
+			 */
+			search_type = SRCH_FORW;
+			if (number <= 0)
+				number = 1;
+			mca_search();
+			c = getcc();
+			goto again;
+
+		case A_B_SEARCH:
+			/*
+			 * Search backward for a pattern.
+			 * Get the first char of the pattern.
+			 */
+			search_type = SRCH_BACK;
+			if (number <= 0)
+				number = 1;
+			mca_search();
+			c = getcc();
+			goto again;
+
+		case A_AGAIN_SEARCH:
+			/*
+			 * Repeat previous search.
+			 */
+			DO_SEARCH();
+			break;
+		
+		case A_T_AGAIN_SEARCH:
+			/*
+			 * Repeat previous search, multiple files.
+			 */
+			search_type |= SRCH_PAST_EOF;
+			DO_SEARCH();
+			break;
+
+		case A_REVERSE_SEARCH:
+			/*
+			 * Repeat previous search, in reverse direction.
+			 */
+			save_search_type = search_type;
+			search_type = SRCH_REVERSE(search_type);
+			DO_SEARCH();
+			search_type = save_search_type;
+			break;
+
+		case A_T_REVERSE_SEARCH:
+			/* 
+			 * Repeat previous search, 
+			 * multiple files in reverse direction.
+			 */
+			save_search_type = search_type;
+			search_type = SRCH_REVERSE(search_type);
+			search_type |= SRCH_PAST_EOF;
+			DO_SEARCH();
+			search_type = save_search_type;
+			break;
+
+		case A_HELP:
+			/*
+			 * Help.
+			 */
+			if (nohelp)
+			{
+				bell();
+				break;
+			}
+			lower_left();
+			clear_eol();
+			putstr("help");
+			cmd_exec();
+			help();
+			break;
+
+		case A_EXAMINE:
+			/*
+			 * Edit a new file.  Get the filename.
+			 */
+			start_mca(A_EXAMINE, "Examine: ");
+			c = getcc();
+			goto again;
+			
+		case A_VISUAL:
+			/*
+			 * Invoke an editor on the input file.
+			 */
+#if EDITOR
+			if (strcmp(get_filename(curr_ifile), "-") == 0)
+			{
+				error("Cannot edit standard input", NULL_PARG);
+				break;
+			}
+			/*
+			 * Expand the editor prototype string
+			 * and pass it to the system to execute.
+			 */
+			cmd_exec();
+			lsystem(pr_expand(editproto, 0));
+			/*
+			 * Re-edit the file, since data may have changed.
+			 * Some editors even recreate the file, so flushing
+			 * buffers is not sufficient.
+			 */
+			(void) edit(get_filename(curr_ifile), 0);
+			break;
+#else
+			error("Command not available", NULL_PARG);
+			break;
+#endif
+
+		case A_NEXT_FILE:
+			/*
+			 * Examine next file.
+			 */
+			if (number <= 0)
+				number = 1;
+			if (edit_next(number))
+			{
+				if (quit_at_eof && hit_eof)
+					quit(0);
+				parg.p_string = (number > 1) ? "(N-th) " : "";
+				error("No %snext file", &parg);
+			}
+			break;
+
+		case A_PREV_FILE:
+			/*
+			 * Examine previous file.
+			 */
+			if (number <= 0)
+				number = 1;
+			if (edit_prev(number))
+			{
+				parg.p_string = (number > 1) ? "(N-th) " : "";
+				error("No %sprevious file", &parg);
+			}
+			break;
+
+		case A_INDEX_FILE:
+			/*
+			 * Examine a particular file.
+			 */
+			if (number <= 0)
+				number = 1;
+			if (edit_index(number))
+				error("No such file", NULL_PARG);
+			break;
+
+		case A_OPT_TOGGLE:
+			start_mca(A_OPT_TOGGLE, "-");
+			optflag = OPT_TOGGLE;
+			c = getcc();
+			goto again;
+
+		case A_DISP_OPTION:
+			/*
+			 * Report a flag setting.
+			 */
+			start_mca(A_DISP_OPTION, "_");
+			c = getcc();
+			if (c == erase_char || c == kill_char)
+				break;
+			toggle_option(c, "", OPT_NO_TOGGLE);
+			break;
+
+		case A_FIRSTCMD:
+			/*
+			 * Set an initial command for new files.
+			 */
+			start_mca(A_FIRSTCMD, "+");
+			c = getcc();
+			goto again;
+
+		case A_SHELL:
+			/*
+			 * Shell escape.
+			 */
+#if SHELL_ESCAPE
+			start_mca(A_SHELL, "!");
+			c = getcc();
+			goto again;
+#else
+			error("Command not available", NULL_PARG);
+			break;
+#endif
+
+		case A_SETMARK:
+			/*
+			 * Set a mark.
+			 */
+			start_mca(A_SETMARK, "mark: ");
+			c = getcc();
+			if (c == erase_char || c == kill_char ||
+			    c == '\n' || c == '\r')
+				break;
+			setmark(c);
+			break;
+
+		case A_GOMARK:
+			/*
+			 * Go to a mark.
+			 */
+			start_mca(A_GOMARK, "goto mark: ");
+			c = getcc();
+			if (c == erase_char || c == kill_char || 
+			    c == '\n' || c == '\r')
+				break;
+			gomark(c);
+			break;
+
+#if PIPEC
+		case A_PIPE:
+			start_mca(A_PIPE, "|mark: ");
+			c = getcc();
+			if (c == erase_char || c == kill_char)
+				break;
+			if (c == '\n' || c == '\r')
+				c = '.';
+			if (badmark(c))
+				break;
+			pipec = c;
+			start_mca(A_PIPE, "!");
+			c = getcc();
+			goto again;
+#endif
+
+		case A_B_BRACKET:
+		case A_F_BRACKET:
+			start_mca(action, "Brackets: ");
+			c = getcc();
+			goto again;
+
+		case A_PREFIX:
+			/*
+			 * The command is incomplete (more chars are needed).
+			 * Display the current char, so the user knows
+			 * what's going on, and get another character.
+			 */
+			if (mca != A_PREFIX)
+			{
+				start_mca(A_PREFIX, " ");
+				cmd_reset();
+				(void) cmd_char(c);
+			}
+			c = getcc();
+			goto again;
+
+		case A_NOACTION:
+			break;
+
+		default:
+			bell();
+			break;
+		}
+	}
+}