* 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.9 (Berkeley) %G%";
* User-level command processor.
extern int erase_char
, kill_char
;
extern char *every_first_cmd
;
extern char *current_file
;
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 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.
* 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.
} else if (c
== kill_char
)
/* {{ Could do this faster, but who cares? }} */
} else if (cp
>= &cmdbuf
[sizeof(cmdbuf
)-1])
* No room in the command buffer.
} else if (cmd_col
>= sc_width
-3)
* {{ Could get fancy here; maybe shift the displayed
* line and make room for more chars, like ksh. }}
* Append the character to the string.
* 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
* Display the appropriate prompt.
if (first_cmd
!= NULL
&& *first_cmd
!= '\0')
* No prompt necessary if commands are from first_cmd
* rather than from the user.
* If nothing is displayed yet, display starting from line 1.
if (position(TOP
) == NULL_POSITION
)
* 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
)
* Select the proper prompt and display it.
* The character normally comes from the keyboard,
* but may come from the "first_cmd" string.
* Reached end of first_cmd input.
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.
search(1, cmdbuf
, number
, wsearch
);
search(0, cmdbuf
, number
, wsearch
);
* Skip leading spaces or + signs in the string.
for (p
= cmdbuf
; *p
== '+' || *p
== ' '; p
++)
if (every_first_cmd
!= NULL
)
every_first_cmd
= save(p
);
toggle_option(cmdbuf
, 1);
* Ignore leading spaces in the filename.
for (p
= cmdbuf
; *p
== ' '; p
++)
* Add a character to a multi-character command.
* Not in a multicharacter command.
* In the prefix of a command.
* 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.
* 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
&&
toggle_option(cmdbuf
, 1);
* 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.
* 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
) ? "!/" : "!?");
search(mca
==A_F_SEARCH
, (char *)NULL
, number
, wsearch
);
* Edit a new file. Get the filename.
start_mca(A_EXAMINE
, "Examine: ");
* Invoke an editor on the input file.
error("Cannot edit standard input");
start_mca(A_TOGGLE_OPTION
, "-");
start_mca(A_DISP_OPTION
, "_");
if (c
== erase_char
|| c
== kill_char
)
toggle_option(cmdbuf
, 0);
* Set an initial command for new files.
start_mca(A_FIRSTCMD
, "+");
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
, "& ");
char buf
[MAXPATHLEN
], *getenv();
editor
= getenv("EDITOR");
/* pass the line number to vi */
if (editor
== NULL
|| *editor
== '\0') {
if (dolinenumber
&& (c
= currline(MIDDLE
)))
(void)sprintf(buf
, "%s +%d %s", editor
, c
, current_file
);
(void)sprintf(buf
, "%s %s", editor
, current_file
);