Added all of the MH sources, including RCS files, in
[mmh] / docs / historical / mh-6.8.5 / miscellany / less-177 / command.c
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 }