diff options
author | etheisen <etheisen@cvs.openbsd.org> | 1996-09-21 05:39:47 +0000 |
---|---|---|
committer | etheisen <etheisen@cvs.openbsd.org> | 1996-09-21 05:39:47 +0000 |
commit | 47d3895c0565680e9e7eba725be0896bfd06ce11 (patch) | |
tree | 921c411da39dc3da0c9f04e1732558983f372819 /usr.bin/less/command.c | |
parent | a2e06afb07d9a651364258a3d25e37f99d1dae46 (diff) |
Import of unmolested less-290.
Diffstat (limited to 'usr.bin/less/command.c')
-rw-r--r-- | usr.bin/less/command.c | 1253 |
1 files changed, 1253 insertions, 0 deletions
diff --git a/usr.bin/less/command.c b/usr.bin/less/command.c new file mode 100644 index 00000000000..d1ff9946237 --- /dev/null +++ b/usr.bin/less/command.c @@ -0,0 +1,1253 @@ +/* + * Copyright (c) 1984,1985,1989,1994,1995 Mark Nudelman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice in the documentation and/or other materials provided with + * the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/* + * User-level command processor. + */ + +#include "less.h" +#include "position.h" +#include "option.h" +#include "cmd.h" + +extern int erase_char, kill_char; +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 wscroll; +extern int nohelp; +extern int top_scroll; +extern int ignore_eoi; +extern char *every_first_cmd; +extern char *curr_altfilename; +extern char version[]; +extern struct scrpos initial_scrpos; +extern IFILE curr_ifile; +#if CMD_HISTORY +extern void *ml_search; +extern void *ml_examine; +#if SHELL_ESCAPE || PIPEC +extern void *ml_shell; +#endif +#else +/* No CMD_HISTORY */ +#define ml_search NULL +#define ml_examine NULL +#define ml_shell NULL +#endif +#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, mlist) + int action; + char *prompt; + void *mlist; +{ + mca = action; + clear_bot(); + cmd_putstr(prompt); +#if CMD_HISTORY + set_mlist(mlist); +#endif +} + + public int +in_mca() +{ + return (mca != 0 && mca != A_PREFIX); +} + +/* + * Set up the display to start a new search command. + */ + static void +mca_search() +{ + if (search_type & SRCH_FORW) + mca = A_F_SEARCH; + else + mca = A_B_SEARCH; + + clear_bot(); + + if (search_type & SRCH_FIRST_FILE) + cmd_putstr("@"); + + if (search_type & SRCH_PAST_EOF) + cmd_putstr("*"); + + if (search_type & SRCH_NOMATCH) + cmd_putstr("!"); + + if (search_type & SRCH_FORW) + cmd_putstr("/"); + else + cmd_putstr("?"); +#if CMD_HISTORY + set_mlist(ml_search); +#endif +} + +/* + * Execute a multicharacter command. + */ + static void +exec_mca() +{ + register char *cbuf; + + 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; +#if EXAMINE + case A_EXAMINE: + edit_list(cbuf); + break; +#endif +#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) + 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') && + editchar(c, EC_PEEK|EC_NOHISTORY|EC_NOCOMPLETE) == A_INVALID) + { + /* + * Not part of the number. + * Treat as a normal command character. + */ + number = cmd_int(); + mca = 0; + cmd_accept(); + 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, (void*)NULL); + 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) == CC_QUIT) + /* + * 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) + { + int save_top_scroll; + save_top_scroll = top_scroll; + top_scroll = 1; + repaint(); + top_scroll = save_top_scroll; + } + + /* + * If the -E flag is set and we've hit EOF on the last file, quit. + */ + if (quit_at_eof == OPT_ONPLUS && hit_eof && + next_ifile(curr_ifile) == NULL_IFILE) + quit(QUIT_OK); + + /* + * Select the proper prompt and display it. + */ + clear_bot(); + p = pr_string(); + if (p == NULL) + putchr(':'); + else + { + so_enter(); + putstr(p); + so_exit(); + } +} + + public void +dispversion() +{ + PARG parg; + + parg.p_string = version; + error("less version %s", &parg); +} + +/* + * Get command character. + * The character normally comes from the keyboard, + * but may come from ungotten characters + * (characters previously given to ungetcc or ungetsc). + */ + public 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(QUIT_ERROR); + } + *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; + IFILE save_ifile; + int changed_file; + + changed_file = 0; + save_ifile = curr_ifile; + + if (search_type & SRCH_FIRST_FILE) + { + /* + * Start at the first (or last) file + * in the command line list. + */ + if (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 (search_type & SRCH_FORW) + nomore = edit_next(1); + else + nomore = edit_prev(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. + */ + if (edit_ifile(save_ifile)) + quit(QUIT_ERROR); + } +} + +/* + * 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; + wscroll = (sc_height + 1) / 2; + + for (;;) + { + mca = 0; + cmd_accept(); + number = 0; + optchar = '\0'; + + /* + * See if any signals need processing. + */ + if (sigs) + { + psignals(); + if (quitting) + quit(QUIT_SAVED_STATUS); + } + + /* + * 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 fcmd_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) == CC_QUIT || 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 = fcmd_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, ":", (void*)NULL); + 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 = get_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 = get_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 (!ABORT_SIGS()) + 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) + wscroll = number; + cmd_exec(); + forward(wscroll, 0, 0); + break; + + case A_B_SCROLL: + /* + * Forward N lines + * (default same as last 'd' or 'u' command). + */ + if (number > 0) + wscroll = number; + cmd_exec(); + backward(wscroll, 0, 0); + break; + + case A_FREPAINT: + /* + * Flush buffers, then repaint screen. + * Don't flush the buffers on a pipe! + */ + if (ch_getflags() & CH_CANSEEK) + { + ch_flush(); + 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(); + dispversion(); + break; + + case A_QUIT: + /* + * Exit. + */ + quit(QUIT_OK); + +/* + * 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_UNDO_SEARCH: + undo_search(); + break; + + case A_HELP: + /* + * Help. + */ + if (nohelp) + { + bell(); + break; + } + clear_bot(); + putstr(" help"); + cmd_exec(); + help(0); + break; + + case A_EXAMINE: +#if EXAMINE + /* + * Edit a new file. Get the filename. + */ + start_mca(A_EXAMINE, "Examine: ", ml_examine); + c = getcc(); + goto again; +#else + error("Command not available", NULL_PARG); + break; +#endif + + 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; + } + if (curr_altfilename != NULL) + { + error("Cannot edit file processed with LESSOPEN", + 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. + */ + if (edit_ifile(curr_ifile)) + quit(QUIT_ERROR); + 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(QUIT_OK); + 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, "-", (void*)NULL); + optflag = OPT_TOGGLE; + c = getcc(); + goto again; + + case A_DISP_OPTION: + /* + * Report a flag setting. + */ + start_mca(A_DISP_OPTION, "_", (void*)NULL); + 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, "+", (void*)NULL); + c = getcc(); + goto again; + + case A_SHELL: + /* + * Shell escape. + */ +#if SHELL_ESCAPE + start_mca(A_SHELL, "!", ml_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: ", (void*)NULL); + 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: ", (void*)NULL); + c = getcc(); + if (c == erase_char || c == kill_char || + c == '\n' || c == '\r') + break; + gomark(c); + break; + + case A_PIPE: +#if PIPEC + start_mca(A_PIPE, "|mark: ", (void*)NULL); + 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, "!", ml_shell); + c = getcc(); + goto again; +#else + error("Command not available", NULL_PARG); + break; +#endif + + case A_B_BRACKET: + case A_F_BRACKET: + start_mca(action, "Brackets: ", (void*)NULL); + 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, " ", (void*)NULL); + cmd_reset(); + (void) cmd_char(c); + } + c = getcc(); + goto again; + + case A_NOACTION: + break; + + default: + bell(); + break; + } + } +} |