upgrade to 466 version
[platform/upstream/less.git] / command.c
1 /*
2  * Copyright (C) 1984-2014  Mark Nudelman
3  *
4  * You may distribute under the terms of either the GNU General Public
5  * License or the Less License, as specified in the README file.
6  *
7  * For more information, see the README file.
8  */
9
10
11 /*
12  * User-level command processor.
13  */
14
15 #include "less.h"
16 #if MSDOS_COMPILER==WIN32C
17 #include <windows.h>
18 #endif
19 #include "position.h"
20 #include "option.h"
21 #include "cmd.h"
22
23 extern int erase_char, erase2_char, kill_char;
24 extern int sigs;
25 extern int quit_if_one_screen;
26 extern int squished;
27 extern int sc_width;
28 extern int sc_height;
29 extern int swindow;
30 extern int jump_sline;
31 extern int quitting;
32 extern int wscroll;
33 extern int top_scroll;
34 extern int ignore_eoi;
35 extern int secure;
36 extern int hshift;
37 extern int bs_mode;
38 extern int show_attn;
39 extern POSITION highest_hilite;
40 extern char *every_first_cmd;
41 extern char *curr_altfilename;
42 extern char version[];
43 extern struct scrpos initial_scrpos;
44 extern IFILE curr_ifile;
45 extern void constant *ml_search;
46 extern void constant *ml_examine;
47 #if SHELL_ESCAPE || PIPEC
48 extern void constant *ml_shell;
49 #endif
50 #if EDITOR
51 extern char *editor;
52 extern char *editproto;
53 #endif
54 extern int screen_trashed;      /* The screen has been overwritten */
55 extern int shift_count;
56 extern int oldbot;
57 extern int forw_prompt;
58 extern int same_pos_bell;
59
60 #if SHELL_ESCAPE
61 static char *shellcmd = NULL;   /* For holding last shell command for "!!" */
62 #endif
63 static int mca;                 /* The multicharacter command (action) */
64 static int search_type;         /* The previous type of search */
65 static LINENUM number;          /* The number typed by the user */
66 static long fraction;           /* The fractional part of the number */
67 static struct loption *curropt;
68 static int opt_lower;
69 static int optflag;
70 static int optgetname;
71 static POSITION bottompos;
72 static int save_hshift;
73 static int save_bs_mode;
74 #if PIPEC
75 static char pipec;
76 #endif
77
78 struct ungot {
79         struct ungot *ug_next;
80         char ug_char;
81 };
82 static struct ungot* ungot = NULL;
83 static int unget_end = 0;
84
85 static void multi_search();
86
87 /*
88  * Move the cursor to start of prompt line before executing a command.
89  * This looks nicer if the command takes a long time before
90  * updating the screen.
91  */
92         static void
93 cmd_exec()
94 {
95 #if HILITE_SEARCH
96         clear_attn();
97 #endif
98         clear_bot();
99         flush();
100 }
101
102 /*
103  * Set up the display to start a new multi-character command.
104  */
105         static void
106 start_mca(action, prompt, mlist, cmdflags)
107         int action;
108         constant char *prompt;
109         constant void *mlist;
110         int cmdflags;
111 {
112         mca = action;
113         clear_bot();
114         clear_cmd();
115         cmd_putstr(prompt);
116         set_mlist(mlist, cmdflags);
117 }
118
119         public int
120 in_mca()
121 {
122         return (mca != 0 && mca != A_PREFIX);
123 }
124
125 /*
126  * Set up the display to start a new search command.
127  */
128         static void
129 mca_search()
130 {
131 #if HILITE_SEARCH
132         if (search_type & SRCH_FILTER)
133                 mca = A_FILTER;
134         else 
135 #endif
136         if (search_type & SRCH_FORW)
137                 mca = A_F_SEARCH;
138         else
139                 mca = A_B_SEARCH;
140
141         clear_bot();
142         clear_cmd();
143
144         if (search_type & SRCH_NO_MATCH)
145                 cmd_putstr("Non-match ");
146         if (search_type & SRCH_FIRST_FILE)
147                 cmd_putstr("First-file ");
148         if (search_type & SRCH_PAST_EOF)
149                 cmd_putstr("EOF-ignore ");
150         if (search_type & SRCH_NO_MOVE)
151                 cmd_putstr("Keep-pos ");
152         if (search_type & SRCH_NO_REGEX)
153                 cmd_putstr("Regex-off ");
154
155 #if HILITE_SEARCH
156         if (search_type & SRCH_FILTER)
157                 cmd_putstr("&/");
158         else 
159 #endif
160         if (search_type & SRCH_FORW)
161                 cmd_putstr("/");
162         else
163                 cmd_putstr("?");
164         set_mlist(ml_search, 0);
165 }
166
167 /*
168  * Set up the display to start a new toggle-option command.
169  */
170         static void
171 mca_opt_toggle()
172 {
173         int no_prompt;
174         int flag;
175         char *dash;
176         
177         no_prompt = (optflag & OPT_NO_PROMPT);
178         flag = (optflag & ~OPT_NO_PROMPT);
179         dash = (flag == OPT_NO_TOGGLE) ? "_" : "-";
180
181         mca = A_OPT_TOGGLE;
182         clear_bot();
183         clear_cmd();
184         cmd_putstr(dash);
185         if (optgetname)
186                 cmd_putstr(dash);
187         if (no_prompt)
188                 cmd_putstr("(P)");
189         switch (flag)
190         {
191         case OPT_UNSET:
192                 cmd_putstr("+");
193                 break;
194         case OPT_SET:
195                 cmd_putstr("!");
196                 break;
197         }
198         set_mlist(NULL, 0);
199 }
200
201 /*
202  * Execute a multicharacter command.
203  */
204         static void
205 exec_mca()
206 {
207         register char *cbuf;
208
209         cmd_exec();
210         cbuf = get_cmdbuf();
211
212         switch (mca)
213         {
214         case A_F_SEARCH:
215         case A_B_SEARCH:
216                 multi_search(cbuf, (int) number, 0);
217                 break;
218 #if HILITE_SEARCH
219         case A_FILTER:
220                 search_type ^= SRCH_NO_MATCH;
221                 set_filter_pattern(cbuf, search_type);
222                 break;
223 #endif
224         case A_FIRSTCMD:
225                 /*
226                  * Skip leading spaces or + signs in the string.
227                  */
228                 while (*cbuf == '+' || *cbuf == ' ')
229                         cbuf++;
230                 if (every_first_cmd != NULL)
231                         free(every_first_cmd);
232                 if (*cbuf == '\0')
233                         every_first_cmd = NULL;
234                 else
235                         every_first_cmd = save(cbuf);
236                 break;
237         case A_OPT_TOGGLE:
238                 toggle_option(curropt, opt_lower, cbuf, optflag);
239                 curropt = NULL;
240                 break;
241         case A_F_BRACKET:
242                 match_brac(cbuf[0], cbuf[1], 1, (int) number);
243                 break;
244         case A_B_BRACKET:
245                 match_brac(cbuf[1], cbuf[0], 0, (int) number);
246                 break;
247 #if EXAMINE
248         case A_EXAMINE:
249                 if (secure)
250                         break;
251                 edit_list(cbuf);
252 #if TAGS
253                 /* If tag structure is loaded then clean it up. */
254                 cleantags();
255 #endif
256                 break;
257 #endif
258 #if SHELL_ESCAPE
259         case A_SHELL:
260                 /*
261                  * !! just uses whatever is in shellcmd.
262                  * Otherwise, copy cmdbuf to shellcmd,
263                  * expanding any special characters ("%" or "#").
264                  */
265                 if (*cbuf != '!')
266                 {
267                         if (shellcmd != NULL)
268                                 free(shellcmd);
269                         shellcmd = fexpand(cbuf);
270                 }
271
272                 if (secure)
273                         break;
274                 if (shellcmd == NULL)
275                         lsystem("", "!done");
276                 else
277                         lsystem(shellcmd, "!done");
278                 break;
279 #endif
280 #if PIPEC
281         case A_PIPE:
282                 if (secure)
283                         break;
284                 (void) pipe_mark(pipec, cbuf);
285                 error("|done", NULL_PARG);
286                 break;
287 #endif
288         }
289 }
290
291 /*
292  * Is a character an erase or kill char?
293  */
294         static int
295 is_erase_char(c)
296         int c;
297 {
298         return (c == erase_char || c == erase2_char || c == kill_char);
299 }
300
301 /*
302  * Handle the first char of an option (after the initial dash).
303  */
304         static int
305 mca_opt_first_char(c)
306     int c;
307 {
308         int flag = (optflag & ~OPT_NO_PROMPT);
309         if (flag == OPT_NO_TOGGLE)
310         {
311                 switch (c)
312                 {
313                 case '_':
314                         /* "__" = long option name. */
315                         optgetname = TRUE;
316                         mca_opt_toggle();
317                         return (MCA_MORE);
318                 }
319         } else
320         {
321                 switch (c)
322                 {
323                 case '+':
324                         /* "-+" = UNSET. */
325                         optflag = (flag == OPT_UNSET) ?
326                                 OPT_TOGGLE : OPT_UNSET;
327                         mca_opt_toggle();
328                         return (MCA_MORE);
329                 case '!':
330                         /* "-!" = SET */
331                         optflag = (flag == OPT_SET) ?
332                                 OPT_TOGGLE : OPT_SET;
333                         mca_opt_toggle();
334                         return (MCA_MORE);
335                 case CONTROL('P'):
336                         optflag ^= OPT_NO_PROMPT;
337                         mca_opt_toggle();
338                         return (MCA_MORE);
339                 case '-':
340                         /* "--" = long option name. */
341                         optgetname = TRUE;
342                         mca_opt_toggle();
343                         return (MCA_MORE);
344                 }
345         }
346         /* Char was not handled here. */
347         return (NO_MCA);
348 }
349
350 /*
351  * Add a char to a long option name.
352  * See if we've got a match for an option name yet.
353  * If so, display the complete name and stop 
354  * accepting chars until user hits RETURN.
355  */
356         static int
357 mca_opt_nonfirst_char(c)
358         int c;
359 {
360         char *p;
361         char *oname;
362
363         if (curropt != NULL)
364         {
365                 /*
366                  * Already have a match for the name.
367                  * Don't accept anything but erase/kill.
368                  */
369                 if (is_erase_char(c))
370                         return (MCA_DONE);
371                 return (MCA_MORE);
372         }
373         /*
374          * Add char to cmd buffer and try to match
375          * the option name.
376          */
377         if (cmd_char(c) == CC_QUIT)
378                 return (MCA_DONE);
379         p = get_cmdbuf();
380         opt_lower = ASCII_IS_LOWER(p[0]);
381         curropt = findopt_name(&p, &oname, NULL);
382         if (curropt != NULL)
383         {
384                 /*
385                  * Got a match.
386                  * Remember the option and
387                  * display the full option name.
388                  */
389                 cmd_reset();
390                 mca_opt_toggle();
391                 for (p = oname;  *p != '\0';  p++)
392                 {
393                         c = *p;
394                         if (!opt_lower && ASCII_IS_LOWER(c))
395                                 c = ASCII_TO_UPPER(c);
396                         if (cmd_char(c) != CC_OK)
397                                 return (MCA_DONE);
398                 }
399         }
400         return (MCA_MORE);
401 }
402
403 /*
404  * Handle a char of an option toggle command.
405  */
406         static int
407 mca_opt_char(c)
408         int c;
409 {
410         PARG parg;
411
412         /*
413          * This may be a short option (single char),
414          * or one char of a long option name,
415          * or one char of the option parameter.
416          */
417         if (curropt == NULL && len_cmdbuf() == 0)
418         {
419                 int ret = mca_opt_first_char(c);
420                 if (ret != NO_MCA)
421                         return (ret);
422         }
423         if (optgetname)
424         {
425                 /* We're getting a long option name.  */
426                 if (c != '\n' && c != '\r')
427                         return (mca_opt_nonfirst_char(c));
428                 if (curropt == NULL)
429                 {
430                         parg.p_string = get_cmdbuf();
431                         error("There is no --%s option", &parg);
432                         return (MCA_DONE);
433                 }
434                 optgetname = FALSE;
435                 cmd_reset();
436         } else
437         {
438                 if (is_erase_char(c))
439                         return (NO_MCA);
440                 if (curropt != NULL)
441                         /* We're getting the option parameter. */
442                         return (NO_MCA);
443                 curropt = findopt(c);
444                 if (curropt == NULL)
445                 {
446                         parg.p_string = propt(c);
447                         error("There is no %s option", &parg);
448                         return (MCA_DONE);
449                 }
450         }
451         /*
452          * If the option which was entered does not take a 
453          * parameter, toggle the option immediately,
454          * so user doesn't have to hit RETURN.
455          */
456         if ((optflag & ~OPT_NO_PROMPT) != OPT_TOGGLE ||
457             !opt_has_param(curropt))
458         {
459                 toggle_option(curropt, ASCII_IS_LOWER(c), "", optflag);
460                 return (MCA_DONE);
461         }
462         /*
463          * Display a prompt appropriate for the option parameter.
464          */
465         start_mca(A_OPT_TOGGLE, opt_prompt(curropt), (void*)NULL, 0);
466         return (MCA_MORE);
467 }
468
469 /*
470  * Handle a char of a search command.
471  */
472         static int
473 mca_search_char(c)
474         int c;
475 {
476         int flag = 0;
477
478         /*
479          * Certain characters as the first char of 
480          * the pattern have special meaning:
481          *      !  Toggle the NO_MATCH flag
482          *      *  Toggle the PAST_EOF flag
483          *      @  Toggle the FIRST_FILE flag
484          */
485         if (len_cmdbuf() > 0)
486                 return (NO_MCA);
487
488         switch (c)
489         {
490         case CONTROL('E'): /* ignore END of file */
491         case '*':
492                 if (mca != A_FILTER)
493                         flag = SRCH_PAST_EOF;
494                 break;
495         case CONTROL('F'): /* FIRST file */
496         case '@':
497                 if (mca != A_FILTER)
498                         flag = SRCH_FIRST_FILE;
499                 break;
500         case CONTROL('K'): /* KEEP position */
501                 if (mca != A_FILTER)
502                         flag = SRCH_NO_MOVE;
503                 break;
504         case CONTROL('R'): /* Don't use REGULAR EXPRESSIONS */
505                 flag = SRCH_NO_REGEX;
506                 break;
507         case CONTROL('N'): /* NOT match */
508         case '!':
509                 flag = SRCH_NO_MATCH;
510                 break;
511         }
512
513         if (flag != 0)
514         {
515                 search_type ^= flag;
516                 mca_search();
517                 return (MCA_MORE);
518         }
519         return (NO_MCA);
520 }
521
522 /*
523  * Handle a character of a multi-character command.
524  */
525         static int
526 mca_char(c)
527         int c;
528 {
529         char *cbuf;
530         int ret;
531
532         switch (mca)
533         {
534         case 0:
535                 /*
536                  * We're not in a multicharacter command.
537                  */
538                 return (NO_MCA);
539
540         case A_PREFIX:
541                 /*
542                  * In the prefix of a command.
543                  * This not considered a multichar command
544                  * (even tho it uses cmdbuf, etc.).
545                  * It is handled in the commands() switch.
546                  */
547                 return (NO_MCA);
548
549         case A_DIGIT:
550                 /*
551                  * Entering digits of a number.
552                  * Terminated by a non-digit.
553                  */
554                 if (!((c >= '0' && c <= '9') || c == '.') && 
555                   editchar(c, EC_PEEK|EC_NOHISTORY|EC_NOCOMPLETE|EC_NORIGHTLEFT) == A_INVALID)
556                 {
557                         /*
558                          * Not part of the number.
559                          * End the number and treat this char 
560                          * as a normal command character.
561                          */
562                         number = cmd_int(&fraction);
563                         mca = 0;
564                         cmd_accept();
565                         return (NO_MCA);
566                 }
567                 break;
568
569         case A_OPT_TOGGLE:
570                 ret = mca_opt_char(c);
571                 if (ret != NO_MCA)
572                         return (ret);
573                 break;
574
575         case A_F_SEARCH:
576         case A_B_SEARCH:
577         case A_FILTER:
578                 ret = mca_search_char(c);
579                 if (ret != NO_MCA)
580                         return (ret);
581                 break;
582
583         default:
584                 /* Other multicharacter command. */
585                 break;
586         }
587
588         /*
589          * The multichar command is terminated by a newline.
590          */
591         if (c == '\n' || c == '\r')
592         {
593                 /*
594                  * Execute the command.
595                  */
596                 exec_mca();
597                 return (MCA_DONE);
598         }
599
600         /*
601          * Append the char to the command buffer.
602          */
603         if (cmd_char(c) == CC_QUIT)
604                 /*
605                  * Abort the multi-char command.
606                  */
607                 return (MCA_DONE);
608
609         if ((mca == A_F_BRACKET || mca == A_B_BRACKET) && len_cmdbuf() >= 2)
610         {
611                 /*
612                  * Special case for the bracket-matching commands.
613                  * Execute the command after getting exactly two
614                  * characters from the user.
615                  */
616                 exec_mca();
617                 return (MCA_DONE);
618         }
619
620         /*
621          * Need another character.
622          */
623         return (MCA_MORE);
624 }
625
626 /*
627  * Discard any buffered file data.
628  */
629         static void
630 clear_buffers()
631 {
632         if (!(ch_getflags() & CH_CANSEEK))
633                 return;
634         ch_flush();
635         clr_linenum();
636 #if HILITE_SEARCH
637         clr_hilite();
638 #endif
639 }
640
641 /*
642  * Make sure the screen is displayed.
643  */
644         static void
645 make_display()
646 {
647         /*
648          * If nothing is displayed yet, display starting from initial_scrpos.
649          */
650         if (empty_screen())
651         {
652                 if (initial_scrpos.pos == NULL_POSITION)
653                         /*
654                          * {{ Maybe this should be:
655                          *    jump_loc(ch_zero(), jump_sline);
656                          *    but this behavior seems rather unexpected 
657                          *    on the first screen. }}
658                          */
659                         jump_loc(ch_zero(), 1);
660                 else
661                         jump_loc(initial_scrpos.pos, initial_scrpos.ln);
662         } else if (screen_trashed)
663         {
664                 int save_top_scroll = top_scroll;
665                 int save_ignore_eoi = ignore_eoi;
666                 top_scroll = 1;
667                 ignore_eoi = 0;
668                 if (screen_trashed == 2)
669                 {
670                         /* Special case used by ignore_eoi: re-open the input file
671                          * and jump to the end of the file. */
672                         reopen_curr_ifile();
673                         jump_forw();
674                 }
675                 repaint();
676                 top_scroll = save_top_scroll;
677                 ignore_eoi = save_ignore_eoi;
678         }
679 }
680
681 /*
682  * Display the appropriate prompt.
683  */
684         static void
685 prompt()
686 {
687         register constant char *p;
688
689         if (ungot != NULL)
690         {
691                 /*
692                  * No prompt necessary if commands are from 
693                  * ungotten chars rather than from the user.
694                  */
695                 return;
696         }
697
698         /*
699          * Make sure the screen is displayed.
700          */
701         make_display();
702         bottompos = position(BOTTOM_PLUS_ONE);
703
704         /*
705          * If we've hit EOF on the last file and the -E flag is set, quit.
706          */
707         if (get_quit_at_eof() == OPT_ONPLUS &&
708             eof_displayed() && !(ch_getflags() & CH_HELPFILE) && 
709             next_ifile(curr_ifile) == NULL_IFILE)
710                 quit(QUIT_OK);
711
712         /*
713          * If the entire file is displayed and the -F flag is set, quit.
714          */
715         if (quit_if_one_screen &&
716             entire_file_displayed() && !(ch_getflags() & CH_HELPFILE) && 
717             next_ifile(curr_ifile) == NULL_IFILE)
718                 quit(QUIT_OK);
719
720 #if MSDOS_COMPILER==WIN32C
721         /* 
722          * In Win32, display the file name in the window title.
723          */
724         if (!(ch_getflags() & CH_HELPFILE))
725                 SetConsoleTitle(pr_expand("Less?f - %f.", 0));
726 #endif
727         /*
728          * Select the proper prompt and display it.
729          */
730         /*
731          * If the previous action was a forward movement, 
732          * don't clear the bottom line of the display;
733          * just print the prompt since the forward movement guarantees 
734          * that we're in the right position to display the prompt.
735          * Clearing the line could cause a problem: for example, if the last
736          * line displayed ended at the right screen edge without a newline,
737          * then clearing would clear the last displayed line rather than
738          * the prompt line.
739          */
740         if (!forw_prompt)
741                 clear_bot();
742         clear_cmd();
743         forw_prompt = 0;
744         p = pr_string();
745         if (is_filtering())
746                 putstr("& ");
747         if (p == NULL || *p == '\0')
748                 putchr(':');
749         else
750         {
751                 at_enter(AT_STANDOUT);
752                 putstr(p);
753                 at_exit();
754         }
755         clear_eol();
756 }
757
758 /*
759  * Display the less version message.
760  */
761         public void
762 dispversion()
763 {
764         PARG parg;
765
766         parg.p_string = version;
767         error("less %s", &parg);
768 }
769
770 /*
771  * Get command character.
772  * The character normally comes from the keyboard,
773  * but may come from ungotten characters
774  * (characters previously given to ungetcc or ungetsc).
775  */
776         public int
777 getcc()
778 {
779         if (unget_end) 
780         {
781                 /*
782                  * We have just run out of ungotten chars.
783                  */
784                 unget_end = 0;
785                 if (len_cmdbuf() == 0)
786                         return (getchr());
787                 /*
788                  * Command is incomplete, so try to complete it.
789                  */
790                 switch (mca)
791                 {
792                 case A_DIGIT:
793                         /*
794                          * We have a number but no command.  Treat as #g.
795                          */
796                         return ('g');
797
798                 case A_F_SEARCH:
799                 case A_B_SEARCH:
800                         /*
801                          * We have "/string" but no newline.  Add the \n.
802                          */
803                         return ('\n'); 
804
805                 default:
806                         /*
807                          * Some other incomplete command.  Let user complete it.
808                          */
809                         return (getchr());
810                 }
811         }
812
813         if (ungot == NULL)
814         {
815                 /*
816                  * Normal case: no ungotten chars, so get one from the user.
817                  */
818                 return (getchr());
819         }
820
821         /*
822          * Return the next ungotten char.
823          */
824         {
825                 struct ungot *ug = ungot;
826                 char c = ug->ug_char;
827                 ungot = ug->ug_next;
828                 free(ug);
829                 unget_end = (ungot == NULL);
830                 return (c);
831         }
832 }
833
834 /*
835  * "Unget" a command character.
836  * The next getcc() will return this character.
837  */
838         public void
839 ungetcc(c)
840         int c;
841 {
842         struct ungot *ug = (struct ungot *) ecalloc(1, sizeof(struct ungot));
843
844         ug->ug_char = c;
845         ug->ug_next = ungot;
846         ungot = ug;
847         unget_end = 0;
848 }
849
850 /*
851  * Unget a whole string of command characters.
852  * The next sequence of getcc()'s will return this string.
853  */
854         public void
855 ungetsc(s)
856         char *s;
857 {
858         register char *p;
859
860         for (p = s + strlen(s) - 1;  p >= s;  p--)
861                 ungetcc(*p);
862 }
863
864 /*
865  * Search for a pattern, possibly in multiple files.
866  * If SRCH_FIRST_FILE is set, begin searching at the first file.
867  * If SRCH_PAST_EOF is set, continue the search thru multiple files.
868  */
869         static void
870 multi_search(pattern, n, silent)
871         char *pattern;
872         int n;
873         int silent;
874 {
875         register int nomore;
876         IFILE save_ifile;
877         int changed_file;
878
879         changed_file = 0;
880         save_ifile = save_curr_ifile();
881
882         if (search_type & SRCH_FIRST_FILE)
883         {
884                 /*
885                  * Start at the first (or last) file 
886                  * in the command line list.
887                  */
888                 if (search_type & SRCH_FORW)
889                         nomore = edit_first();
890                 else
891                         nomore = edit_last();
892                 if (nomore)
893                 {
894                         unsave_ifile(save_ifile);
895                         return;
896                 }
897                 changed_file = 1;
898                 search_type &= ~SRCH_FIRST_FILE;
899         }
900
901         for (;;)
902         {
903                 n = search(search_type, pattern, n);
904                 /*
905                  * The SRCH_NO_MOVE flag doesn't "stick": it gets cleared
906                  * after being used once.  This allows "n" to work after
907                  * using a /@@ search.
908                  */
909                 search_type &= ~SRCH_NO_MOVE;
910                 if (n == 0)
911                 {
912                         /*
913                          * Found it.
914                          */
915                         unsave_ifile(save_ifile);
916                         return;
917                 }
918
919                 if (n < 0)
920                         /*
921                          * Some kind of error in the search.
922                          * Error message has been printed by search().
923                          */
924                         break;
925
926                 if ((search_type & SRCH_PAST_EOF) == 0)
927                         /*
928                          * We didn't find a match, but we're
929                          * supposed to search only one file.
930                          */
931                         break;
932                 /*
933                  * Move on to the next file.
934                  */
935                 if (search_type & SRCH_FORW)
936                         nomore = edit_next(1);
937                 else
938                         nomore = edit_prev(1);
939                 if (nomore)
940                         break;
941                 changed_file = 1;
942         }
943
944         /*
945          * Didn't find it.
946          * Print an error message if we haven't already.
947          */
948         if (n > 0 && !silent)
949                 error("Pattern not found", NULL_PARG);
950
951         if (changed_file)
952         {
953                 /*
954                  * Restore the file we were originally viewing.
955                  */
956                 reedit_ifile(save_ifile);
957         } else
958         {
959                 unsave_ifile(save_ifile);
960         }
961 }
962
963 /*
964  * Forward forever, or until a highlighted line appears.
965  */
966         static int
967 forw_loop(until_hilite)
968         int until_hilite;
969 {
970         POSITION curr_len;
971
972         if (ch_getflags() & CH_HELPFILE)
973                 return (A_NOACTION);
974
975         cmd_exec();
976         jump_forw_buffered();
977         curr_len = ch_length();
978         highest_hilite = until_hilite ? curr_len : NULL_POSITION;
979         ignore_eoi = 1;
980         while (!sigs)
981         {
982                 if (until_hilite && highest_hilite > curr_len)
983                 {
984                         bell();
985                         break;
986                 }
987                 make_display();
988                 forward(1, 0, 0);
989         }
990         ignore_eoi = 0;
991         ch_set_eof();
992
993         /*
994          * This gets us back in "F mode" after processing 
995          * a non-abort signal (e.g. window-change).  
996          */
997         if (sigs && !ABORT_SIGS())
998                 return (until_hilite ? A_F_UNTIL_HILITE : A_F_FOREVER);
999
1000         return (A_NOACTION);
1001 }
1002
1003 /*
1004  * Main command processor.
1005  * Accept and execute commands until a quit command.
1006  */
1007         public void
1008 commands()
1009 {
1010         register int c;
1011         register int action;
1012         register char *cbuf;
1013         int newaction;
1014         int save_search_type;
1015         char *extra;
1016         char tbuf[2];
1017         PARG parg;
1018         IFILE old_ifile;
1019         IFILE new_ifile;
1020         char *tagfile;
1021
1022         search_type = SRCH_FORW;
1023         wscroll = (sc_height + 1) / 2;
1024         newaction = A_NOACTION;
1025
1026         for (;;)
1027         {
1028                 mca = 0;
1029                 cmd_accept();
1030                 number = 0;
1031                 curropt = NULL;
1032
1033                 /*
1034                  * See if any signals need processing.
1035                  */
1036                 if (sigs)
1037                 {
1038                         psignals();
1039                         if (quitting)
1040                                 quit(QUIT_SAVED_STATUS);
1041                 }
1042
1043                 /*
1044                  * See if window size changed, for systems that don't
1045                  * generate SIGWINCH.
1046                  */
1047                 check_winch();
1048
1049                 /*
1050                  * Display prompt and accept a character.
1051                  */
1052                 cmd_reset();
1053                 prompt();
1054                 if (sigs)
1055                         continue;
1056                 if (newaction == A_NOACTION)
1057                         c = getcc();
1058
1059         again:
1060                 if (sigs)
1061                         continue;
1062
1063                 if (newaction != A_NOACTION)
1064                 {
1065                         action = newaction;
1066                         newaction = A_NOACTION;
1067                 } else
1068                 {
1069                         /*
1070                          * If we are in a multicharacter command, call mca_char.
1071                          * Otherwise we call fcmd_decode to determine the
1072                          * action to be performed.
1073                          */
1074                         if (mca)
1075                                 switch (mca_char(c))
1076                                 {
1077                                 case MCA_MORE:
1078                                         /*
1079                                          * Need another character.
1080                                          */
1081                                         c = getcc();
1082                                         goto again;
1083                                 case MCA_DONE:
1084                                         /*
1085                                          * Command has been handled by mca_char.
1086                                          * Start clean with a prompt.
1087                                          */
1088                                         continue;
1089                                 case NO_MCA:
1090                                         /*
1091                                          * Not a multi-char command
1092                                          * (at least, not anymore).
1093                                          */
1094                                         break;
1095                                 }
1096
1097                         /*
1098                          * Decode the command character and decide what to do.
1099                          */
1100                         if (mca)
1101                         {
1102                                 /*
1103                                  * We're in a multichar command.
1104                                  * Add the character to the command buffer
1105                                  * and display it on the screen.
1106                                  * If the user backspaces past the start 
1107                                  * of the line, abort the command.
1108                                  */
1109                                 if (cmd_char(c) == CC_QUIT || len_cmdbuf() == 0)
1110                                         continue;
1111                                 cbuf = get_cmdbuf();
1112                         } else
1113                         {
1114                                 /*
1115                                  * Don't use cmd_char if we're starting fresh
1116                                  * at the beginning of a command, because we
1117                                  * don't want to echo the command until we know
1118                                  * it is a multichar command.  We also don't
1119                                  * want erase_char/kill_char to be treated
1120                                  * as line editing characters.
1121                                  */
1122                                 tbuf[0] = c;
1123                                 tbuf[1] = '\0';
1124                                 cbuf = tbuf;
1125                         }
1126                         extra = NULL;
1127                         action = fcmd_decode(cbuf, &extra);
1128                         /*
1129                          * If an "extra" string was returned,
1130                          * process it as a string of command characters.
1131                          */
1132                         if (extra != NULL)
1133                                 ungetsc(extra);
1134                 }
1135                 /*
1136                  * Clear the cmdbuf string.
1137                  * (But not if we're in the prefix of a command,
1138                  * because the partial command string is kept there.)
1139                  */
1140                 if (action != A_PREFIX)
1141                         cmd_reset();
1142
1143                 switch (action)
1144                 {
1145                 case A_DIGIT:
1146                         /*
1147                          * First digit of a number.
1148                          */
1149                         start_mca(A_DIGIT, ":", (void*)NULL, CF_QUIT_ON_ERASE);
1150                         goto again;
1151
1152                 case A_F_WINDOW:
1153                         /*
1154                          * Forward one window (and set the window size).
1155                          */
1156                         if (number > 0)
1157                                 swindow = (int) number;
1158                         /* FALLTHRU */
1159                 case A_F_SCREEN:
1160                         /*
1161                          * Forward one screen.
1162                          */
1163                         if (number <= 0)
1164                                 number = get_swindow();
1165                         cmd_exec();
1166                         if (show_attn)
1167                                 set_attnpos(bottompos);
1168                         forward((int) number, 0, 1);
1169                         break;
1170
1171                 case A_B_WINDOW:
1172                         /*
1173                          * Backward one window (and set the window size).
1174                          */
1175                         if (number > 0)
1176                                 swindow = (int) number;
1177                         /* FALLTHRU */
1178                 case A_B_SCREEN:
1179                         /*
1180                          * Backward one screen.
1181                          */
1182                         if (number <= 0)
1183                                 number = get_swindow();
1184                         cmd_exec();
1185                         backward((int) number, 0, 1);
1186                         break;
1187
1188                 case A_F_LINE:
1189                         /*
1190                          * Forward N (default 1) line.
1191                          */
1192                         if (number <= 0)
1193                                 number = 1;
1194                         cmd_exec();
1195                         if (show_attn == OPT_ONPLUS && number > 1)
1196                                 set_attnpos(bottompos);
1197                         forward((int) number, 0, 0);
1198                         break;
1199
1200                 case A_B_LINE:
1201                         /*
1202                          * Backward N (default 1) line.
1203                          */
1204                         if (number <= 0)
1205                                 number = 1;
1206                         cmd_exec();
1207                         backward((int) number, 0, 0);
1208                         break;
1209
1210                 case A_FF_LINE:
1211                         /*
1212                          * Force forward N (default 1) line.
1213                          */
1214                         if (number <= 0)
1215                                 number = 1;
1216                         cmd_exec();
1217                         if (show_attn == OPT_ONPLUS && number > 1)
1218                                 set_attnpos(bottompos);
1219                         forward((int) number, 1, 0);
1220                         break;
1221
1222                 case A_BF_LINE:
1223                         /*
1224                          * Force backward N (default 1) line.
1225                          */
1226                         if (number <= 0)
1227                                 number = 1;
1228                         cmd_exec();
1229                         backward((int) number, 1, 0);
1230                         break;
1231                 
1232                 case A_FF_SCREEN:
1233                         /*
1234                          * Force forward one screen.
1235                          */
1236                         if (number <= 0)
1237                                 number = get_swindow();
1238                         cmd_exec();
1239                         if (show_attn == OPT_ONPLUS)
1240                                 set_attnpos(bottompos);
1241                         forward((int) number, 1, 0);
1242                         break;
1243
1244                 case A_F_FOREVER:
1245                         /*
1246                          * Forward forever, ignoring EOF.
1247                          */
1248                         if (show_attn)
1249                                 set_attnpos(bottompos);
1250                         newaction = forw_loop(0);
1251                         break;
1252
1253                 case A_F_UNTIL_HILITE:
1254                         newaction = forw_loop(1);
1255                         break;
1256
1257                 case A_F_SCROLL:
1258                         /*
1259                          * Forward N lines 
1260                          * (default same as last 'd' or 'u' command).
1261                          */
1262                         if (number > 0)
1263                                 wscroll = (int) number;
1264                         cmd_exec();
1265                         if (show_attn == OPT_ONPLUS)
1266                                 set_attnpos(bottompos);
1267                         forward(wscroll, 0, 0);
1268                         break;
1269
1270                 case A_B_SCROLL:
1271                         /*
1272                          * Forward N lines 
1273                          * (default same as last 'd' or 'u' command).
1274                          */
1275                         if (number > 0)
1276                                 wscroll = (int) number;
1277                         cmd_exec();
1278                         backward(wscroll, 0, 0);
1279                         break;
1280
1281                 case A_FREPAINT:
1282                         /*
1283                          * Flush buffers, then repaint screen.
1284                          * Don't flush the buffers on a pipe!
1285                          */
1286                         clear_buffers();
1287                         /* FALLTHRU */
1288                 case A_REPAINT:
1289                         /*
1290                          * Repaint screen.
1291                          */
1292                         cmd_exec();
1293                         repaint();
1294                         break;
1295
1296                 case A_GOLINE:
1297                         /*
1298                          * Go to line N, default beginning of file.
1299                          */
1300                         if (number <= 0)
1301                                 number = 1;
1302                         cmd_exec();
1303                         jump_back(number);
1304                         break;
1305
1306                 case A_PERCENT:
1307                         /*
1308                          * Go to a specified percentage into the file.
1309                          */
1310                         if (number < 0)
1311                         {
1312                                 number = 0;
1313                                 fraction = 0;
1314                         }
1315                         if (number > 100)
1316                         {
1317                                 number = 100;
1318                                 fraction = 0;
1319                         }
1320                         cmd_exec();
1321                         jump_percent((int) number, fraction);
1322                         break;
1323
1324                 case A_GOEND:
1325                         /*
1326                          * Go to line N, default end of file.
1327                          */
1328                         cmd_exec();
1329                         if (number <= 0)
1330                                 jump_forw();
1331                         else
1332                                 jump_back(number);
1333                         break;
1334
1335                 case A_GOEND_BUF:
1336                         /*
1337                          * Go to line N, default last buffered byte.
1338                          */
1339                         cmd_exec();
1340                         if (number <= 0)
1341                                 jump_forw_buffered();
1342                         else
1343                                 jump_back(number);
1344                         break;
1345
1346                 case A_GOPOS:
1347                         /*
1348                          * Go to a specified byte position in the file.
1349                          */
1350                         cmd_exec();
1351                         if (number < 0)
1352                                 number = 0;
1353                         jump_line_loc((POSITION) number, jump_sline);
1354                         break;
1355
1356                 case A_STAT:
1357                         /*
1358                          * Print file name, etc.
1359                          */
1360                         if (ch_getflags() & CH_HELPFILE)
1361                                 break;
1362                         cmd_exec();
1363                         parg.p_string = eq_message();
1364                         error("%s", &parg);
1365                         break;
1366
1367                 case A_VERSION:
1368                         /*
1369                          * Print version number, without the "@(#)".
1370                          */
1371                         cmd_exec();
1372                         dispversion();
1373                         break;
1374
1375                 case A_QUIT:
1376                         /*
1377                          * Exit.
1378                          */
1379                         if (curr_ifile != NULL_IFILE && 
1380                             ch_getflags() & CH_HELPFILE)
1381                         {
1382                                 /*
1383                                  * Quit while viewing the help file
1384                                  * just means return to viewing the
1385                                  * previous file.
1386                                  */
1387                                 hshift = save_hshift;
1388                                 bs_mode = save_bs_mode;
1389                                 if (edit_prev(1) == 0)
1390                                         break;
1391                         }
1392                         if (extra != NULL)
1393                                 quit(*extra);
1394                         quit(QUIT_OK);
1395                         break;
1396
1397 /*
1398  * Define abbreviation for a commonly used sequence below.
1399  */
1400 #define DO_SEARCH() \
1401                         if (number <= 0) number = 1;    \
1402                         mca_search();                   \
1403                         cmd_exec();                     \
1404                         multi_search((char *)NULL, (int) number, 0);
1405
1406
1407                 case A_F_SEARCH:
1408                         /*
1409                          * Search forward for a pattern.
1410                          * Get the first char of the pattern.
1411                          */
1412                         search_type = SRCH_FORW;
1413                         if (number <= 0)
1414                                 number = 1;
1415                         mca_search();
1416                         c = getcc();
1417                         goto again;
1418
1419                 case A_B_SEARCH:
1420                         /*
1421                          * Search backward for a pattern.
1422                          * Get the first char of the pattern.
1423                          */
1424                         search_type = SRCH_BACK;
1425                         if (number <= 0)
1426                                 number = 1;
1427                         mca_search();
1428                         c = getcc();
1429                         goto again;
1430
1431                 case A_FILTER:
1432 #if HILITE_SEARCH
1433                         search_type = SRCH_FORW | SRCH_FILTER;
1434                         mca_search();
1435                         c = getcc();
1436                         goto again;
1437 #else
1438                         error("Command not available", NULL_PARG);
1439                         break;
1440 #endif
1441
1442                 case A_AGAIN_SEARCH:
1443                         /*
1444                          * Repeat previous search.
1445                          */
1446                         DO_SEARCH();
1447                         break;
1448                 
1449                 case A_T_AGAIN_SEARCH:
1450                         /*
1451                          * Repeat previous search, multiple files.
1452                          */
1453                         search_type |= SRCH_PAST_EOF;
1454                         DO_SEARCH();
1455                         break;
1456
1457                 case A_REVERSE_SEARCH:
1458                         /*
1459                          * Repeat previous search, in reverse direction.
1460                          */
1461                         save_search_type = search_type;
1462                         search_type = SRCH_REVERSE(search_type);
1463                         DO_SEARCH();
1464                         search_type = save_search_type;
1465                         break;
1466
1467                 case A_T_REVERSE_SEARCH:
1468                         /* 
1469                          * Repeat previous search, 
1470                          * multiple files in reverse direction.
1471                          */
1472                         save_search_type = search_type;
1473                         search_type = SRCH_REVERSE(search_type);
1474                         search_type |= SRCH_PAST_EOF;
1475                         DO_SEARCH();
1476                         search_type = save_search_type;
1477                         break;
1478
1479                 case A_UNDO_SEARCH:
1480                         undo_search();
1481                         break;
1482
1483                 case A_HELP:
1484                         /*
1485                          * Help.
1486                          */
1487                         if (ch_getflags() & CH_HELPFILE)
1488                                 break;
1489                         cmd_exec();
1490                         save_hshift = hshift;
1491                         hshift = 0;
1492                         save_bs_mode = bs_mode;
1493                         bs_mode = BS_SPECIAL;
1494                         (void) edit(FAKE_HELPFILE);
1495                         break;
1496
1497                 case A_EXAMINE:
1498 #if EXAMINE
1499                         /*
1500                          * Edit a new file.  Get the filename.
1501                          */
1502                         if (secure)
1503                         {
1504                                 error("Command not available", NULL_PARG);
1505                                 break;
1506                         }
1507                         start_mca(A_EXAMINE, "Examine: ", ml_examine, 0);
1508                         c = getcc();
1509                         goto again;
1510 #else
1511                         error("Command not available", NULL_PARG);
1512                         break;
1513 #endif
1514                         
1515                 case A_VISUAL:
1516                         /*
1517                          * Invoke an editor on the input file.
1518                          */
1519 #if EDITOR
1520                         if (secure)
1521                         {
1522                                 error("Command not available", NULL_PARG);
1523                                 break;
1524                         }
1525                         if (ch_getflags() & CH_HELPFILE)
1526                                 break;
1527                         if (strcmp(get_filename(curr_ifile), "-") == 0)
1528                         {
1529                                 error("Cannot edit standard input", NULL_PARG);
1530                                 break;
1531                         }
1532                         if (curr_altfilename != NULL)
1533                         {
1534                                 error("WARNING: This file was viewed via LESSOPEN",
1535                                         NULL_PARG);
1536                         }
1537                         start_mca(A_SHELL, "!", ml_shell, 0);
1538                         /*
1539                          * Expand the editor prototype string
1540                          * and pass it to the system to execute.
1541                          * (Make sure the screen is displayed so the
1542                          * expansion of "+%lm" works.)
1543                          */
1544                         make_display();
1545                         cmd_exec();
1546                         lsystem(pr_expand(editproto, 0), (char*)NULL);
1547                         break;
1548 #else
1549                         error("Command not available", NULL_PARG);
1550                         break;
1551 #endif
1552
1553                 case A_NEXT_FILE:
1554                         /*
1555                          * Examine next file.
1556                          */
1557 #if TAGS
1558                         if (ntags())
1559                         {
1560                                 error("No next file", NULL_PARG);
1561                                 break;
1562                         }
1563 #endif
1564                         if (number <= 0)
1565                                 number = 1;
1566                         if (edit_next((int) number))
1567                         {
1568                                 if (get_quit_at_eof() && eof_displayed() && 
1569                                     !(ch_getflags() & CH_HELPFILE))
1570                                         quit(QUIT_OK);
1571                                 parg.p_string = (number > 1) ? "(N-th) " : "";
1572                                 error("No %snext file", &parg);
1573                         }
1574                         break;
1575
1576                 case A_PREV_FILE:
1577                         /*
1578                          * Examine previous file.
1579                          */
1580 #if TAGS
1581                         if (ntags())
1582                         {
1583                                 error("No previous file", NULL_PARG);
1584                                 break;
1585                         }
1586 #endif
1587                         if (number <= 0)
1588                                 number = 1;
1589                         if (edit_prev((int) number))
1590                         {
1591                                 parg.p_string = (number > 1) ? "(N-th) " : "";
1592                                 error("No %sprevious file", &parg);
1593                         }
1594                         break;
1595
1596                 case A_NEXT_TAG:
1597 #if TAGS
1598                         if (number <= 0)
1599                                 number = 1;
1600                         tagfile = nexttag((int) number);
1601                         if (tagfile == NULL)
1602                         {
1603                                 error("No next tag", NULL_PARG);
1604                                 break;
1605                         }
1606                         if (edit(tagfile) == 0)
1607                         {
1608                                 POSITION pos = tagsearch();
1609                                 if (pos != NULL_POSITION)
1610                                         jump_loc(pos, jump_sline);
1611                         }
1612 #else
1613                         error("Command not available", NULL_PARG);
1614 #endif
1615                         break;
1616
1617                 case A_PREV_TAG:
1618 #if TAGS
1619                         if (number <= 0)
1620                                 number = 1;
1621                         tagfile = prevtag((int) number);
1622                         if (tagfile == NULL)
1623                         {
1624                                 error("No previous tag", NULL_PARG);
1625                                 break;
1626                         }
1627                         if (edit(tagfile) == 0)
1628                         {
1629                                 POSITION pos = tagsearch();
1630                                 if (pos != NULL_POSITION)
1631                                         jump_loc(pos, jump_sline);
1632                         }
1633 #else
1634                         error("Command not available", NULL_PARG);
1635 #endif
1636                         break;
1637
1638                 case A_INDEX_FILE:
1639                         /*
1640                          * Examine a particular file.
1641                          */
1642                         if (number <= 0)
1643                                 number = 1;
1644                         if (edit_index((int) number))
1645                                 error("No such file", NULL_PARG);
1646                         break;
1647
1648                 case A_REMOVE_FILE:
1649                         if (ch_getflags() & CH_HELPFILE)
1650                                 break;
1651                         old_ifile = curr_ifile;
1652                         new_ifile = getoff_ifile(curr_ifile);
1653                         if (new_ifile == NULL_IFILE)
1654                         {
1655                                 bell();
1656                                 break;
1657                         }
1658                         if (edit_ifile(new_ifile) != 0)
1659                         {
1660                                 reedit_ifile(old_ifile);
1661                                 break;
1662                         }
1663                         del_ifile(old_ifile);
1664                         break;
1665
1666                 case A_OPT_TOGGLE:
1667                         optflag = OPT_TOGGLE;
1668                         optgetname = FALSE;
1669                         mca_opt_toggle();
1670                         c = getcc();
1671                         goto again;
1672
1673                 case A_DISP_OPTION:
1674                         /*
1675                          * Report a flag setting.
1676                          */
1677                         optflag = OPT_NO_TOGGLE;
1678                         optgetname = FALSE;
1679                         mca_opt_toggle();
1680                         c = getcc();
1681                         goto again;
1682
1683                 case A_FIRSTCMD:
1684                         /*
1685                          * Set an initial command for new files.
1686                          */
1687                         start_mca(A_FIRSTCMD, "+", (void*)NULL, 0);
1688                         c = getcc();
1689                         goto again;
1690
1691                 case A_SHELL:
1692                         /*
1693                          * Shell escape.
1694                          */
1695 #if SHELL_ESCAPE
1696                         if (secure)
1697                         {
1698                                 error("Command not available", NULL_PARG);
1699                                 break;
1700                         }
1701                         start_mca(A_SHELL, "!", ml_shell, 0);
1702                         c = getcc();
1703                         goto again;
1704 #else
1705                         error("Command not available", NULL_PARG);
1706                         break;
1707 #endif
1708
1709                 case A_SETMARK:
1710                         /*
1711                          * Set a mark.
1712                          */
1713                         if (ch_getflags() & CH_HELPFILE)
1714                                 break;
1715                         start_mca(A_SETMARK, "mark: ", (void*)NULL, 0);
1716                         c = getcc();
1717                         if (c == erase_char || c == erase2_char ||
1718                             c == kill_char || c == '\n' || c == '\r')
1719                                 break;
1720                         setmark(c);
1721                         break;
1722
1723                 case A_GOMARK:
1724                         /*
1725                          * Go to a mark.
1726                          */
1727                         start_mca(A_GOMARK, "goto mark: ", (void*)NULL, 0);
1728                         c = getcc();
1729                         if (c == erase_char || c == erase2_char ||
1730                             c == kill_char || c == '\n' || c == '\r')
1731                                 break;
1732                         cmd_exec();
1733                         gomark(c);
1734                         break;
1735
1736                 case A_PIPE:
1737 #if PIPEC
1738                         if (secure)
1739                         {
1740                                 error("Command not available", NULL_PARG);
1741                                 break;
1742                         }
1743                         start_mca(A_PIPE, "|mark: ", (void*)NULL, 0);
1744                         c = getcc();
1745                         if (c == erase_char || c == erase2_char || c == kill_char)
1746                                 break;
1747                         if (c == '\n' || c == '\r')
1748                                 c = '.';
1749                         if (badmark(c))
1750                                 break;
1751                         pipec = c;
1752                         start_mca(A_PIPE, "!", ml_shell, 0);
1753                         c = getcc();
1754                         goto again;
1755 #else
1756                         error("Command not available", NULL_PARG);
1757                         break;
1758 #endif
1759
1760                 case A_B_BRACKET:
1761                 case A_F_BRACKET:
1762                         start_mca(action, "Brackets: ", (void*)NULL, 0);
1763                         c = getcc();
1764                         goto again;
1765
1766                 case A_LSHIFT:
1767                         if (number > 0)
1768                                 shift_count = number;
1769                         else
1770                                 number = (shift_count > 0) ?
1771                                         shift_count : sc_width / 2;
1772                         if (number > hshift)
1773                                 number = hshift;
1774                         hshift -= number;
1775                         screen_trashed = 1;
1776                         break;
1777
1778                 case A_RSHIFT:
1779                         if (number > 0)
1780                                 shift_count = number;
1781                         else
1782                                 number = (shift_count > 0) ?
1783                                         shift_count : sc_width / 2;
1784                         hshift += number;
1785                         screen_trashed = 1;
1786                         break;
1787
1788                 case A_PREFIX:
1789                         /*
1790                          * The command is incomplete (more chars are needed).
1791                          * Display the current char, so the user knows
1792                          * what's going on, and get another character.
1793                          */
1794                         if (mca != A_PREFIX)
1795                         {
1796                                 cmd_reset();
1797                                 start_mca(A_PREFIX, " ", (void*)NULL,
1798                                         CF_QUIT_ON_ERASE);
1799                                 (void) cmd_char(c);
1800                         }
1801                         c = getcc();
1802                         goto again;
1803
1804                 case A_NOACTION:
1805                         break;
1806
1807                 default:
1808                         bell();
1809                         break;
1810                 }
1811         }
1812 }