]>
diplodocus.org Git - nmh/blob - docs/historical/mh-6.8.5/miscellany/less-177/command.c
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
, " ");