=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/less/command.c,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- src/usr.bin/less/command.c 2003/04/10 15:53:30 1.5 +++ src/usr.bin/less/command.c 2003/04/13 18:26:25 1.6 @@ -1,29 +1,11 @@ -/* $OpenBSD: command.c,v 1.5 2003/04/10 15:53:30 millert Exp $ */ - /* - * Copyright (c) 1984,1985,1989,1994,1995 Mark Nudelman - * All rights reserved. + * Copyright (C) 1984-2002 Mark Nudelman * - * 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. + * You may distribute under the terms of either the GNU General Public + * License or the Less License, as specified in the README file. * - * 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. + * For more information about less, or for information on how to + * contact the author, see the README file. */ @@ -32,6 +14,9 @@ */ #include "less.h" +#if MSDOS_COMPILER==WIN32C +#include +#endif #include "position.h" #include "option.h" #include "cmd.h" @@ -39,6 +24,8 @@ extern int erase_char, kill_char; extern int sigs; extern int quit_at_eof; +extern int quit_if_one_screen; +extern int squished; extern int hit_eof; extern int sc_width; extern int sc_height; @@ -46,45 +33,42 @@ extern int jump_sline; extern int quitting; extern int wscroll; -extern int nohelp; extern int top_scroll; extern int ignore_eoi; +extern int secure; +extern int hshift; +extern int show_attn; 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; +extern void constant *ml_search; +extern void constant *ml_examine; #if SHELL_ESCAPE || PIPEC -extern void *ml_shell; +extern void constant *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 */ +extern int shift_count; extern int be_helpful; -public int helpprompt; - -static char ungot[100]; +static char ungot[UNGOT_SIZE]; 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 LINENUM number; /* The number typed by the user */ static char optchar; static int optflag; +static int optgetname; +static POSITION bottompos; +static char *help_prompt; #if PIPEC static char pipec; #endif @@ -99,6 +83,7 @@ static void cmd_exec() { + clear_attn(); lower_left(); flush(); } @@ -107,17 +92,16 @@ * Set up the display to start a new multi-character command. */ static void -start_mca(action, prompt, mlist) +start_mca(action, prompt, mlist, cmdflags) int action; char *prompt; void *mlist; + int cmdflags; { mca = action; - clear_bot(); + clear_cmd(); cmd_putstr(prompt); -#if CMD_HISTORY - set_mlist(mlist); -#endif + set_mlist(mlist, cmdflags); } public int @@ -137,33 +121,66 @@ else mca = A_B_SEARCH; - clear_bot(); + clear_cmd(); + if (search_type & SRCH_NO_MATCH) + cmd_putstr("Non-match "); if (search_type & SRCH_FIRST_FILE) - cmd_putstr("@"); - + cmd_putstr("First-file "); if (search_type & SRCH_PAST_EOF) - cmd_putstr("*"); + cmd_putstr("EOF-ignore "); + if (search_type & SRCH_NO_MOVE) + cmd_putstr("Keep-pos "); + if (search_type & SRCH_NO_REGEX) + cmd_putstr("Regex-off "); - 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 + set_mlist(ml_search, 0); } /* + * Set up the display to start a new toggle-option command. + */ + static void +mca_opt_toggle() +{ + int no_prompt; + int flag; + char *dash; + + no_prompt = (optflag & OPT_NO_PROMPT); + flag = (optflag & ~OPT_NO_PROMPT); + dash = (flag == OPT_NO_TOGGLE) ? "_" : "-"; + + mca = A_OPT_TOGGLE; + clear_cmd(); + cmd_putstr(dash); + if (optgetname) + cmd_putstr(dash); + if (no_prompt) + cmd_putstr("(P)"); + switch (flag) + { + case OPT_UNSET: + cmd_putstr("+"); + break; + case OPT_SET: + cmd_putstr("!"); + break; + } + set_mlist(NULL, 0); +} + +/* * Execute a multicharacter command. */ static void exec_mca() { - char *cbuf; + register char *cbuf; cmd_exec(); cbuf = get_cmdbuf(); @@ -172,7 +189,7 @@ { case A_F_SEARCH: case A_B_SEARCH: - multi_search(cbuf, number); + multi_search(cbuf, (int) number); break; case A_FIRSTCMD: /* @@ -192,14 +209,20 @@ optchar = '\0'; break; case A_F_BRACKET: - match_brac(cbuf[0], cbuf[1], 1, number); + match_brac(cbuf[0], cbuf[1], 1, (int) number); break; case A_B_BRACKET: - match_brac(cbuf[1], cbuf[0], 0, number); + match_brac(cbuf[1], cbuf[0], 0, (int) number); break; #if EXAMINE case A_EXAMINE: + if (secure) + break; edit_list(cbuf); +#if TAGS + /* If tag structure is loaded then clean it up. */ + cleantags(); +#endif break; #endif #if SHELL_ESCAPE @@ -216,15 +239,18 @@ shellcmd = fexpand(cbuf); } + if (secure) + break; if (shellcmd == NULL) - lsystem(""); + lsystem("", "!done"); else - lsystem(shellcmd); - error("!done", NULL_PARG); + lsystem(shellcmd, "!done"); break; #endif #if PIPEC case A_PIPE: + if (secure) + break; (void) pipe_mark(pipec, cbuf); error("|done", NULL_PARG); break; @@ -242,6 +268,7 @@ char *p; int flag; char buf[3]; + PARG parg; switch (mca) { @@ -266,7 +293,7 @@ * Terminated by a non-digit. */ if ((c < '0' || c > '9') && - editchar(c, EC_PEEK|EC_NOHISTORY|EC_NOCOMPLETE) == A_INVALID) + editchar(c, EC_PEEK|EC_NOHISTORY|EC_NOCOMPLETE|EC_NORIGHTLEFT) == A_INVALID) { /* * Not part of the number. @@ -287,35 +314,137 @@ * 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. + * "--" begins inputting a long option name. */ - if (c == erase_char || c == kill_char) - break; - if (optchar != '\0' && optchar != '+' && optchar != '-') + if (optchar == '\0' && len_cmdbuf() == 0) + { + flag = (optflag & ~OPT_NO_PROMPT); + if (flag == OPT_NO_TOGGLE) + { + switch (c) + { + case '_': + /* "__" = long option name. */ + optgetname = TRUE; + mca_opt_toggle(); + return (MCA_MORE); + } + } else + { + switch (c) + { + case '+': + /* "-+" = UNSET. */ + optflag = (flag == OPT_UNSET) ? + OPT_TOGGLE : OPT_UNSET; + mca_opt_toggle(); + return (MCA_MORE); + case '!': + /* "-!" = SET */ + optflag = (flag == OPT_SET) ? + OPT_TOGGLE : OPT_SET; + mca_opt_toggle(); + return (MCA_MORE); + case CONTROL('P'): + optflag ^= OPT_NO_PROMPT; + mca_opt_toggle(); + return (MCA_MORE); + case '-': + /* "--" = long option name. */ + optgetname = TRUE; + mca_opt_toggle(); + return (MCA_MORE); + } + } + } + if (optgetname) + { /* - * We already have the option letter. + * We're getting a long option name. + * See if we've matched an option name yet. + * If so, display the complete name and stop + * accepting chars until user hits RETURN. */ - break; - switch (c) - { - case '+': - optflag = OPT_UNSET; - break; - case '-': - optflag = OPT_SET; - break; - default: - optchar = c; - if (optflag != OPT_TOGGLE || single_char_option(c)) + struct loption *o; + char *oname; + int lc; + + if (c == '\n' || c == '\r') { - toggle_option(c, "", optflag); - return (MCA_DONE); + /* + * When the user hits RETURN, make sure + * we've matched an option name, then + * pretend he just entered the equivalent + * option letter. + */ + if (optchar == '\0') + { + parg.p_string = get_cmdbuf(); + error("There is no --%s option", &parg); + return (MCA_DONE); + } + optgetname = FALSE; + cmd_reset(); + c = optchar; + } else + { + if (optchar != '\0') + { + /* + * Already have a match for the name. + * Don't accept anything but erase/kill. + */ + if (c == erase_char || c == kill_char) + return (MCA_DONE); + return (MCA_MORE); + } + /* + * Add char to cmd buffer and try to match + * the option name. + */ + if (cmd_char(c) == CC_QUIT) + return (MCA_DONE); + p = get_cmdbuf(); + lc = islower(p[0]); + o = findopt_name(&p, &oname, NULL); + if (o != NULL) + { + /* + * Got a match. + * Remember the option letter and + * display the full option name. + */ + optchar = o->oletter; + if (!lc && islower(optchar)) + optchar = toupper(optchar); + cmd_reset(); + mca_opt_toggle(); + for (p = oname; *p != '\0'; p++) + { + c = *p; + if (!lc && islower(c)) + c = toupper(c); + if (cmd_char(c) != CC_OK) + return (MCA_DONE); + } + } + return (MCA_MORE); } - break; + } else + { + if (c == erase_char || c == kill_char) + break; + if (optchar != '\0') + /* We already have the option letter. */ + break; } - if (optchar == '+' || optchar == '-') + + optchar = c; + if ((optflag & ~OPT_NO_PROMPT) != OPT_TOGGLE || + single_char_option(c)) { - optchar = c; - break; + toggle_option(c, "", optflag); + return (MCA_DONE); } /* * Display a prompt appropriate for the option letter. @@ -327,7 +456,7 @@ buf[2] = '\0'; p = buf; } - start_mca(A_OPT_TOGGLE, p, (void*)NULL); + start_mca(A_OPT_TOGGLE, p, (void*)NULL, 0); return (MCA_MORE); case A_F_SEARCH: @@ -336,7 +465,7 @@ * Special case for search commands. * Certain characters as the first char of * the pattern have special meaning: - * ! Toggle the NOMATCH flag + * ! Toggle the NO_MATCH flag * * Toggle the PAST_EOF flag * @ Toggle the FIRST_FILE flag */ @@ -349,15 +478,24 @@ flag = 0; switch (c) { - case '!': - flag = SRCH_NOMATCH; + case CONTROL('E'): /* ignore END of file */ + case '*': + flag = SRCH_PAST_EOF; break; + case CONTROL('F'): /* FIRST file */ case '@': flag = SRCH_FIRST_FILE; break; - case '*': - flag = SRCH_PAST_EOF; + case CONTROL('K'): /* KEEP position */ + flag = SRCH_NO_MOVE; break; + case CONTROL('R'): /* Don't use REGULAR EXPRESSIONS */ + flag = SRCH_NO_REGEX; + break; + case CONTROL('N'): /* NOT match */ + case '!': + flag = SRCH_NO_MATCH; + break; } if (flag != 0) { @@ -380,6 +518,7 @@ exec_mca(); return (MCA_DONE); } + /* * Append the char to the command buffer. */ @@ -407,22 +546,11 @@ } /* - * Display the appropriate prompt. + * Make sure the screen is displayed. */ static void -prompt() +make_display() { - 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. */ @@ -446,45 +574,84 @@ repaint(); top_scroll = save_top_scroll; } +} +/* + * 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; + } + /* + * Make sure the screen is displayed. + */ + make_display(); + bottompos = position(BOTTOM_PLUS_ONE); + + /* * If the -E flag is set and we've hit EOF on the last file, quit. */ - if (quit_at_eof == OPT_ONPLUS && hit_eof && + if ((quit_at_eof == OPT_ONPLUS || quit_if_one_screen) && + hit_eof && !(ch_getflags() & CH_HELPFILE) && next_ifile(curr_ifile) == NULL_IFILE) quit(QUIT_OK); + quit_if_one_screen = FALSE; +#if 0 /* This doesn't work well because some "te"s clear the screen. */ + /* + * If the -e flag is set and we've hit EOF on the last file, + * and the file is squished (shorter than the screen), quit. + */ + if (quit_at_eof && squished && + next_ifile(curr_ifile) == NULL_IFILE) + quit(QUIT_OK); +#endif +#if MSDOS_COMPILER==WIN32C + /* + * In Win32, display the file name in the window title. + */ + if (!(ch_getflags() & CH_HELPFILE)) + SetConsoleTitle(pr_expand("Less?f - %f.", 0)); +#endif /* * Select the proper prompt and display it. */ - clear_bot(); - if (helpprompt) { + clear_cmd(); + p = help_prompt ? help_prompt : pr_string(); + if (p == NULL) + putchr(':'); + else + { so_enter(); - putstr("[Press 'h' for instructions.]"); + putstr(p); + if (be_helpful && !help_prompt && strlen(p) + 40 < sc_width) + putstr(" [Press space to continue, 'q' to quit.]"); so_exit(); - helpprompt = 0; - } else { - p = pr_string(); - if (p == NULL) - putchr(':'); - else - { - so_enter(); - putstr(p); - if (be_helpful && strlen(p) + 40 < sc_width) - putstr(" [Press space to continue, 'q' to quit.]"); - so_exit(); - } } + help_prompt = NULL; } +/* + * Display the less version message. + */ public void dispversion() { PARG parg; parg.p_string = version; - error("less version %s", &parg); + error("less %s", &parg); } /* @@ -566,7 +733,7 @@ ungetsc(s) char *s; { - char *p; + register char *p; for (p = s + strlen(s) - 1; p >= s; p--) ungetcc(*p); @@ -582,12 +749,12 @@ char *pattern; int n; { - int nomore; + register int nomore; IFILE save_ifile; int changed_file; changed_file = 0; - save_ifile = curr_ifile; + save_ifile = save_curr_ifile(); if (search_type & SRCH_FIRST_FILE) { @@ -600,18 +767,31 @@ else nomore = edit_last(); if (nomore) + { + unsave_ifile(save_ifile); return; + } changed_file = 1; search_type &= ~SRCH_FIRST_FILE; } for (;;) { - if ((n = search(search_type, pattern, n)) == 0) + n = search(search_type, pattern, n); + /* + * The SRCH_NO_MOVE flag doesn't "stick": it gets cleared + * after being used once. This allows "n" to work after + * using a /@@ search. + */ + search_type &= ~SRCH_NO_MOVE; + if (n == 0) + { /* * Found it. */ + unsave_ifile(save_ifile); return; + } if (n < 0) /* @@ -650,8 +830,7 @@ /* * Restore the file we were originally viewing. */ - if (edit_ifile(save_ifile)) - quit(QUIT_ERROR); + reedit_ifile(save_ifile); } } @@ -662,16 +841,21 @@ public void commands() { - int c; - int action; - char *cbuf; + register int c; + register int action; + register char *cbuf; + int newaction; int save_search_type; - char *s; + char *extra; char tbuf[2]; PARG parg; + IFILE old_ifile; + IFILE new_ifile; + char *tagfile; search_type = SRCH_FORW; wscroll = (sc_height + 1) / 2; + newaction = A_NOACTION; for (;;) { @@ -689,86 +873,100 @@ if (quitting) quit(QUIT_SAVED_STATUS); } - + /* + * See if window size changed, for systems that don't + * generate SIGWINCH. + */ + check_winch(); + + /* * Display prompt and accept a character. */ cmd_reset(); prompt(); if (sigs) continue; - c = getcc(); + if (newaction == A_NOACTION) + 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)) + if (newaction != A_NOACTION) + { + action = newaction; + newaction = A_NOACTION; + } else + { + /* + * 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) { - case MCA_MORE: /* - * Need another character. + * 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. */ - c = getcc(); - goto again; - case MCA_DONE: + if (cmd_char(c) == CC_QUIT || len_cmdbuf() == 0) + continue; + cbuf = get_cmdbuf(); + } else + { /* - * Command has been handled by mca_char. - * Start clean with a prompt. + * 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. */ - continue; - case NO_MCA: - /* - * Not a multi-char command - * (at least, not anymore). - */ - break; + tbuf[0] = c; + tbuf[1] = '\0'; + cbuf = tbuf; } - - /* - * Decode the command character and decide what to do. - */ - if (mca) - { + extra = NULL; + action = fcmd_decode(cbuf, &extra); /* - * 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 an "extra" string was returned, + * process it as a string of command characters. */ - 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; + if (extra != NULL) + ungetsc(extra); } - 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.) @@ -782,7 +980,7 @@ /* * First digit of a number. */ - start_mca(A_DIGIT, ":", (void*)NULL); + start_mca(A_DIGIT, ":", (void*)NULL, CF_QUIT_ON_ERASE); goto again; case A_F_WINDOW: @@ -790,7 +988,7 @@ * Forward one window (and set the window size). */ if (number > 0) - swindow = number; + swindow = (int) number; /* FALLTHRU */ case A_F_SCREEN: /* @@ -799,7 +997,9 @@ if (number <= 0) number = get_swindow(); cmd_exec(); - forward(number, 0, 1); + if (show_attn) + set_attnpos(bottompos); + forward((int) number, 0, 1); break; case A_B_WINDOW: @@ -807,7 +1007,7 @@ * Backward one window (and set the window size). */ if (number > 0) - swindow = number; + swindow = (int) number; /* FALLTHRU */ case A_B_SCREEN: /* @@ -816,7 +1016,7 @@ if (number <= 0) number = get_swindow(); cmd_exec(); - backward(number, 0, 1); + backward((int) number, 0, 1); break; case A_F_LINE: @@ -826,7 +1026,9 @@ if (number <= 0) number = 1; cmd_exec(); - forward(number, 0, 0); + if (show_attn == OPT_ONPLUS && number > 1) + set_attnpos(bottompos); + forward((int) number, 0, 0); break; case A_B_LINE: @@ -836,7 +1038,7 @@ if (number <= 0) number = 1; cmd_exec(); - backward(number, 0, 0); + backward((int) number, 0, 0); break; case A_FF_LINE: @@ -846,7 +1048,9 @@ if (number <= 0) number = 1; cmd_exec(); - forward(number, 1, 0); + if (show_attn == OPT_ONPLUS && number > 1) + set_attnpos(bottompos); + forward((int) number, 1, 0); break; case A_BF_LINE: @@ -856,20 +1060,40 @@ if (number <= 0) number = 1; cmd_exec(); - backward(number, 1, 0); + backward((int) number, 1, 0); break; + case A_FF_SCREEN: + /* + * Force forward one screen. + */ + if (number <= 0) + number = get_swindow(); + cmd_exec(); + if (show_attn == OPT_ONPLUS) + set_attnpos(bottompos); + forward((int) number, 1, 0); + break; + case A_F_FOREVER: /* * Forward forever, ignoring EOF. */ + if (ch_getflags() & CH_HELPFILE) + break; cmd_exec(); jump_forw(); ignore_eoi = 1; hit_eof = 0; - while (!ABORT_SIGS()) + while (!sigs) forward(1, 0, 0); ignore_eoi = 0; + /* + * This gets us back in "F mode" after processing + * a non-abort signal (e.g. window-change). + */ + if (sigs && !ABORT_SIGS()) + newaction = A_F_FOREVER; break; case A_F_SCROLL: @@ -878,8 +1102,10 @@ * (default same as last 'd' or 'u' command). */ if (number > 0) - wscroll = number; + wscroll = (int) number; cmd_exec(); + if (show_attn == OPT_ONPLUS) + set_attnpos(bottompos); forward(wscroll, 0, 0); break; @@ -889,7 +1115,7 @@ * (default same as last 'd' or 'u' command). */ if (number > 0) - wscroll = number; + wscroll = (int) number; cmd_exec(); backward(wscroll, 0, 0); break; @@ -903,6 +1129,9 @@ { ch_flush(); clr_linenum(); +#if HILITE_SEARCH + clr_hilite(); +#endif } /* FALLTHRU */ case A_REPAINT: @@ -932,7 +1161,7 @@ if (number > 100) number = 100; cmd_exec(); - jump_percent(number); + jump_percent((int) number); break; case A_GOEND: @@ -953,18 +1182,20 @@ cmd_exec(); if (number < 0) number = 0; - jump_line_loc((POSITION)number, jump_sline); + jump_line_loc((POSITION) number, jump_sline); break; case A_STAT: /* * Print file name, etc. */ + if (ch_getflags() & CH_HELPFILE) + break; cmd_exec(); parg.p_string = eq_message(); error("%s", &parg); break; - + case A_VERSION: /* * Print version number, without the "@(#)". @@ -977,7 +1208,21 @@ /* * Exit. */ + if (curr_ifile != NULL_IFILE && + ch_getflags() & CH_HELPFILE) + { + /* + * Quit while viewing the help file + * just means return to viewing the + * previous file. + */ + if (edit_prev(1) == 0) + break; + } + if (extra != NULL) + quit(*extra); quit(QUIT_OK); + break; /* * Define abbreviation for a commonly used sequence below. @@ -985,7 +1230,7 @@ #define DO_SEARCH() if (number <= 0) number = 1; \ mca_search(); \ cmd_exec(); \ - multi_search((char *)NULL, number); + multi_search((char *)NULL, (int) number); case A_F_SEARCH: @@ -1057,15 +1302,10 @@ /* * Help. */ - if (nohelp) - { - bell(); + if (ch_getflags() & CH_HELPFILE) break; - } - clear_bot(); - putstr(" help"); cmd_exec(); - help(0); + (void) edit(FAKE_HELPFILE); break; case A_EXAMINE: @@ -1073,7 +1313,12 @@ /* * Edit a new file. Get the filename. */ - start_mca(A_EXAMINE, "Examine: ", ml_examine); + if (secure) + { + error("Command not available", NULL_PARG); + break; + } + start_mca(A_EXAMINE, "Examine: ", ml_examine, 0); c = getcc(); goto again; #else @@ -1086,6 +1331,13 @@ * Invoke an editor on the input file. */ #if EDITOR + if (secure) + { + error("Command not available", NULL_PARG); + break; + } + if (ch_getflags() & CH_HELPFILE) + break; if (strcmp(get_filename(curr_ifile), "-") == 0) { error("Cannot edit standard input", NULL_PARG); @@ -1097,19 +1349,16 @@ NULL_PARG); break; } + start_mca(A_SHELL, "!", ml_shell, 0); /* * Expand the editor prototype string * and pass it to the system to execute. + * (Make sure the screen is displayed so the + * expansion of "+%lm" works.) */ + make_display(); 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); + lsystem(pr_expand(editproto, 0), (char*)NULL); break; #else error("Command not available", NULL_PARG); @@ -1120,11 +1369,19 @@ /* * Examine next file. */ +#if TAGS + if (ntags()) + { + error("No next file", NULL_PARG); + break; + } +#endif if (number <= 0) number = 1; - if (edit_next(number)) + if (edit_next((int) number)) { - if (quit_at_eof && hit_eof) + if (quit_at_eof && hit_eof && + !(ch_getflags() & CH_HELPFILE)) quit(QUIT_OK); parg.p_string = (number > 1) ? "(N-th) " : ""; error("No %snext file", &parg); @@ -1135,28 +1392,96 @@ /* * Examine previous file. */ +#if TAGS + if (ntags()) + { + error("No previous file", NULL_PARG); + break; + } +#endif if (number <= 0) number = 1; - if (edit_prev(number)) + if (edit_prev((int) number)) { parg.p_string = (number > 1) ? "(N-th) " : ""; error("No %sprevious file", &parg); } break; + case A_NEXT_TAG: +#if TAGS + if (number <= 0) + number = 1; + tagfile = nexttag((int) number); + if (tagfile == NULL) + { + error("No next tag", NULL_PARG); + break; + } + if (edit(tagfile) == 0) + { + POSITION pos = tagsearch(); + if (pos != NULL_POSITION) + jump_loc(pos, jump_sline); + } +#else + error("Command not available", NULL_PARG); +#endif + break; + + case A_PREV_TAG: +#if TAGS + if (number <= 0) + number = 1; + tagfile = prevtag((int) number); + if (tagfile == NULL) + { + error("No previous tag", NULL_PARG); + break; + } + if (edit(tagfile) == 0) + { + POSITION pos = tagsearch(); + if (pos != NULL_POSITION) + jump_loc(pos, jump_sline); + } +#else + error("Command not available", NULL_PARG); +#endif + break; + case A_INDEX_FILE: /* * Examine a particular file. */ if (number <= 0) number = 1; - if (edit_index(number)) + if (edit_index((int) number)) error("No such file", NULL_PARG); break; + case A_REMOVE_FILE: + if (ch_getflags() & CH_HELPFILE) + break; + old_ifile = curr_ifile; + new_ifile = getoff_ifile(curr_ifile); + if (new_ifile == NULL_IFILE) + { + bell(); + break; + } + if (edit_ifile(new_ifile) != 0) + { + reedit_ifile(old_ifile); + break; + } + del_ifile(old_ifile); + break; + case A_OPT_TOGGLE: - start_mca(A_OPT_TOGGLE, "-", (void*)NULL); optflag = OPT_TOGGLE; + optgetname = FALSE; + mca_opt_toggle(); c = getcc(); goto again; @@ -1164,18 +1489,17 @@ /* * Report a flag setting. */ - start_mca(A_DISP_OPTION, "_", (void*)NULL); + optflag = OPT_NO_TOGGLE; + optgetname = FALSE; + mca_opt_toggle(); c = getcc(); - if (c == erase_char || c == kill_char) - break; - toggle_option(c, "", OPT_NO_TOGGLE); - break; + goto again; case A_FIRSTCMD: /* * Set an initial command for new files. */ - start_mca(A_FIRSTCMD, "+", (void*)NULL); + start_mca(A_FIRSTCMD, "+", (void*)NULL, 0); c = getcc(); goto again; @@ -1184,7 +1508,12 @@ * Shell escape. */ #if SHELL_ESCAPE - start_mca(A_SHELL, "!", ml_shell); + if (secure) + { + error("Command not available", NULL_PARG); + break; + } + start_mca(A_SHELL, "!", ml_shell, 0); c = getcc(); goto again; #else @@ -1196,7 +1525,9 @@ /* * Set a mark. */ - start_mca(A_SETMARK, "mark: ", (void*)NULL); + if (ch_getflags() & CH_HELPFILE) + break; + start_mca(A_SETMARK, "mark: ", (void*)NULL, 0); c = getcc(); if (c == erase_char || c == kill_char || c == '\n' || c == '\r') @@ -1208,7 +1539,7 @@ /* * Go to a mark. */ - start_mca(A_GOMARK, "goto mark: ", (void*)NULL); + start_mca(A_GOMARK, "goto mark: ", (void*)NULL, 0); c = getcc(); if (c == erase_char || c == kill_char || c == '\n' || c == '\r') @@ -1218,7 +1549,12 @@ case A_PIPE: #if PIPEC - start_mca(A_PIPE, "|mark: ", (void*)NULL); + if (secure) + { + error("Command not available", NULL_PARG); + break; + } + start_mca(A_PIPE, "|mark: ", (void*)NULL, 0); c = getcc(); if (c == erase_char || c == kill_char) break; @@ -1227,7 +1563,7 @@ if (badmark(c)) break; pipec = c; - start_mca(A_PIPE, "!", ml_shell); + start_mca(A_PIPE, "!", ml_shell, 0); c = getcc(); goto again; #else @@ -1237,10 +1573,32 @@ case A_B_BRACKET: case A_F_BRACKET: - start_mca(action, "Brackets: ", (void*)NULL); + start_mca(action, "Brackets: ", (void*)NULL, 0); c = getcc(); goto again; + case A_LSHIFT: + if (number > 0) + shift_count = number; + else + number = (shift_count > 0) ? + shift_count : sc_width / 2; + if (number > hshift) + number = hshift; + hshift -= number; + screen_trashed = 1; + break; + + case A_RSHIFT: + if (number > 0) + shift_count = number; + else + number = (shift_count > 0) ? + shift_count : sc_width / 2; + hshift += number; + screen_trashed = 1; + break; + case A_PREFIX: /* * The command is incomplete (more chars are needed). @@ -1249,8 +1607,9 @@ */ if (mca != A_PREFIX) { - start_mca(A_PREFIX, " ", (void*)NULL); cmd_reset(); + start_mca(A_PREFIX, " ", (void*)NULL, + CF_QUIT_ON_ERASE); (void) cmd_char(c); } c = getcc(); @@ -1261,7 +1620,7 @@ default: if (be_helpful) - helpprompt = 1; + help_prompt = "[Press 'h' for instructions.]"; else bell(); break;