comparison miscellany/less-177/command.c @ 0:bce86c4163a3

Initial revision
author kono
date Mon, 18 Apr 2005 23:46:02 +0900
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:bce86c4163a3
1 /*
2 * User-level command processor.
3 */
4
5 #include "less.h"
6 #include "position.h"
7 #include "option.h"
8 #include "cmd.h"
9
10 #define NO_MCA 0
11 #define MCA_DONE 1
12 #define MCA_MORE 2
13
14 extern int erase_char, kill_char;
15 extern int ispipe;
16 extern int sigs;
17 extern int quit_at_eof;
18 extern int hit_eof;
19 extern int sc_width;
20 extern int sc_height;
21 extern int swindow;
22 extern int jump_sline;
23 extern int quitting;
24 extern int scroll;
25 extern int nohelp;
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;
31 #if EDITOR
32 extern char *editor;
33 extern char *editproto;
34 #endif
35 extern int screen_trashed; /* The screen has been overwritten */
36
37 static char ungot[100];
38 static char *ungotp = NULL;
39 #if SHELL_ESCAPE
40 static char *shellcmd = NULL; /* For holding last shell command for "!!" */
41 #endif
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 */
45 static char optchar;
46 static int optflag;
47 #if PIPEC
48 static char pipec;
49 #endif
50
51 static void multi_search();
52
53 /*
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.
57 */
58 static void
59 cmd_exec()
60 {
61 lower_left();
62 flush();
63 }
64
65 /*
66 * Set up the display to start a new multi-character command.
67 */
68 static void
69 start_mca(action, prompt)
70 int action;
71 char *prompt;
72 {
73 mca = action;
74 lower_left();
75 clear_eol();
76 cmd_putstr(prompt);
77 }
78
79 /*
80 * Set up the display to start a new search command.
81 */
82 static void
83 mca_search()
84 {
85 switch (SRCH_DIR(search_type))
86 {
87 case SRCH_FORW:
88 mca = A_F_SEARCH;
89 break;
90 case SRCH_BACK:
91 mca = A_B_SEARCH;
92 break;
93 }
94
95 lower_left();
96 clear_eol();
97
98 if (search_type & SRCH_FIRST_FILE)
99 cmd_putstr("@");
100
101 if (search_type & SRCH_PAST_EOF)
102 cmd_putstr("*");
103
104 if (search_type & SRCH_NOMATCH)
105 cmd_putstr("!");
106
107 switch (SRCH_DIR(search_type))
108 {
109 case SRCH_FORW:
110 cmd_putstr("/");
111 break;
112 case SRCH_BACK:
113 cmd_putstr("?");
114 break;
115 }
116 }
117
118 /*
119 * Execute a multicharacter command.
120 */
121 static void
122 exec_mca()
123 {
124 register char *cbuf;
125 register char *s;
126
127 cmd_exec();
128 cbuf = get_cmdbuf();
129
130 switch (mca)
131 {
132 case A_F_SEARCH:
133 case A_B_SEARCH:
134 multi_search(cbuf, number);
135 break;
136 case A_FIRSTCMD:
137 /*
138 * Skip leading spaces or + signs in the string.
139 */
140 while (*cbuf == '+' || *cbuf == ' ')
141 cbuf++;
142 if (every_first_cmd != NULL)
143 free(every_first_cmd);
144 if (*cbuf == '\0')
145 every_first_cmd = NULL;
146 else
147 every_first_cmd = save(cbuf);
148 break;
149 case A_OPT_TOGGLE:
150 toggle_option(optchar, cbuf, optflag);
151 optchar = '\0';
152 break;
153 case A_F_BRACKET:
154 match_brac(cbuf[0], cbuf[1], 1, number);
155 break;
156 case A_B_BRACKET:
157 match_brac(cbuf[1], cbuf[0], 0, number);
158 break;
159 case A_EXAMINE:
160 /*
161 * Ignore leading spaces and glob the filename.
162 */
163 cbuf = skipsp(cbuf);
164 s = glob(cbuf);
165 if (s != NULL)
166 {
167 edit_list(s);
168 free(s);
169 } else
170 edit_list(cbuf);
171 break;
172 #if SHELL_ESCAPE
173 case A_SHELL:
174 /*
175 * !! just uses whatever is in shellcmd.
176 * Otherwise, copy cmdbuf to shellcmd,
177 * expanding any special characters ("%" or "#").
178 */
179 if (*cbuf != '!')
180 {
181 if (shellcmd != NULL)
182 free(shellcmd);
183 shellcmd = fexpand(cbuf);
184 if (shellcmd == NULL)
185 break;
186 }
187
188 if (shellcmd == NULL)
189 lsystem("");
190 else
191 lsystem(shellcmd);
192 error("!done", NULL_PARG);
193 break;
194 #endif
195 #if PIPEC
196 case A_PIPE:
197 (void) pipe_mark(pipec, cbuf);
198 error("|done", NULL_PARG);
199 break;
200 #endif
201 }
202 }
203
204 /*
205 * Add a character to a multi-character command.
206 */
207 static int
208 mca_char(c)
209 int c;
210 {
211 char *p;
212 int flag;
213 char buf[3];
214
215 switch (mca)
216 {
217 case 0:
218 /*
219 * Not in a multicharacter command.
220 */
221 return (NO_MCA);
222
223 case A_PREFIX:
224 /*
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.
229 */
230 return (NO_MCA);
231
232 case A_DIGIT:
233 /*
234 * Entering digits of a number.
235 * Terminated by a non-digit.
236 */
237 if ((c < '0' || c > '9') &&
238 c != erase_char && c != kill_char)
239 {
240 /*
241 * Not part of the number.
242 * Treat as a normal command character.
243 */
244 number = cmd_int();
245 mca = 0;
246 return (NO_MCA);
247 }
248 break;
249
250 case A_OPT_TOGGLE:
251 /*
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.
258 */
259 if (c == erase_char || c == kill_char)
260 break;
261 if (optchar != '\0' && optchar != '+' && optchar != '-')
262 /*
263 * We already have the option letter.
264 */
265 break;
266 switch (c)
267 {
268 case '+':
269 optflag = OPT_UNSET;
270 break;
271 case '-':
272 optflag = OPT_SET;
273 break;
274 default:
275 optchar = c;
276 if (optflag != OPT_TOGGLE || single_char_option(c))
277 {
278 toggle_option(c, "", optflag);
279 return (MCA_DONE);
280 }
281 break;
282 }
283 if (optchar == '+' || optchar == '-')
284 {
285 optchar = c;
286 break;
287 }
288 /*
289 * Display a prompt appropriate for the option letter.
290 */
291 if ((p = opt_prompt(c)) == NULL)
292 {
293 buf[0] = '-';
294 buf[1] = c;
295 buf[2] = '\0';
296 p = buf;
297 }
298 start_mca(A_OPT_TOGGLE, p);
299 return (MCA_MORE);
300
301 case A_F_SEARCH:
302 case A_B_SEARCH:
303 /*
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
310 */
311 if (len_cmdbuf() > 0)
312 /*
313 * Only works for the first char of the pattern.
314 */
315 break;
316
317 flag = 0;
318 switch (c)
319 {
320 case '!':
321 flag = SRCH_NOMATCH;
322 break;
323 case '@':
324 flag = SRCH_FIRST_FILE;
325 break;
326 case '*':
327 flag = SRCH_PAST_EOF;
328 break;
329 }
330 if (flag != 0)
331 {
332 search_type ^= flag;
333 mca_search();
334 return (MCA_MORE);
335 }
336 break;
337 }
338
339 /*
340 * Any other multicharacter command
341 * is terminated by a newline.
342 */
343 if (c == '\n' || c == '\r')
344 {
345 /*
346 * Execute the command.
347 */
348 exec_mca();
349 return (MCA_DONE);
350 }
351 /*
352 * Append the char to the command buffer.
353 */
354 if (cmd_char(c))
355 /*
356 * Abort the multi-char command.
357 */
358 return (MCA_DONE);
359
360 if ((mca == A_F_BRACKET || mca == A_B_BRACKET) && len_cmdbuf() >= 2)
361 {
362 /*
363 * Special case for the bracket-matching commands.
364 * Execute the command after getting exactly two
365 * characters from the user.
366 */
367 exec_mca();
368 return (MCA_DONE);
369 }
370
371 /*
372 * Need another character.
373 */
374 return (MCA_MORE);
375 }
376
377 /*
378 * Display the appropriate prompt.
379 */
380 static void
381 prompt()
382 {
383 register char *p;
384
385 if (ungotp != NULL && ungotp > ungot)
386 {
387 /*
388 * No prompt necessary if commands are from
389 * ungotten chars rather than from the user.
390 */
391 return;
392 }
393
394 /*
395 * If nothing is displayed yet, display starting from initial_scrpos.
396 */
397 if (empty_screen())
398 {
399 if (initial_scrpos.pos == NULL_POSITION)
400 /*
401 * {{ Maybe this should be:
402 * jump_loc(ch_zero(), jump_sline);
403 * but this behavior seems rather unexpected
404 * on the first screen. }}
405 */
406 jump_loc(ch_zero(), 1);
407 else
408 jump_loc(initial_scrpos.pos, initial_scrpos.ln);
409 } else if (screen_trashed)
410 repaint();
411
412 /*
413 * If the -E flag is set and we've hit EOF on the last file, quit.
414 */
415 if (quit_at_eof == 2 && hit_eof &&
416 next_ifile(curr_ifile) == NULL_IFILE)
417 quit(0);
418
419 /*
420 * Select the proper prompt and display it.
421 */
422 lower_left();
423 clear_eol();
424 p = pr_string();
425 if (p == NULL)
426 putchr(':');
427 else
428 {
429 so_enter();
430 putstr(p);
431 so_exit();
432 }
433 #if __MSDOS__
434 scroll_bar();
435 #endif
436 }
437
438 /*
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).
443 */
444 static int
445 getcc()
446 {
447 if (ungotp == NULL)
448 /*
449 * Normal case: no ungotten chars, so get one from the user.
450 */
451 return (getchr());
452
453 if (ungotp > ungot)
454 /*
455 * Return the next ungotten char.
456 */
457 return (*--ungotp);
458
459 /*
460 * We have just run out of ungotten chars.
461 */
462 ungotp = NULL;
463 if (len_cmdbuf() == 0 || !empty_screen())
464 return (getchr());
465 /*
466 * Command is incomplete, so try to complete it.
467 */
468 switch (mca)
469 {
470 case A_DIGIT:
471 /*
472 * We have a number but no command. Treat as #g.
473 */
474 return ('g');
475
476 case A_F_SEARCH:
477 case A_B_SEARCH:
478 /*
479 * We have "/string" but no newline. Add the \n.
480 */
481 return ('\n');
482
483 default:
484 /*
485 * Some other incomplete command. Let user complete it.
486 */
487 return (getchr());
488 }
489 }
490
491 /*
492 * "Unget" a command character.
493 * The next getcc() will return this character.
494 */
495 public void
496 ungetcc(c)
497 int c;
498 {
499 if (ungotp == NULL)
500 ungotp = ungot;
501 if (ungotp >= ungot + sizeof(ungot))
502 {
503 error("ungetcc overflow", NULL_PARG);
504 quit(1);
505 }
506 *ungotp++ = c;
507 }
508
509 /*
510 * Unget a whole string of command characters.
511 * The next sequence of getcc()'s will return this string.
512 */
513 public void
514 ungetsc(s)
515 char *s;
516 {
517 register char *p;
518
519 for (p = s + strlen(s) - 1; p >= s; p--)
520 ungetcc(*p);
521 }
522
523 /*
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.
527 */
528 static void
529 multi_search(pattern, n)
530 char *pattern;
531 int n;
532 {
533 register int nomore;
534 char *curr_filename;
535 int changed_file;
536
537 changed_file = 0;
538 curr_filename = get_filename(curr_ifile);
539
540 if (search_type & SRCH_FIRST_FILE)
541 {
542 /*
543 * Start at the first (or last) file
544 * in the command line list.
545 */
546 if (SRCH_DIR(search_type) == SRCH_FORW)
547 nomore = edit_first();
548 else
549 nomore = edit_last();
550 if (nomore)
551 return;
552 changed_file = 1;
553 search_type &= ~SRCH_FIRST_FILE;
554 }
555
556 for (;;)
557 {
558 if ((n = search(search_type, pattern, n)) == 0)
559 /*
560 * Found it.
561 */
562 return;
563
564 if (n < 0)
565 /*
566 * Some kind of error in the search.
567 * Error message has been printed by search().
568 */
569 break;
570
571 if ((search_type & SRCH_PAST_EOF) == 0)
572 /*
573 * We didn't find a match, but we're
574 * supposed to search only one file.
575 */
576 break;
577 /*
578 * Move on to the next file.
579 */
580 if (SRCH_DIR(search_type) == SRCH_BACK)
581 nomore = edit_prev(1);
582 else
583 nomore = edit_next(1);
584 if (nomore)
585 break;
586 changed_file = 1;
587 }
588
589 /*
590 * Didn't find it.
591 * Print an error message if we haven't already.
592 */
593 if (n > 0)
594 error("Pattern not found", NULL_PARG);
595
596 if (changed_file)
597 /*
598 * Restore the file we were originally viewing.
599 */
600 (void) edit(curr_filename, 0);
601 }
602
603 /*
604 * Main command processor.
605 * Accept and execute commands until a quit command.
606 */
607 public void
608 commands()
609 {
610 register int c;
611 register int action;
612 register char *cbuf;
613 int save_search_type;
614 char *s;
615 char tbuf[2];
616 PARG parg;
617
618 search_type = SRCH_FORW;
619 scroll = (sc_height + 1) / 2;
620
621 for (;;)
622 {
623 mca = 0;
624 number = 0;
625 optchar = '\0';
626
627 /*
628 * See if any signals need processing.
629 */
630 if (sigs)
631 {
632 psignals();
633 if (quitting)
634 quit(-1);
635 }
636
637 /*
638 * Display prompt and accept a character.
639 */
640 cmd_reset();
641 prompt();
642 if (sigs)
643 continue;
644 c = getcc();
645
646 again:
647 if (sigs)
648 continue;
649
650 /*
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.
654 */
655 if (mca)
656 switch (mca_char(c))
657 {
658 case MCA_MORE:
659 /*
660 * Need another character.
661 */
662 c = getcc();
663 goto again;
664 case MCA_DONE:
665 /*
666 * Command has been handled by mca_char.
667 * Start clean with a prompt.
668 */
669 continue;
670 case NO_MCA:
671 /*
672 * Not a multi-char command
673 * (at least, not anymore).
674 */
675 break;
676 }
677
678 /*
679 * Decode the command character and decide what to do.
680 */
681 if (mca)
682 {
683 /*
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.
689 */
690 if (cmd_char(c) || len_cmdbuf() == 0)
691 continue;
692 cbuf = get_cmdbuf();
693 } else
694 {
695 /*
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.
702 */
703 tbuf[0] = c;
704 tbuf[1] = '\0';
705 cbuf = tbuf;
706 }
707 s = NULL;
708 action = cmd_decode(cbuf, &s);
709 /*
710 * If an "extra" string was returned,
711 * process it as a string of command characters.
712 */
713 if (s != NULL)
714 ungetsc(s);
715 /*
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.)
719 */
720 if (action != A_PREFIX)
721 cmd_reset();
722
723 switch (action)
724 {
725 case A_DIGIT:
726 /*
727 * First digit of a number.
728 */
729 start_mca(A_DIGIT, ":");
730 goto again;
731
732 case A_F_WINDOW:
733 /*
734 * Forward one window (and set the window size).
735 */
736 if (number > 0)
737 swindow = number;
738 /* FALLTHRU */
739 case A_F_SCREEN:
740 /*
741 * Forward one screen.
742 */
743 if (number <= 0)
744 number = swindow;
745 cmd_exec();
746 forward(number, 0, 1);
747 break;
748
749 case A_B_WINDOW:
750 /*
751 * Backward one window (and set the window size).
752 */
753 if (number > 0)
754 swindow = number;
755 /* FALLTHRU */
756 case A_B_SCREEN:
757 /*
758 * Backward one screen.
759 */
760 if (number <= 0)
761 number = swindow;
762 cmd_exec();
763 backward(number, 0, 1);
764 break;
765
766 case A_F_LINE:
767 /*
768 * Forward N (default 1) line.
769 */
770 if (number <= 0)
771 number = 1;
772 cmd_exec();
773 forward(number, 0, 0);
774 break;
775
776 case A_B_LINE:
777 /*
778 * Backward N (default 1) line.
779 */
780 if (number <= 0)
781 number = 1;
782 cmd_exec();
783 backward(number, 0, 0);
784 break;
785
786 case A_FF_LINE:
787 /*
788 * Force forward N (default 1) line.
789 */
790 if (number <= 0)
791 number = 1;
792 cmd_exec();
793 forward(number, 1, 0);
794 break;
795
796 case A_BF_LINE:
797 /*
798 * Force backward N (default 1) line.
799 */
800 if (number <= 0)
801 number = 1;
802 cmd_exec();
803 backward(number, 1, 0);
804 break;
805
806 case A_F_FOREVER:
807 /*
808 * Forward forever, ignoring EOF.
809 */
810 cmd_exec();
811 jump_forw();
812 ignore_eoi = 1;
813 hit_eof = 0;
814 while (sigs == 0)
815 forward(1, 0, 0);
816 ignore_eoi = 0;
817 break;
818
819 case A_F_SCROLL:
820 /*
821 * Forward N lines
822 * (default same as last 'd' or 'u' command).
823 */
824 if (number > 0)
825 scroll = number;
826 cmd_exec();
827 forward(scroll, 0, 0);
828 break;
829
830 case A_B_SCROLL:
831 /*
832 * Forward N lines
833 * (default same as last 'd' or 'u' command).
834 */
835 if (number > 0)
836 scroll = number;
837 cmd_exec();
838 backward(scroll, 0, 0);
839 break;
840
841 case A_FREPAINT:
842 /*
843 * Flush buffers, then repaint screen.
844 * Don't flush the buffers on a pipe!
845 */
846 ch_flush();
847 if (!ispipe)
848 clr_linenum();
849 /* FALLTHRU */
850 case A_REPAINT:
851 /*
852 * Repaint screen.
853 */
854 cmd_exec();
855 repaint();
856 break;
857
858 case A_GOLINE:
859 /*
860 * Go to line N, default beginning of file.
861 */
862 if (number <= 0)
863 number = 1;
864 cmd_exec();
865 jump_back(number);
866 break;
867
868 case A_PERCENT:
869 /*
870 * Go to a specified percentage into the file.
871 */
872 if (number < 0)
873 number = 0;
874 if (number > 100)
875 number = 100;
876 cmd_exec();
877 jump_percent(number);
878 break;
879
880 case A_GOEND:
881 /*
882 * Go to line N, default end of file.
883 */
884 cmd_exec();
885 if (number <= 0)
886 jump_forw();
887 else
888 jump_back(number);
889 break;
890
891 case A_GOPOS:
892 /*
893 * Go to a specified byte position in the file.
894 */
895 cmd_exec();
896 if (number < 0)
897 number = 0;
898 jump_line_loc((POSITION)number, jump_sline);
899 break;
900
901 case A_STAT:
902 /*
903 * Print file name, etc.
904 */
905 cmd_exec();
906 parg.p_string = eq_message();
907 error("%s", &parg);
908 break;
909
910 case A_VERSION:
911 /*
912 * Print version number, without the "@(#)".
913 */
914 cmd_exec();
915 parg.p_string = version+4;
916 error("%s", &parg);
917 break;
918
919 case A_QUIT:
920 /*
921 * Exit.
922 */
923 quit(0);
924
925 /*
926 * Define abbreviation for a commonly used sequence below.
927 */
928 #define DO_SEARCH() if (number <= 0) number = 1; \
929 mca_search(); \
930 cmd_exec(); \
931 multi_search((char *)NULL, number);
932
933
934 case A_F_SEARCH:
935 /*
936 * Search forward for a pattern.
937 * Get the first char of the pattern.
938 */
939 search_type = SRCH_FORW;
940 if (number <= 0)
941 number = 1;
942 mca_search();
943 c = getcc();
944 goto again;
945
946 case A_B_SEARCH:
947 /*
948 * Search backward for a pattern.
949 * Get the first char of the pattern.
950 */
951 search_type = SRCH_BACK;
952 if (number <= 0)
953 number = 1;
954 mca_search();
955 c = getcc();
956 goto again;
957
958 case A_AGAIN_SEARCH:
959 /*
960 * Repeat previous search.
961 */
962 DO_SEARCH();
963 break;
964
965 case A_T_AGAIN_SEARCH:
966 /*
967 * Repeat previous search, multiple files.
968 */
969 search_type |= SRCH_PAST_EOF;
970 DO_SEARCH();
971 break;
972
973 case A_REVERSE_SEARCH:
974 /*
975 * Repeat previous search, in reverse direction.
976 */
977 save_search_type = search_type;
978 search_type = SRCH_REVERSE(search_type);
979 DO_SEARCH();
980 search_type = save_search_type;
981 break;
982
983 case A_T_REVERSE_SEARCH:
984 /*
985 * Repeat previous search,
986 * multiple files in reverse direction.
987 */
988 save_search_type = search_type;
989 search_type = SRCH_REVERSE(search_type);
990 search_type |= SRCH_PAST_EOF;
991 DO_SEARCH();
992 search_type = save_search_type;
993 break;
994
995 case A_HELP:
996 /*
997 * Help.
998 */
999 if (nohelp)
1000 {
1001 bell();
1002 break;
1003 }
1004 lower_left();
1005 clear_eol();
1006 putstr("help");
1007 cmd_exec();
1008 help();
1009 break;
1010
1011 case A_EXAMINE:
1012 /*
1013 * Edit a new file. Get the filename.
1014 */
1015 start_mca(A_EXAMINE, "Examine: ");
1016 c = getcc();
1017 goto again;
1018
1019 case A_VISUAL:
1020 /*
1021 * Invoke an editor on the input file.
1022 */
1023 #if EDITOR
1024 if (strcmp(get_filename(curr_ifile), "-") == 0)
1025 {
1026 error("Cannot edit standard input", NULL_PARG);
1027 break;
1028 }
1029 /*
1030 * Expand the editor prototype string
1031 * and pass it to the system to execute.
1032 */
1033 cmd_exec();
1034 lsystem(pr_expand(editproto, 0));
1035 /*
1036 * Re-edit the file, since data may have changed.
1037 * Some editors even recreate the file, so flushing
1038 * buffers is not sufficient.
1039 */
1040 (void) edit(get_filename(curr_ifile), 0);
1041 break;
1042 #else
1043 error("Command not available", NULL_PARG);
1044 break;
1045 #endif
1046
1047 case A_NEXT_FILE:
1048 /*
1049 * Examine next file.
1050 */
1051 if (number <= 0)
1052 number = 1;
1053 if (edit_next(number))
1054 {
1055 if (quit_at_eof && hit_eof)
1056 quit(0);
1057 parg.p_string = (number > 1) ? "(N-th) " : "";
1058 error("No %snext file", &parg);
1059 }
1060 break;
1061
1062 case A_PREV_FILE:
1063 /*
1064 * Examine previous file.
1065 */
1066 if (number <= 0)
1067 number = 1;
1068 if (edit_prev(number))
1069 {
1070 parg.p_string = (number > 1) ? "(N-th) " : "";
1071 error("No %sprevious file", &parg);
1072 }
1073 break;
1074
1075 case A_INDEX_FILE:
1076 /*
1077 * Examine a particular file.
1078 */
1079 if (number <= 0)
1080 number = 1;
1081 if (edit_index(number))
1082 error("No such file", NULL_PARG);
1083 break;
1084
1085 case A_OPT_TOGGLE:
1086 start_mca(A_OPT_TOGGLE, "-");
1087 optflag = OPT_TOGGLE;
1088 c = getcc();
1089 goto again;
1090
1091 case A_DISP_OPTION:
1092 /*
1093 * Report a flag setting.
1094 */
1095 start_mca(A_DISP_OPTION, "_");
1096 c = getcc();
1097 if (c == erase_char || c == kill_char)
1098 break;
1099 toggle_option(c, "", OPT_NO_TOGGLE);
1100 break;
1101
1102 case A_FIRSTCMD:
1103 /*
1104 * Set an initial command for new files.
1105 */
1106 start_mca(A_FIRSTCMD, "+");
1107 c = getcc();
1108 goto again;
1109
1110 case A_SHELL:
1111 /*
1112 * Shell escape.
1113 */
1114 #if SHELL_ESCAPE
1115 start_mca(A_SHELL, "!");
1116 c = getcc();
1117 goto again;
1118 #else
1119 error("Command not available", NULL_PARG);
1120 break;
1121 #endif
1122
1123 case A_SETMARK:
1124 /*
1125 * Set a mark.
1126 */
1127 start_mca(A_SETMARK, "mark: ");
1128 c = getcc();
1129 if (c == erase_char || c == kill_char ||
1130 c == '\n' || c == '\r')
1131 break;
1132 setmark(c);
1133 break;
1134
1135 case A_GOMARK:
1136 /*
1137 * Go to a mark.
1138 */
1139 start_mca(A_GOMARK, "goto mark: ");
1140 c = getcc();
1141 if (c == erase_char || c == kill_char ||
1142 c == '\n' || c == '\r')
1143 break;
1144 gomark(c);
1145 break;
1146
1147 #if PIPEC
1148 case A_PIPE:
1149 start_mca(A_PIPE, "|mark: ");
1150 c = getcc();
1151 if (c == erase_char || c == kill_char)
1152 break;
1153 if (c == '\n' || c == '\r')
1154 c = '.';
1155 if (badmark(c))
1156 break;
1157 pipec = c;
1158 start_mca(A_PIPE, "!");
1159 c = getcc();
1160 goto again;
1161 #endif
1162
1163 case A_B_BRACKET:
1164 case A_F_BRACKET:
1165 start_mca(action, "Brackets: ");
1166 c = getcc();
1167 goto again;
1168
1169 case A_PREFIX:
1170 /*
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.
1174 */
1175 if (mca != A_PREFIX)
1176 {
1177 start_mca(A_PREFIX, " ");
1178 cmd_reset();
1179 (void) cmd_char(c);
1180 }
1181 c = getcc();
1182 goto again;
1183
1184 case A_NOACTION:
1185 break;
1186
1187 default:
1188 bell();
1189 break;
1190 }
1191 }
1192 }