X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/00896020c954c6ae12d02f92f78155d1d033c5aa..b4a09a32d1cdc7706df24af5b17e1c0c9371a659:/usr/src/usr.bin/more/command.c diff --git a/usr/src/usr.bin/more/command.c b/usr/src/usr.bin/more/command.c index 3aac884d74..a654489506 100644 --- a/usr/src/usr.bin/more/command.c +++ b/usr/src/usr.bin/more/command.c @@ -3,15 +3,13 @@ * Copyright (c) 1988 Regents of the University of California. * All rights reserved. * - * This code is derived from software contributed to Berkeley by - * Mark Nudleman. - * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed - * by the University of California, Berkeley. The name of the + * by Mark Nudleman and the University of California, Berkeley. The + * name of Mark Nudleman or the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR @@ -20,22 +18,19 @@ */ #ifndef lint -static char sccsid[] = "@(#)command.c 5.4 (Berkeley) %G%"; +static char sccsid[] = "@(#)command.c 5.16 (Berkeley) %G%"; #endif /* not lint */ -/* - * User-level command processor. - */ - -#include "less.h" -#include "position.h" -#include "cmd.h" +#include +#include +#include +#include #define NO_MCA 0 #define MCA_DONE 1 #define MCA_MORE 2 -extern int erase_char, kill_char; +extern int erase_char, kill_char, werase_char; extern int ispipe; extern int sigs; extern int quit_at_eof; @@ -47,58 +42,43 @@ extern int curr_ac; extern int ac; extern int quitting; extern int scroll; -extern char *first_cmd; -extern char *every_first_cmd; -extern char version[]; -extern char *current_file; -extern char *editor; extern int screen_trashed; /* The screen has been overwritten */ static char cmdbuf[120]; /* Buffer for holding a multi-char command */ static char *cp; /* Pointer into cmdbuf */ static int cmd_col; /* Current column of the multi-char command */ +static int longprompt; /* if stat command instead of prompt */ static int mca; /* The multicharacter command (action) */ static int last_mca; /* The previous mca */ static int number; /* The number typed by the user */ static int wsearch; /* Search for matches (1) or non-matches (0) */ -/* - * Reset command buffer (to empty). - */ -cmd_reset() -{ - cp = cmdbuf; -} +#define CMD_RESET cp = cmdbuf /* reset command buffer to empty */ +#define CMD_EXEC lower_left(); flush() -/* - * Backspace in command buffer. - */ - static int +/* backspace in command buffer. */ +static cmd_erase() { + /* + * backspace past beginning of the string: this usually means + * abort the command. + */ if (cp == cmdbuf) - /* - * Backspace past beginning of the string: - * this usually means abort the command. - */ - return (1); + return(1); - if (control_char(*--cp)) - { - /* - * Erase an extra character, for the carat. - */ + /* erase an extra character, for the carat. */ + if (CONTROL_CHAR(*--cp)) { backspace(); - cmd_col--; + --cmd_col; } + backspace(); - cmd_col--; - return (0); + --cmd_col; + return(0); } -/* - * Set up the display to start a new multi-character command. - */ +/* set up the display to start a new multi-character command. */ start_mca(action, prompt) int action; char *prompt; @@ -111,260 +91,210 @@ start_mca(action, prompt) } /* - * Process a single character of a multi-character command, such as + * process a single character of a multi-character command, such as * a number, or the pattern of a search command. */ - static int +static cmd_char(c) int c; { if (c == erase_char) - { - if (cmd_erase()) - return (1); - } else if (c == kill_char) - { - /* {{ Could do this faster, but who cares? }} */ - while (cmd_erase() == 0) - ; - } else if (cp >= &cmdbuf[sizeof(cmdbuf)-1]) - { - /* - * No room in the command buffer. - */ - bell(); - } else if (cmd_col >= sc_width-3) - { - /* - * No room on the screen. - * {{ Could get fancy here; maybe shift the displayed - * line and make room for more chars, like ksh. }} - */ + return(cmd_erase()); + /* in this order, in case werase == erase_char */ + if (c == werase_char) { + if (cp > cmdbuf) { + while (isspace(cp[-1]) && !cmd_erase()); + while (!isspace(cp[-1]) && !cmd_erase()); + while (isspace(cp[-1]) && !cmd_erase()); + } + return(cp == cmdbuf); + } + if (c == kill_char) { + while (!cmd_erase()); + return(1); + } + /* + * No room in the command buffer, or no room on the screen; + * {{ Could get fancy here; maybe shift the displayed line + * and make room for more chars, like ksh. }} + */ + if (cp >= &cmdbuf[sizeof(cmdbuf)-1] || cmd_col >= sc_width-3) bell(); - } else - { - /* - * Append the character to the string. - */ + else { *cp++ = c; - if (control_char(c)) - { + if (CONTROL_CHAR(c)) { putchr('^'); cmd_col++; - c = carat_char(c); + c = CARAT_CHAR(c); } putchr(c); cmd_col++; } - return (0); + return(0); } -/* - * Return the number currently in the command buffer. - */ - static int -cmd_int() -{ - *cp = '\0'; - cp = cmdbuf; - return (atoi(cmdbuf)); -} - -/* - * 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(); -} - -/* - * Display the appropriate prompt. - */ - static void prompt() { - register char *p; - - if (first_cmd != NULL && *first_cmd != '\0') - { - /* - * No prompt necessary if commands are from first_cmd - * rather than from the user. - */ - return; - } + extern int linenums; + extern char *current_name, *firstsearch, *next_name; + off_t len, pos, ch_length(), position(), forw_line(); + char pbuf[40]; /* - * If nothing is displayed yet, display starting from line 1. + * if nothing is displayed yet, display starting from line 1; + * if search string provided, go there instead. */ - if (position(TOP) == NULL_POSITION) - jump_back(1); + if (position(TOP) == NULL_POSITION) { + if (forw_line((off_t)0) == NULL_POSITION) + return(0); + if (!firstsearch || !search(1, firstsearch, 1, 1)) + jump_back(1); + } 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 && curr_ac + 1 >= ac) + /* if no -e flag and we've hit EOF on the last file, quit. */ + if (!quit_at_eof && hit_eof && curr_ac + 1 >= ac) quit(); - /* - * Select the proper prompt and display it. - */ + /* select the proper prompt and display it. */ lower_left(); clear_eol(); - p = pr_string(); - if (p == NULL) - putchr(':'); - else - { + if (longprompt) { so_enter(); - putstr(p); + putstr(current_name); + putstr(":"); + if (!ispipe) { + (void)sprintf(pbuf, " file %d/%d", curr_ac + 1, ac); + putstr(pbuf); + } + if (linenums) { + (void)sprintf(pbuf, " line %d", currline(BOTTOM)); + putstr(pbuf); + } + if ((pos = position(BOTTOM)) != NULL_POSITION) { + (void)sprintf(pbuf, " byte %ld", pos); + putstr(pbuf); + if (!ispipe && (len = ch_length())) { + (void)sprintf(pbuf, "/%ld pct %ld%%", + len, ((100 * pos) / len)); + putstr(pbuf); + } + } + so_exit(); + longprompt = 0; + } + else { + so_enter(); + putstr(current_name); + if (hit_eof) + if (next_name) { + (void)sprintf(pbuf, ": END (next file: %s)", + next_name); + putstr(pbuf); + } + else + putstr(": END"); + else if (!ispipe && + (pos = position(BOTTOM)) != NULL_POSITION && + (len = ch_length())) { + (void)sprintf(pbuf, " (%ld%%)", ((100 * pos) / len)); + putstr(pbuf); + } so_exit(); } + return(1); } -/* - * Get command character. - * The character normally comes from the keyboard, - * but may come from the "first_cmd" string. - */ - static int +/* get command character. */ +static getcc() { - if (first_cmd == NULL) - return (getchr()); - - if (*first_cmd == '\0') - { + extern int cmdstack; + int ch; + + /* left over from error() routine. */ + if (cmdstack) { + ch = cmdstack; + cmdstack = NULL; + return(ch); + } + if (cp > cmdbuf && position(TOP) == NULL_POSITION) { /* - * Reached end of first_cmd input. + * Command is incomplete, so try to complete it. + * There are only two cases: + * 1. We have "/string" but no newline. Add the \n. + * 2. We have a number but no command. Treat as #g. + * (This is all pretty hokey.) */ - first_cmd = NULL; - if (cp > cmdbuf && position(TOP) == NULL_POSITION) - { - /* - * Command is incomplete, so try to complete it. - * There are only two cases: - * 1. We have "/string" but no newline. Add the \n. - * 2. We have a number but no command. Treat as #g. - * (This is all pretty hokey.) - */ - if (mca != A_DIGIT) - /* Not a number; must be search string */ - return ('\n'); - else - /* A number; append a 'g' */ - return ('g'); - } - return (getchr()); + if (mca != A_DIGIT) + /* Not a number; must be search string */ + return('\n'); + else + /* A number; append a 'g' */ + return('g'); } - return (*first_cmd++); + return(getchr()); } -/* - * Execute a multicharacter command. - */ - static void +/* execute a multicharacter command. */ +static exec_mca() { + extern int file; + extern char *tagfile; register char *p; + char *glob(); *cp = '\0'; - cmd_exec(); - switch (mca) - { + CMD_EXEC; + switch (mca) { case A_F_SEARCH: - search(1, cmdbuf, number, wsearch); + (void)search(1, cmdbuf, number, wsearch); break; case A_B_SEARCH: - search(0, cmdbuf, number, wsearch); - break; - case A_FIRSTCMD: - /* - * Skip leading spaces or + signs in the string. - */ - for (p = cmdbuf; *p == '+' || *p == ' '; p++) - ; - if (every_first_cmd != NULL) - free(every_first_cmd); - if (*p == '\0') - every_first_cmd = NULL; - else - every_first_cmd = save(p); - break; - case A_TOGGLE_OPTION: - toggle_option(cmdbuf, 1); + (void)search(0, cmdbuf, number, wsearch); break; case A_EXAMINE: - /* - * Ignore leading spaces in the filename. - */ - for (p = cmdbuf; *p == ' '; p++) - ; - edit(glob(p)); + for (p = cmdbuf; isspace(*p); ++p); + (void)edit(glob(p)); + break; + case A_TAGFILE: + for (p = cmdbuf; isspace(*p); ++p); + findtag(p); + if (tagfile == NULL) + break; + if (edit(tagfile)) + (void)tagsearch(); break; } } -/* - * Add a character to a multi-character command. - */ - static int +/* add a character to a multi-character command. */ +static mca_char(c) int c; { - switch (mca) - { - case 0: - /* - * Not in a multicharacter command. - */ - return (NO_MCA); - - case A_PREFIX: - /* - * In the prefix of a command. - */ - return (NO_MCA); - + switch (mca) { + case 0: /* not in a multicharacter command. */ + case A_PREFIX: /* in the prefix of a command. */ + 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) - { + if (!isascii(c) || !isdigit(c) && + c != erase_char && c != kill_char && c != werase_char) { /* * Not part of the number. * Treat as a normal command character. */ - number = cmd_int(); + *cp = '\0'; + number = atoi(cmdbuf); + CMD_RESET; mca = 0; - return (NO_MCA); - } - break; - - case A_TOGGLE_OPTION: - /* - * Special case for the TOGGLE_OPTION command. - * if the option letter which was entered is a - * single-char option, execute the command immediately, - * so he doesn't have to hit RETURN. - */ - if (cp == cmdbuf && c != erase_char && c != kill_char && - single_char_option(c)) - { - cmdbuf[0] = c; - cmdbuf[1] = '\0'; - toggle_option(cmdbuf, 1); - return (MCA_DONE); + return(NO_MCA); } break; } @@ -373,33 +303,22 @@ mca_char(c) * Any other multicharacter command * is terminated by a newline. */ - if (c == '\n' || c == '\r') - { - /* - * Execute the command. - */ + if (c == '\n' || c == '\r') { exec_mca(); - return (MCA_DONE); + return(MCA_DONE); } - /* - * Append the char to the command buffer. - */ + + /* append the char to the command buffer. */ if (cmd_char(c)) - /* - * Abort the multi-char command. - */ - return (MCA_DONE); - /* - * Need another character. - */ - return (MCA_MORE); + return(MCA_DONE); + + return(MCA_MORE); } /* * Main command processor. * Accept and execute commands until a quit command, then return. */ - public void commands() { register int c; @@ -408,31 +327,30 @@ commands() last_mca = 0; scroll = (sc_height + 1) / 2; - for (;;) - { + for (;;) { mca = 0; number = 0; /* * See if any signals need processing. */ - if (sigs) - { + if (sigs) { psignals(); if (quitting) quit(); } - /* * Display prompt and accept a character. */ - cmd_reset(); - prompt(); + CMD_RESET; + if (!prompt()) { + next_file(1); + continue; + } noprefix(); c = getcc(); - again: - if (sigs) +again: if (sigs) continue; /* @@ -441,8 +359,7 @@ commands() * action to be performed. */ if (mca) - switch (mca_char(c)) - { + switch (mca_char(c)) { case MCA_MORE: /* * Need another character. @@ -463,299 +380,155 @@ commands() break; } - /* - * Decode the command character and decide what to do. - */ - switch (action = cmd_decode(c)) - { - case A_DIGIT: - /* - * First digit of a number. - */ + /* decode the command character and decide what to do. */ + switch (action = cmd_decode(c)) { + case A_DIGIT: /* first digit of a number */ start_mca(A_DIGIT, ":"); goto again; - - case A_F_SCREEN: - /* - * Forward one screen. - */ - if (number <= 0) - number = sc_window; - if (number <= 0) + case A_F_SCREEN: /* forward one screen */ + CMD_EXEC; + if (number <= 0 && (number = sc_window) <= 0) number = sc_height - 1; - cmd_exec(); forward(number, 1); break; - - case A_B_SCREEN: - /* - * Backward one screen. - */ - if (number <= 0) - number = sc_window; - if (number <= 0) + case A_B_SCREEN: /* backward one screen */ + CMD_EXEC; + if (number <= 0 && (number = sc_window) <= 0) number = sc_height - 1; - cmd_exec(); backward(number, 1); break; - - case A_F_LINE: - /* - * Forward N (default 1) line. - */ - if (number <= 0) - number = 1; - cmd_exec(); - forward(number, 0); + case A_F_LINE: /* forward N (default 1) line */ + CMD_EXEC; + forward(number <= 0 ? 1 : number, 0); break; - - case A_B_LINE: - /* - * Backward N (default 1) line. - */ - if (number <= 0) - number = 1; - cmd_exec(); - backward(number, 0); + case A_B_LINE: /* backward N (default 1) line */ + CMD_EXEC; + backward(number <= 0 ? 1 : number, 0); break; - - case A_F_SCROLL: - /* - * Forward N lines - * (default same as last 'd' or 'u' command). - */ + case A_F_SCROLL: /* forward N lines */ + CMD_EXEC; if (number > 0) scroll = number; - cmd_exec(); forward(scroll, 0); break; - - case A_B_SCROLL: - /* - * Forward N lines - * (default same as last 'd' or 'u' command). - */ + case A_B_SCROLL: /* backward N lines */ + CMD_EXEC; if (number > 0) scroll = number; - cmd_exec(); backward(scroll, 0); break; - - case A_FREPAINT: - /* - * Flush buffers, then repaint screen. - * Don't flush the buffers on a pipe! - */ - if (!ispipe) - { + case A_FREPAINT: /* flush buffers and repaint */ + if (!ispipe) { ch_init(0, 0); clr_linenum(); } - /* FALLTHRU */ - case A_REPAINT: - /* - * Repaint screen. - */ - cmd_exec(); + /* FALLTHROUGH */ + case A_REPAINT: /* repaint the screen */ + CMD_EXEC; repaint(); break; - - case A_GOLINE: - /* - * Go to line N, default beginning of file. - */ + case A_GOLINE: /* go to line N, default 1 */ + CMD_EXEC; if (number <= 0) number = 1; - cmd_exec(); jump_back(number); break; - - case A_PERCENT: - /* - * Go to a specified percentage into the file. - */ + case A_PERCENT: /* go to percent of file */ + CMD_EXEC; if (number < 0) number = 0; - if (number > 100) + else if (number > 100) number = 100; - cmd_exec(); jump_percent(number); break; - - case A_GOEND: - /* - * Go to line N, default end of file. - */ - cmd_exec(); + case A_GOEND: /* go to line N, default end */ + CMD_EXEC; if (number <= 0) jump_forw(); else jump_back(number); break; - - case A_STAT: - /* - * Print file name, etc. - */ - cmd_exec(); - error(eq_message()); - break; - - case A_VERSION: - /* - * Print version number, without the "@(#)". - */ - cmd_exec(); - error(version+4); - break; - - case A_QUIT: - /* - * Exit. - */ + case A_STAT: /* print file name, etc. */ + longprompt = 1; + continue; + case A_QUIT: /* exit */ quit(); - - case A_F_SEARCH: + case A_F_SEARCH: /* search for a pattern */ case A_B_SEARCH: - /* - * Search for a pattern. - * Accept chars of the pattern until \n. - */ if (number <= 0) number = 1; start_mca(action, (action==A_F_SEARCH) ? "/" : "?"); last_mca = mca; wsearch = 1; c = getcc(); - if (c == '!') - { + if (c == '!') { /* - * Invert the sense of the search. - * Set wsearch to 0 and get a new - * character for the start of the pattern. + * Invert the sense of the search; set wsearch + * to 0 and get a new character for the start + * of the pattern. */ start_mca(action, - (action==A_F_SEARCH) ? "!/" : "!?"); + (action == A_F_SEARCH) ? "!/" : "!?"); wsearch = 0; c = getcc(); } goto again; - - case A_AGAIN_SEARCH: - /* - * Repeat previous search. - */ + case A_AGAIN_SEARCH: /* repeat previous search */ if (number <= 0) number = 1; if (wsearch) start_mca(last_mca, - (last_mca==A_F_SEARCH) ? "/" : "?"); + (last_mca == A_F_SEARCH) ? "/" : "?"); else start_mca(last_mca, - (last_mca==A_F_SEARCH) ? "!/" : "!?"); - cmd_exec(); - search(mca==A_F_SEARCH, (char *)NULL, number, wsearch); + (last_mca == A_F_SEARCH) ? "!/" : "!?"); + CMD_EXEC; + (void)search(mca == A_F_SEARCH, (char *)NULL, + number, wsearch); break; - - case A_HELP: - /* - * Help. - */ + case A_HELP: /* help */ lower_left(); clear_eol(); putstr("help"); - cmd_exec(); + CMD_EXEC; help(); break; - - case A_EXAMINE: - /* - * Edit a new file. Get the filename. - */ - cmd_reset(); + case A_TAGFILE: /* tag a new file */ + CMD_RESET; + start_mca(A_TAGFILE, "Tag: "); + c = getcc(); + goto again; + case A_FILE_LIST: /* show list of file names */ + CMD_EXEC; + showlist(); + repaint(); + break; + case A_EXAMINE: /* edit a new file */ + CMD_RESET; start_mca(A_EXAMINE, "Examine: "); c = getcc(); goto again; - - case A_VISUAL: - /* - * Invoke an editor on the input file. - */ - if (ispipe) - { + case A_VISUAL: /* invoke the editor */ + if (ispipe) { error("Cannot edit standard input"); break; } - /* - * Try to pass the line number to the editor. - */ - cmd_exec(); - c = currline(MIDDLE); - if (c == 0) - sprintf(cmdbuf, "%s %s", - editor, current_file); - else - sprintf(cmdbuf, "%s +%d %s", - editor, c, current_file); - lsystem(cmdbuf); + CMD_EXEC; + editfile(); ch_init(0, 0); clr_linenum(); break; - - case A_NEXT_FILE: - /* - * Examine next file. - */ + case A_NEXT_FILE: /* examine next file */ if (number <= 0) number = 1; next_file(number); break; - - case A_PREV_FILE: - /* - * Examine previous file. - */ + case A_PREV_FILE: /* examine previous file */ if (number <= 0) number = 1; prev_file(number); break; - - case A_TOGGLE_OPTION: - /* - * Toggle a flag setting. - */ - cmd_reset(); - start_mca(A_TOGGLE_OPTION, "-"); - c = getcc(); - goto again; - - case A_DISP_OPTION: - /* - * Report a flag setting. - */ - cmd_reset(); - start_mca(A_DISP_OPTION, "_"); - c = getcc(); - if (c == erase_char || c == kill_char) - break; - cmdbuf[0] = c; - cmdbuf[1] = '\0'; - toggle_option(cmdbuf, 0); - break; - - case A_FIRSTCMD: - /* - * Set an initial command for new files. - */ - cmd_reset(); - start_mca(A_FIRSTCMD, "+"); - c = getcc(); - goto again; - - case A_SETMARK: - /* - * Set a mark. - */ + case A_SETMARK: /* set a mark */ lower_left(); clear_eol(); start_mca(A_SETMARK, "mark: "); @@ -764,11 +537,7 @@ commands() break; setmark(c); break; - - case A_GOMARK: - /* - * Go to a mark. - */ + case A_GOMARK: /* go to mark */ lower_left(); clear_eol(); start_mca(A_GOMARK, "goto mark: "); @@ -777,27 +546,96 @@ commands() break; gomark(c); break; - 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. + * Display the current char so the user knows what's + * going on and get another character. */ if (mca != A_PREFIX) - start_mca(A_PREFIX, "& "); - if (control_char(c)) - { + start_mca(A_PREFIX, ""); + if (CONTROL_CHAR(c)) { putchr('^'); - c = carat_char(c); + c = CARAT_CHAR(c); } putchr(c); c = getcc(); goto again; - default: bell(); break; } } } + +static +editfile() +{ + extern char *current_file; + static int dolinenumber; + static char *editor; + int c; + char buf[MAXPATHLEN * 2 + 20], *getenv(); + + if (editor == NULL) { + editor = getenv("EDITOR"); + /* pass the line number to vi */ + if (editor == NULL || *editor == '\0') { +#define EDIT_PGM "/usr/ucb/vi" + editor = EDIT_PGM; + dolinenumber = 1; + } + else + dolinenumber = 0; + } + if (dolinenumber && (c = currline(MIDDLE))) + (void)sprintf(buf, "%s +%d %s", editor, c, current_file); + else + (void)sprintf(buf, "%s %s", editor, current_file); + lsystem(buf); +} + +static +showlist() +{ + extern int sc_width; + extern char **av; + register int indx, width; + int len; + char *p; + + if (ac <= 0) { + error("No files provided as arguments."); + return; + } + for (width = indx = 0; indx < ac;) { + p = strcmp(av[indx], "-") ? av[indx] : "stdin"; + len = strlen(p) + 1; + if (curr_ac == indx) + len += 2; + if (width + len + 1 >= sc_width) { + if (!width) { + if (curr_ac == indx) + putchr('['); + putstr(p); + if (curr_ac == indx) + putchr(']'); + ++indx; + } + width = 0; + putchr('\n'); + continue; + } + if (width) + putchr(' '); + if (curr_ac == indx) + putchr('['); + putstr(p); + if (curr_ac == indx) + putchr(']'); + width += len; + ++indx; + } + putchr('\n'); + error((char *)NULL); +}