2 * User-level command processor.
14 extern int erase_char, kill_char;
17 extern int quit_at_eof;
22 extern int jump_sline;
26 extern int ignore_eoi;
27 extern char *every_first_cmd;
28 extern char version[];
29 extern struct scrpos initial_scrpos;
30 extern IFILE curr_ifile;
33 extern char *editproto;
35 extern int screen_trashed; /* The screen has been overwritten */
37 static char ungot[100];
38 static char *ungotp = NULL;
40 static char *shellcmd = NULL; /* For holding last shell command for "!!" */
42 static int mca; /* The multicharacter command (action) */
43 static int search_type; /* The previous type of search */
44 static int number; /* The number typed by the user */
51 static void multi_search();
54 * Move the cursor to lower left before executing a command.
55 * This looks nicer if the command takes a long time before
56 * updating the screen.
66 * Set up the display to start a new multi-character command.
69 start_mca(action, prompt)
80 * Set up the display to start a new search command.
85 switch (SRCH_DIR(search_type))
98 if (search_type & SRCH_FIRST_FILE)
101 if (search_type & SRCH_PAST_EOF)
104 if (search_type & SRCH_NOMATCH)
107 switch (SRCH_DIR(search_type))
119 * Execute a multicharacter command.
134 multi_search(cbuf, number);
138 * Skip leading spaces or + signs in the string.
140 while (*cbuf == '+' || *cbuf == ' ')
142 if (every_first_cmd != NULL)
143 free(every_first_cmd);
145 every_first_cmd = NULL;
147 every_first_cmd = save(cbuf);
150 toggle_option(optchar, cbuf, optflag);
154 match_brac(cbuf[0], cbuf[1], 1, number);
157 match_brac(cbuf[1], cbuf[0], 0, number);
161 * Ignore leading spaces and glob the filename.
175 * !! just uses whatever is in shellcmd.
176 * Otherwise, copy cmdbuf to shellcmd,
177 * expanding any special characters ("%" or "#").
181 if (shellcmd != NULL)
183 shellcmd = fexpand(cbuf);
184 if (shellcmd == NULL)
188 if (shellcmd == NULL)
192 error("!done", NULL_PARG);
197 (void) pipe_mark(pipec, cbuf);
198 error("|done", NULL_PARG);
205 * Add a character to a multi-character command.
219 * Not in a multicharacter command.
225 * In the prefix of a command.
226 * This not considered a multichar command
227 * (even tho it uses cmdbuf, etc.).
228 * It is handled in the commands() switch.
234 * Entering digits of a number.
235 * Terminated by a non-digit.
237 if ((c < '0' || c > '9') &&
238 c != erase_char && c != kill_char)
241 * Not part of the number.
242 * Treat as a normal command character.
252 * Special case for the TOGGLE_OPTION command.
253 * If the option letter which was entered is a
254 * single-char option, execute the command immediately,
255 * so user doesn't have to hit RETURN.
256 * If the first char is + or -, this indicates
257 * OPT_UNSET or OPT_SET respectively, instead of OPT_TOGGLE.
259 if (c == erase_char || c == kill_char)
261 if (optchar != '\0' && optchar != '+' && optchar != '-')
263 * We already have the option letter.
276 if (optflag != OPT_TOGGLE || single_char_option(c))
278 toggle_option(c, "", optflag);
283 if (optchar == '+' || optchar == '-')
289 * Display a prompt appropriate for the option letter.
291 if ((p = opt_prompt(c)) == NULL)
298 start_mca(A_OPT_TOGGLE, p);
304 * Special case for search commands.
305 * Certain characters as the first char of
306 * the pattern have special meaning:
307 * ! Toggle the NOMATCH flag
308 * * Toggle the PAST_EOF flag
309 * @ Toggle the FIRST_FILE flag
311 if (len_cmdbuf() > 0)
313 * Only works for the first char of the pattern.
324 flag = SRCH_FIRST_FILE;
327 flag = SRCH_PAST_EOF;
340 * Any other multicharacter command
341 * is terminated by a newline.
343 if (c == '\n' || c == '\r')
346 * Execute the command.
352 * Append the char to the command buffer.
356 * Abort the multi-char command.
360 if ((mca == A_F_BRACKET || mca == A_B_BRACKET) && len_cmdbuf() >= 2)
363 * Special case for the bracket-matching commands.
364 * Execute the command after getting exactly two
365 * characters from the user.
372 * Need another character.
378 * Display the appropriate prompt.
385 if (ungotp != NULL && ungotp > ungot)
388 * No prompt necessary if commands are from
389 * ungotten chars rather than from the user.
395 * If nothing is displayed yet, display starting from initial_scrpos.
399 if (initial_scrpos.pos == NULL_POSITION)
401 * {{ Maybe this should be:
402 * jump_loc(ch_zero(), jump_sline);
403 * but this behavior seems rather unexpected
404 * on the first screen. }}
406 jump_loc(ch_zero(), 1);
408 jump_loc(initial_scrpos.pos, initial_scrpos.ln);
409 } else if (screen_trashed)
413 * If the -E flag is set and we've hit EOF on the last file, quit.
415 if (quit_at_eof == 2 && hit_eof &&
416 next_ifile(curr_ifile) == NULL_IFILE)
420 * Select the proper prompt and display it.
439 * Get command character.
440 * The character normally comes from the keyboard,
441 * but may come from ungotten characters
442 * (characters previously given to ungetcc or ungetsc).
449 * Normal case: no ungotten chars, so get one from the user.
455 * Return the next ungotten char.
460 * We have just run out of ungotten chars.
463 if (len_cmdbuf() == 0 || !empty_screen())
466 * Command is incomplete, so try to complete it.
472 * We have a number but no command. Treat as #g.
479 * We have "/string" but no newline. Add the \n.
485 * Some other incomplete command. Let user complete it.
492 * "Unget" a command character.
493 * The next getcc() will return this character.
501 if (ungotp >= ungot + sizeof(ungot))
503 error("ungetcc overflow", NULL_PARG);
510 * Unget a whole string of command characters.
511 * The next sequence of getcc()'s will return this string.
519 for (p = s + strlen(s) - 1; p >= s; p--)
524 * Search for a pattern, possibly in multiple files.
525 * If SRCH_FIRST_FILE is set, begin searching at the first file.
526 * If SRCH_PAST_EOF is set, continue the search thru multiple files.
529 multi_search(pattern, n)
538 curr_filename = get_filename(curr_ifile);
540 if (search_type & SRCH_FIRST_FILE)
543 * Start at the first (or last) file
544 * in the command line list.
546 if (SRCH_DIR(search_type) == SRCH_FORW)
547 nomore = edit_first();
549 nomore = edit_last();
553 search_type &= ~SRCH_FIRST_FILE;
558 if ((n = search(search_type, pattern, n)) == 0)
566 * Some kind of error in the search.
567 * Error message has been printed by search().
571 if ((search_type & SRCH_PAST_EOF) == 0)
573 * We didn't find a match, but we're
574 * supposed to search only one file.
578 * Move on to the next file.
580 if (SRCH_DIR(search_type) == SRCH_BACK)
581 nomore = edit_prev(1);
583 nomore = edit_next(1);
591 * Print an error message if we haven't already.
594 error("Pattern not found", NULL_PARG);
598 * Restore the file we were originally viewing.
600 (void) edit(curr_filename, 0);
604 * Main command processor.
605 * Accept and execute commands until a quit command.
613 int save_search_type;
618 search_type = SRCH_FORW;
619 scroll = (sc_height + 1) / 2;
628 * See if any signals need processing.
638 * Display prompt and accept a character.
651 * If we are in a multicharacter command, call mca_char.
652 * Otherwise we call cmd_decode to determine the
653 * action to be performed.
660 * Need another character.
666 * Command has been handled by mca_char.
667 * Start clean with a prompt.
672 * Not a multi-char command
673 * (at least, not anymore).
679 * Decode the command character and decide what to do.
684 * We're in a multichar command.
685 * Add the character to the command buffer
686 * and display it on the screen.
687 * If the user backspaces past the start
688 * of the line, abort the command.
690 if (cmd_char(c) || len_cmdbuf() == 0)
696 * Don't use cmd_char if we're starting fresh
697 * at the beginning of a command, because we
698 * don't want to echo the command until we know
699 * it is a multichar command. We also don't
700 * want erase_char/kill_char to be treated
701 * as line editing characters.
708 action = cmd_decode(cbuf, &s);
710 * If an "extra" string was returned,
711 * process it as a string of command characters.
716 * Clear the cmdbuf string.
717 * (But not if we're in the prefix of a command,
718 * because the partial command string is kept there.)
720 if (action != A_PREFIX)
727 * First digit of a number.
729 start_mca(A_DIGIT, ":");
734 * Forward one window (and set the window size).
741 * Forward one screen.
746 forward(number, 0, 1);
751 * Backward one window (and set the window size).
758 * Backward one screen.
763 backward(number, 0, 1);
768 * Forward N (default 1) line.
773 forward(number, 0, 0);
778 * Backward N (default 1) line.
783 backward(number, 0, 0);
788 * Force forward N (default 1) line.
793 forward(number, 1, 0);
798 * Force backward N (default 1) line.
803 backward(number, 1, 0);
808 * Forward forever, ignoring EOF.
822 * (default same as last 'd' or 'u' command).
827 forward(scroll, 0, 0);
833 * (default same as last 'd' or 'u' command).
838 backward(scroll, 0, 0);
843 * Flush buffers, then repaint screen.
844 * Don't flush the buffers on a pipe!
860 * Go to line N, default beginning of file.
870 * Go to a specified percentage into the file.
877 jump_percent(number);
882 * Go to line N, default end of file.
893 * Go to a specified byte position in the file.
898 jump_line_loc((POSITION)number, jump_sline);
903 * Print file name, etc.
906 parg.p_string = eq_message();
912 * Print version number, without the "@(#)".
915 parg.p_string = version+4;
926 * Define abbreviation for a commonly used sequence below.
928 #define DO_SEARCH() if (number <= 0) number = 1; \
931 multi_search((char *)NULL, number);
936 * Search forward for a pattern.
937 * Get the first char of the pattern.
939 search_type = SRCH_FORW;
948 * Search backward for a pattern.
949 * Get the first char of the pattern.
951 search_type = SRCH_BACK;
960 * Repeat previous search.
965 case A_T_AGAIN_SEARCH:
967 * Repeat previous search, multiple files.
969 search_type |= SRCH_PAST_EOF;
973 case A_REVERSE_SEARCH:
975 * Repeat previous search, in reverse direction.
977 save_search_type = search_type;
978 search_type = SRCH_REVERSE(search_type);
980 search_type = save_search_type;
983 case A_T_REVERSE_SEARCH:
985 * Repeat previous search,
986 * multiple files in reverse direction.
988 save_search_type = search_type;
989 search_type = SRCH_REVERSE(search_type);
990 search_type |= SRCH_PAST_EOF;
992 search_type = save_search_type;
1013 * Edit a new file. Get the filename.
1015 start_mca(A_EXAMINE, "Examine: ");
1021 * Invoke an editor on the input file.
1024 if (strcmp(get_filename(curr_ifile), "-") == 0)
1026 error("Cannot edit standard input", NULL_PARG);
1030 * Expand the editor prototype string
1031 * and pass it to the system to execute.
1034 lsystem(pr_expand(editproto, 0));
1036 * Re-edit the file, since data may have changed.
1037 * Some editors even recreate the file, so flushing
1038 * buffers is not sufficient.
1040 (void) edit(get_filename(curr_ifile), 0);
1043 error("Command not available", NULL_PARG);
1049 * Examine next file.
1053 if (edit_next(number))
1055 if (quit_at_eof && hit_eof)
1057 parg.p_string = (number > 1) ? "(N-th) " : "";
1058 error("No %snext file", &parg);
1064 * Examine previous file.
1068 if (edit_prev(number))
1070 parg.p_string = (number > 1) ? "(N-th) " : "";
1071 error("No %sprevious file", &parg);
1077 * Examine a particular file.
1081 if (edit_index(number))
1082 error("No such file", NULL_PARG);
1086 start_mca(A_OPT_TOGGLE, "-");
1087 optflag = OPT_TOGGLE;
1093 * Report a flag setting.
1095 start_mca(A_DISP_OPTION, "_");
1097 if (c == erase_char || c == kill_char)
1099 toggle_option(c, "", OPT_NO_TOGGLE);
1104 * Set an initial command for new files.
1106 start_mca(A_FIRSTCMD, "+");
1115 start_mca(A_SHELL, "!");
1119 error("Command not available", NULL_PARG);
1127 start_mca(A_SETMARK, "mark: ");
1129 if (c == erase_char || c == kill_char ||
1130 c == '\n' || c == '\r')
1139 start_mca(A_GOMARK, "goto mark: ");
1141 if (c == erase_char || c == kill_char ||
1142 c == '\n' || c == '\r')
1149 start_mca(A_PIPE, "|mark: ");
1151 if (c == erase_char || c == kill_char)
1153 if (c == '\n' || c == '\r')
1158 start_mca(A_PIPE, "!");
1165 start_mca(action, "Brackets: ");
1171 * The command is incomplete (more chars are needed).
1172 * Display the current char, so the user knows
1173 * what's going on, and get another character.
1175 if (mca != A_PREFIX)
1177 start_mca(A_PREFIX, " ");