* Copyright (c) 1988 Mark Nudleman
* Copyright (c) 1988 Regents of the University of California.
* 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 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
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
static char sccsid
[] = "@(#)command.c 5.12 (Berkeley) %G%";
* User-level command processor.
extern int erase_char
, kill_char
, werase_char
;
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).
* Backspace in command buffer.
* Backspace past beginning of the string:
* this usually means abort the command.
if (CONTROL_CHAR(*--cp
)) {
* Erase an extra character, for the carat.
* Set up the display to start a new multi-character command.
start_mca(action
, prompt
)
cmd_col
= strlen(prompt
);
* Process a single character of a multi-character command, such as
* a number, or the pattern of a search command.
/* in this order, in case werase == erase_char */
while (isspace(cp
[-1]) && !cmd_erase());
while (!isspace(cp
[-1]) && !cmd_erase());
while (isspace(cp
[-1]) && !cmd_erase());
* 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)
* Return the number currently in the command buffer.
* Move the cursor to lower left before executing a command.
* This looks nicer if the command takes a long time before
extern int terseprompt
, linenums
;
extern char *current_name
, *firstsearch
;
off_t len
, pos
, ch_length(), position(), forw_line();
* if nothing is displayed yet, display starting from line 1;
* if search string provided, go there instead.
if (position(TOP
) == NULL_POSITION
) {
if (forw_line((off_t
)0) == NULL_POSITION
)
if (!firstsearch
|| !search(1, firstsearch
, 1, 1))
/* if no -e flag and we've hit EOF on the last file, quit. */
if (!quit_at_eof
&& hit_eof
&& curr_ac
+ 1 >= ac
)
/* select the proper prompt and display it. */
(void)sprintf(pbuf
, " file %d/%d", curr_ac
+ 1, ac
);
(void)sprintf(pbuf
, " line %d", currline(BOTTOM
));
if ((pos
= position(BOTTOM
)) != NULL_POSITION
) {
(void)sprintf(pbuf
, " byte %ld", pos
);
if (!ispipe
&& (len
= ch_length())) {
(void)sprintf(pbuf
, "/%ld pct %ld%%",
len
, ((100 * pos
) / len
));
(void)sprintf(pbuf
, ": %d", currline(TOP
));
/* left over from error() routine. */
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.)
/* Not a number; must be search string */
/* A number; append a 'g' */
* Execute a multicharacter command.
(void)search(1, cmdbuf
, number
, wsearch
);
(void)search(0, cmdbuf
, number
, wsearch
);
for (p
= cmdbuf
; isspace(*p
); ++p
);
for (p
= cmdbuf
; isspace(*p
); ++p
);
* Add a character to a multi-character command.
case 0: /* not in a multicharacter command. */
case A_PREFIX
: /* in the prefix of a command. */
* Entering digits of a number.
* Terminated by a non-digit.
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.
* Any other multicharacter command
* is terminated by a newline.
if (c
== '\n' || c
== '\r') {
* Append the char to the command buffer.
* Abort the multi-char command.
* Need another character.
* Main command processor.
* Accept and execute commands until a quit command, then return.
scroll
= (sc_height
+ 1) / 2;
* See if any signals need processing.
* Display prompt and accept a character.
* If we are in a multicharacter command, call mca_char.
* Otherwise we call cmd_decode to determine the
* action to be performed.
* Need another character.
* Command has been handled by mca_char.
* Start clean with a prompt.
* Not a multi-char command
* (at least, not anymore).
* Decode the command character and decide what to do.
switch (action
= cmd_decode(c
))
* First digit of a number.
* Forward N (default 1) line.
* Backward N (default 1) line.
* (default same as last 'd' or 'u' command).
* (default same as last 'd' or 'u' command).
* Flush buffers, then repaint screen.
* Don't flush the buffers on a pipe!
* Go to line N, default beginning of file.
* Go to a specified percentage into the file.
* Go to line N, default end of file.
case A_STAT
: /* print file name, etc. */
* Accept chars of the pattern until \n.
start_mca(action
, (action
==A_F_SEARCH
) ? "/" : "?");
* Invert the sense of the search.
* Set wsearch to 0 and get a new
* character for the start of the pattern.
(action
==A_F_SEARCH
) ? "!/" : "!?");
* Repeat previous search.
(last_mca
==A_F_SEARCH
) ? "/" : "?");
(last_mca
==A_F_SEARCH
) ? "!/" : "!?");
(void)search(mca
== A_F_SEARCH
, (char *)NULL
,
case A_TAGFILE
: /* tag a new file; get the file name */
start_mca(A_TAGFILE
, "Tag: ");
case A_EXAMINE
: /* edit a new file; get the file name */
start_mca(A_EXAMINE
, "Examine: ");
* Invoke an editor on the input file.
error("Cannot edit standard input");
start_mca(A_SETMARK
, "mark: ");
if (c
== erase_char
|| c
== kill_char
)
start_mca(A_GOMARK
, "goto mark: ");
if (c
== erase_char
|| c
== kill_char
)
* The command is incomplete (more chars are needed).
* Display the current char so the user knows
* what's going on and get another character.
start_mca(A_PREFIX
, "& ");
extern char *current_file
;
char buf
[MAXPATHLEN
* 2 + 20], *getenv();
editor
= getenv("EDITOR");
/* pass the line number to vi */
if (editor
== NULL
|| *editor
== '\0') {
#define EDIT_PGM "/usr/ucb/vi"
if (dolinenumber
&& (c
= currline(MIDDLE
)))
(void)sprintf(buf
, "%s +%d %s", editor
, c
, current_file
);
(void)sprintf(buf
, "%s %s", editor
, current_file
);