docs: Move trek(6) USD papers into share/doc
[dragonfly.git] / contrib / less / 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         char ug_end_command;
82 };
83 static struct ungot* ungot = NULL;
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         int ret;
530
531         switch (mca)
532         {
533         case 0:
534                 /*
535                  * We're not in a multicharacter command.
536                  */
537                 return (NO_MCA);
538
539         case A_PREFIX:
540                 /*
541                  * In the prefix of a command.
542                  * This not considered a multichar command
543                  * (even tho it uses cmdbuf, etc.).
544                  * It is handled in the commands() switch.
545                  */
546                 return (NO_MCA);
547
548         case A_DIGIT:
549                 /*
550                  * Entering digits of a number.
551                  * Terminated by a non-digit.
552                  */
553                 if (!((c >= '0' && c <= '9') || c == '.') && 
554                   editchar(c, EC_PEEK|EC_NOHISTORY|EC_NOCOMPLETE|EC_NORIGHTLEFT) == A_INVALID)
555                 {
556                         /*
557                          * Not part of the number.
558                          * End the number and treat this char 
559                          * as a normal command character.
560                          */
561                         number = cmd_int(&fraction);
562                         mca = 0;
563                         cmd_accept();
564                         return (NO_MCA);
565                 }
566                 break;
567
568         case A_OPT_TOGGLE:
569                 ret = mca_opt_char(c);
570                 if (ret != NO_MCA)
571                         return (ret);
572                 break;
573
574         case A_F_SEARCH:
575         case A_B_SEARCH:
576         case A_FILTER:
577                 ret = mca_search_char(c);
578                 if (ret != NO_MCA)
579                         return (ret);
580                 break;
581
582         default:
583                 /* Other multicharacter command. */
584                 break;
585         }
586
587         /*
588          * The multichar command is terminated by a newline.
589          */
590         if (c == '\n' || c == '\r')
591         {
592                 /*
593                  * Execute the command.
594                  */
595                 exec_mca();
596                 return (MCA_DONE);
597         }
598
599         /*
600          * Append the char to the command buffer.
601          */
602         if (cmd_char(c) == CC_QUIT)
603                 /*
604                  * Abort the multi-char command.
605                  */
606                 return (MCA_DONE);
607
608         if ((mca == A_F_BRACKET || mca == A_B_BRACKET) && len_cmdbuf() >= 2)
609         {
610                 /*
611                  * Special case for the bracket-matching commands.
612                  * Execute the command after getting exactly two
613                  * characters from the user.
614                  */
615                 exec_mca();
616                 return (MCA_DONE);
617         }
618
619         /*
620          * Need another character.
621          */
622         return (MCA_MORE);
623 }
624
625 /*
626  * Discard any buffered file data.
627  */
628         static void
629 clear_buffers()
630 {
631         if (!(ch_getflags() & CH_CANSEEK))
632                 return;
633         ch_flush();
634         clr_linenum();
635 #if HILITE_SEARCH
636         clr_hilite();
637 #endif
638 }
639
640 /*
641  * Make sure the screen is displayed.
642  */
643         static void
644 make_display()
645 {
646         /*
647          * If nothing is displayed yet, display starting from initial_scrpos.
648          */
649         if (empty_screen())
650         {
651                 if (initial_scrpos.pos == NULL_POSITION)
652                         /*
653                          * {{ Maybe this should be:
654                          *    jump_loc(ch_zero(), jump_sline);
655                          *    but this behavior seems rather unexpected 
656                          *    on the first screen. }}
657                          */
658                         jump_loc(ch_zero(), 1);
659                 else
660                         jump_loc(initial_scrpos.pos, initial_scrpos.ln);
661         } else if (screen_trashed)
662         {
663                 int save_top_scroll = top_scroll;
664                 int save_ignore_eoi = ignore_eoi;
665                 top_scroll = 1;
666                 ignore_eoi = 0;
667                 if (screen_trashed == 2)
668                 {
669                         /* Special case used by ignore_eoi: re-open the input file
670                          * and jump to the end of the file. */
671                         reopen_curr_ifile();
672                         jump_forw();
673                 }
674                 repaint();
675                 top_scroll = save_top_scroll;
676                 ignore_eoi = save_ignore_eoi;
677         }
678 }
679
680 /*
681  * Display the appropriate prompt.
682  */
683         static void
684 prompt()
685 {
686         register constant char *p;
687
688         if (ungot != NULL && !ungot->ug_end_command)
689         {
690                 /*
691                  * No prompt necessary if commands are from 
692                  * ungotten chars rather than from the user.
693                  */
694                 return;
695         }
696
697         /*
698          * Make sure the screen is displayed.
699          */
700         make_display();
701         bottompos = position(BOTTOM_PLUS_ONE);
702
703         /*
704          * If we've hit EOF on the last file and the -E flag is set, quit.
705          */
706         if (get_quit_at_eof() == OPT_ONPLUS &&
707             eof_displayed() && !(ch_getflags() & CH_HELPFILE) && 
708             next_ifile(curr_ifile) == NULL_IFILE)
709                 quit(QUIT_OK);
710
711         /*
712          * If the entire file is displayed and the -F flag is set, quit.
713          */
714         if (quit_if_one_screen &&
715             entire_file_displayed() && !(ch_getflags() & CH_HELPFILE) && 
716             next_ifile(curr_ifile) == NULL_IFILE)
717                 quit(QUIT_OK);
718
719 #if MSDOS_COMPILER==WIN32C
720         /* 
721          * In Win32, display the file name in the window title.
722          */
723         if (!(ch_getflags() & CH_HELPFILE))
724                 SetConsoleTitle(pr_expand("Less?f - %f.", 0));
725 #endif
726         /*
727          * Select the proper prompt and display it.
728          */
729         /*
730          * If the previous action was a forward movement, 
731          * don't clear the bottom line of the display;
732          * just print the prompt since the forward movement guarantees 
733          * that we're in the right position to display the prompt.
734          * Clearing the line could cause a problem: for example, if the last
735          * line displayed ended at the right screen edge without a newline,
736          * then clearing would clear the last displayed line rather than
737          * the prompt line.
738          */
739         if (!forw_prompt)
740                 clear_bot();
741         clear_cmd();
742         forw_prompt = 0;
743         p = pr_string();
744         if (is_filtering())
745                 putstr("& ");
746         if (p == NULL || *p == '\0')
747                 putchr(':');
748         else
749         {
750                 at_enter(AT_STANDOUT);
751                 putstr(p);
752                 at_exit();
753         }
754         clear_eol();
755 }
756
757 /*
758  * Display the less version message.
759  */
760         public void
761 dispversion()
762 {
763         PARG parg;
764
765         parg.p_string = version;
766         error("less %s", &parg);
767 }
768
769 /*
770  * Get command character.
771  * The character normally comes from the keyboard,
772  * but may come from ungotten characters
773  * (characters previously given to ungetcc or ungetsc).
774  */
775         public int
776 getcc()
777 {
778         if (ungot == NULL)
779         {
780                 /*
781                  * Normal case: no ungotten chars, so get one from the user.
782                  */
783                 return (getchr());
784         }
785
786         /*
787          * Return the next ungotten char.
788          */
789         {
790                 struct ungot *ug = ungot;
791                 char c = ug->ug_char;
792                 int end_command = ug->ug_end_command;
793                 ungot = ug->ug_next;
794                 free(ug);
795                 if (end_command)
796                 {
797                         /*
798                          * Command is incomplete, so try to complete it.
799                          */
800                         switch (mca)
801                         {
802                         case A_DIGIT:
803                                 /*
804                                  * We have a number but no command.  Treat as #g.
805                                  */
806                                 return ('g');
807
808                         case A_F_SEARCH:
809                         case A_B_SEARCH:
810                                 /*
811                                  * We have "/string" but no newline.  Add the \n.
812                                  */
813                                 return ('\n'); 
814
815                         default:
816                                 /*
817                                  * Some other incomplete command.  Let user complete it.
818                                  */
819                                 return (getchr());
820                         }
821                 }
822                 return (c);
823         }
824 }
825
826 /*
827  * "Unget" a command character.
828  * The next getcc() will return this character.
829  */
830         public void
831 ungetcc(c)
832         int c;
833 {
834         struct ungot *ug = (struct ungot *) ecalloc(1, sizeof(struct ungot));
835
836         ug->ug_char = (char) c;
837         ug->ug_end_command = (c == CHAR_END_COMMAND);
838         ug->ug_next = ungot;
839         ungot = ug;
840 }
841
842 /*
843  * Unget a whole string of command characters.
844  * The next sequence of getcc()'s will return this string.
845  */
846         public void
847 ungetsc(s)
848         char *s;
849 {
850         register char *p;
851
852         for (p = s + strlen(s) - 1;  p >= s;  p--)
853                 ungetcc(*p);
854 }
855
856 /*
857  * Search for a pattern, possibly in multiple files.
858  * If SRCH_FIRST_FILE is set, begin searching at the first file.
859  * If SRCH_PAST_EOF is set, continue the search thru multiple files.
860  */
861         static void
862 multi_search(pattern, n, silent)
863         char *pattern;
864         int n;
865         int silent;
866 {
867         register int nomore;
868         IFILE save_ifile;
869         int changed_file;
870
871         changed_file = 0;
872         save_ifile = save_curr_ifile();
873
874         if (search_type & SRCH_FIRST_FILE)
875         {
876                 /*
877                  * Start at the first (or last) file 
878                  * in the command line list.
879                  */
880                 if (search_type & SRCH_FORW)
881                         nomore = edit_first();
882                 else
883                         nomore = edit_last();
884                 if (nomore)
885                 {
886                         unsave_ifile(save_ifile);
887                         return;
888                 }
889                 changed_file = 1;
890                 search_type &= ~SRCH_FIRST_FILE;
891         }
892
893         for (;;)
894         {
895                 n = search(search_type, pattern, n);
896                 /*
897                  * The SRCH_NO_MOVE flag doesn't "stick": it gets cleared
898                  * after being used once.  This allows "n" to work after
899                  * using a /@@ search.
900                  */
901                 search_type &= ~SRCH_NO_MOVE;
902                 if (n == 0)
903                 {
904                         /*
905                          * Found it.
906                          */
907                         unsave_ifile(save_ifile);
908                         return;
909                 }
910
911                 if (n < 0)
912                         /*
913                          * Some kind of error in the search.
914                          * Error message has been printed by search().
915                          */
916                         break;
917
918                 if ((search_type & SRCH_PAST_EOF) == 0)
919                         /*
920                          * We didn't find a match, but we're
921                          * supposed to search only one file.
922                          */
923                         break;
924                 /*
925                  * Move on to the next file.
926                  */
927                 if (search_type & SRCH_FORW)
928                         nomore = edit_next(1);
929                 else
930                         nomore = edit_prev(1);
931                 if (nomore)
932                         break;
933                 changed_file = 1;
934         }
935
936         /*
937          * Didn't find it.
938          * Print an error message if we haven't already.
939          */
940         if (n > 0 && !silent)
941                 error("Pattern not found", NULL_PARG);
942
943         if (changed_file)
944         {
945                 /*
946                  * Restore the file we were originally viewing.
947                  */
948                 reedit_ifile(save_ifile);
949         } else
950         {
951                 unsave_ifile(save_ifile);
952         }
953 }
954
955 /*
956  * Forward forever, or until a highlighted line appears.
957  */
958         static int
959 forw_loop(until_hilite)
960         int until_hilite;
961 {
962         POSITION curr_len;
963
964         if (ch_getflags() & CH_HELPFILE)
965                 return (A_NOACTION);
966
967         cmd_exec();
968         jump_forw_buffered();
969         curr_len = ch_length();
970         highest_hilite = until_hilite ? curr_len : NULL_POSITION;
971         ignore_eoi = 1;
972         while (!sigs)
973         {
974                 if (until_hilite && highest_hilite > curr_len)
975                 {
976                         bell();
977                         break;
978                 }
979                 make_display();
980                 forward(1, 0, 0);
981         }
982         ignore_eoi = 0;
983         ch_set_eof();
984
985         /*
986          * This gets us back in "F mode" after processing 
987          * a non-abort signal (e.g. window-change).  
988          */
989         if (sigs && !ABORT_SIGS())
990                 return (until_hilite ? A_F_UNTIL_HILITE : A_F_FOREVER);
991
992         return (A_NOACTION);
993 }
994
995 /*
996  * Main command processor.
997  * Accept and execute commands until a quit command.
998  */
999         public void
1000 commands()
1001 {
1002         register int c;
1003         register int action;
1004         register char *cbuf;
1005         int newaction;
1006         int save_search_type;
1007         char *extra;
1008         char tbuf[2];
1009         PARG parg;
1010         IFILE old_ifile;
1011         IFILE new_ifile;
1012         char *tagfile;
1013
1014         search_type = SRCH_FORW;
1015         wscroll = (sc_height + 1) / 2;
1016         newaction = A_NOACTION;
1017
1018         for (;;)
1019         {
1020                 mca = 0;
1021                 cmd_accept();
1022                 number = 0;
1023                 curropt = NULL;
1024
1025                 /*
1026                  * See if any signals need processing.
1027                  */
1028                 if (sigs)
1029                 {
1030                         psignals();
1031                         if (quitting)
1032                                 quit(QUIT_SAVED_STATUS);
1033                 }
1034
1035                 /*
1036                  * See if window size changed, for systems that don't
1037                  * generate SIGWINCH.
1038                  */
1039                 check_winch();
1040
1041                 /*
1042                  * Display prompt and accept a character.
1043                  */
1044                 cmd_reset();
1045                 prompt();
1046                 if (sigs)
1047                         continue;
1048                 if (newaction == A_NOACTION)
1049                         c = getcc();
1050
1051         again:
1052                 if (sigs)
1053                         continue;
1054
1055                 if (newaction != A_NOACTION)
1056                 {
1057                         action = newaction;
1058                         newaction = A_NOACTION;
1059                 } else
1060                 {
1061                         /*
1062                          * If we are in a multicharacter command, call mca_char.
1063                          * Otherwise we call fcmd_decode to determine the
1064                          * action to be performed.
1065                          */
1066                         if (mca)
1067                                 switch (mca_char(c))
1068                                 {
1069                                 case MCA_MORE:
1070                                         /*
1071                                          * Need another character.
1072                                          */
1073                                         c = getcc();
1074                                         goto again;
1075                                 case MCA_DONE:
1076                                         /*
1077                                          * Command has been handled by mca_char.
1078                                          * Start clean with a prompt.
1079                                          */
1080                                         continue;
1081                                 case NO_MCA:
1082                                         /*
1083                                          * Not a multi-char command
1084                                          * (at least, not anymore).
1085                                          */
1086                                         break;
1087                                 }
1088
1089                         /*
1090                          * Decode the command character and decide what to do.
1091                          */
1092                         if (mca)
1093                         {
1094                                 /*
1095                                  * We're in a multichar command.
1096                                  * Add the character to the command buffer
1097                                  * and display it on the screen.
1098                                  * If the user backspaces past the start 
1099                                  * of the line, abort the command.
1100                                  */
1101                                 if (cmd_char(c) == CC_QUIT || len_cmdbuf() == 0)
1102                                         continue;
1103                                 cbuf = get_cmdbuf();
1104                         } else
1105                         {
1106                                 /*
1107                                  * Don't use cmd_char if we're starting fresh
1108                                  * at the beginning of a command, because we
1109                                  * don't want to echo the command until we know
1110                                  * it is a multichar command.  We also don't
1111                                  * want erase_char/kill_char to be treated
1112                                  * as line editing characters.
1113                                  */
1114                                 tbuf[0] = c;
1115                                 tbuf[1] = '\0';
1116                                 cbuf = tbuf;
1117                         }
1118                         extra = NULL;
1119                         action = fcmd_decode(cbuf, &extra);
1120                         /*
1121                          * If an "extra" string was returned,
1122                          * process it as a string of command characters.
1123                          */
1124                         if (extra != NULL)
1125                                 ungetsc(extra);
1126                 }
1127                 /*
1128                  * Clear the cmdbuf string.
1129                  * (But not if we're in the prefix of a command,
1130                  * because the partial command string is kept there.)
1131                  */
1132                 if (action != A_PREFIX)
1133                         cmd_reset();
1134
1135                 switch (action)
1136                 {
1137                 case A_DIGIT:
1138                         /*
1139                          * First digit of a number.
1140                          */
1141                         start_mca(A_DIGIT, ":", (void*)NULL, CF_QUIT_ON_ERASE);
1142                         goto again;
1143
1144                 case A_F_WINDOW:
1145                         /*
1146                          * Forward one window (and set the window size).
1147                          */
1148                         if (number > 0)
1149                                 swindow = (int) number;
1150                         /* FALLTHRU */
1151                 case A_F_SCREEN:
1152                         /*
1153                          * Forward one screen.
1154                          */
1155                         if (number <= 0)
1156                                 number = get_swindow();
1157                         cmd_exec();
1158                         if (show_attn)
1159                                 set_attnpos(bottompos);
1160                         forward((int) number, 0, 1);
1161                         break;
1162
1163                 case A_B_WINDOW:
1164                         /*
1165                          * Backward one window (and set the window size).
1166                          */
1167                         if (number > 0)
1168                                 swindow = (int) number;
1169                         /* FALLTHRU */
1170                 case A_B_SCREEN:
1171                         /*
1172                          * Backward one screen.
1173                          */
1174                         if (number <= 0)
1175                                 number = get_swindow();
1176                         cmd_exec();
1177                         backward((int) number, 0, 1);
1178                         break;
1179
1180                 case A_F_LINE:
1181                         /*
1182                          * Forward N (default 1) line.
1183                          */
1184                         if (number <= 0)
1185                                 number = 1;
1186                         cmd_exec();
1187                         if (show_attn == OPT_ONPLUS && number > 1)
1188                                 set_attnpos(bottompos);
1189                         forward((int) number, 0, 0);
1190                         break;
1191
1192                 case A_B_LINE:
1193                         /*
1194                          * Backward N (default 1) line.
1195                          */
1196                         if (number <= 0)
1197                                 number = 1;
1198                         cmd_exec();
1199                         backward((int) number, 0, 0);
1200                         break;
1201
1202                 case A_FF_LINE:
1203                         /*
1204                          * Force forward N (default 1) line.
1205                          */
1206                         if (number <= 0)
1207                                 number = 1;
1208                         cmd_exec();
1209                         if (show_attn == OPT_ONPLUS && number > 1)
1210                                 set_attnpos(bottompos);
1211                         forward((int) number, 1, 0);
1212                         break;
1213
1214                 case A_BF_LINE:
1215                         /*
1216                          * Force backward N (default 1) line.
1217                          */
1218                         if (number <= 0)
1219                                 number = 1;
1220                         cmd_exec();
1221                         backward((int) number, 1, 0);
1222                         break;
1223                 
1224                 case A_FF_SCREEN:
1225                         /*
1226                          * Force forward one screen.
1227                          */
1228                         if (number <= 0)
1229                                 number = get_swindow();
1230                         cmd_exec();
1231                         if (show_attn == OPT_ONPLUS)
1232                                 set_attnpos(bottompos);
1233                         forward((int) number, 1, 0);
1234                         break;
1235
1236                 case A_F_FOREVER:
1237                         /*
1238                          * Forward forever, ignoring EOF.
1239                          */
1240                         if (show_attn)
1241                                 set_attnpos(bottompos);
1242                         newaction = forw_loop(0);
1243                         break;
1244
1245                 case A_F_UNTIL_HILITE:
1246                         newaction = forw_loop(1);
1247                         break;
1248
1249                 case A_F_SCROLL:
1250                         /*
1251                          * Forward N lines 
1252                          * (default same as last 'd' or 'u' command).
1253                          */
1254                         if (number > 0)
1255                                 wscroll = (int) number;
1256                         cmd_exec();
1257                         if (show_attn == OPT_ONPLUS)
1258                                 set_attnpos(bottompos);
1259                         forward(wscroll, 0, 0);
1260                         break;
1261
1262                 case A_B_SCROLL:
1263                         /*
1264                          * Forward N lines 
1265                          * (default same as last 'd' or 'u' command).
1266                          */
1267                         if (number > 0)
1268                                 wscroll = (int) number;
1269                         cmd_exec();
1270                         backward(wscroll, 0, 0);
1271                         break;
1272
1273                 case A_FREPAINT:
1274                         /*
1275                          * Flush buffers, then repaint screen.
1276                          * Don't flush the buffers on a pipe!
1277                          */
1278                         clear_buffers();
1279                         /* FALLTHRU */
1280                 case A_REPAINT:
1281                         /*
1282                          * Repaint screen.
1283                          */
1284                         cmd_exec();
1285                         repaint();
1286                         break;
1287
1288                 case A_GOLINE:
1289                         /*
1290                          * Go to line N, default beginning of file.
1291                          */
1292                         if (number <= 0)
1293                                 number = 1;
1294                         cmd_exec();
1295                         jump_back(number);
1296                         break;
1297
1298                 case A_PERCENT:
1299                         /*
1300                          * Go to a specified percentage into the file.
1301                          */
1302                         if (number < 0)
1303                         {
1304                                 number = 0;
1305                                 fraction = 0;
1306                         }
1307                         if (number > 100)
1308                         {
1309                                 number = 100;
1310                                 fraction = 0;
1311                         }
1312                         cmd_exec();
1313                         jump_percent((int) number, fraction);
1314                         break;
1315
1316                 case A_GOEND:
1317                         /*
1318                          * Go to line N, default end of file.
1319                          */
1320                         cmd_exec();
1321                         if (number <= 0)
1322                                 jump_forw();
1323                         else
1324                                 jump_back(number);
1325                         break;
1326
1327                 case A_GOEND_BUF:
1328                         /*
1329                          * Go to line N, default last buffered byte.
1330                          */
1331                         cmd_exec();
1332                         if (number <= 0)
1333                                 jump_forw_buffered();
1334                         else
1335                                 jump_back(number);
1336                         break;
1337
1338                 case A_GOPOS:
1339                         /*
1340                          * Go to a specified byte position in the file.
1341                          */
1342                         cmd_exec();
1343                         if (number < 0)
1344                                 number = 0;
1345                         jump_line_loc((POSITION) number, jump_sline);
1346                         break;
1347
1348                 case A_STAT:
1349                         /*
1350                          * Print file name, etc.
1351                          */
1352                         if (ch_getflags() & CH_HELPFILE)
1353                                 break;
1354                         cmd_exec();
1355                         parg.p_string = eq_message();
1356                         error("%s", &parg);
1357                         break;
1358
1359                 case A_VERSION:
1360                         /*
1361                          * Print version number, without the "@(#)".
1362                          */
1363                         cmd_exec();
1364                         dispversion();
1365                         break;
1366
1367                 case A_QUIT:
1368                         /*
1369                          * Exit.
1370                          */
1371                         if (curr_ifile != NULL_IFILE && 
1372                             ch_getflags() & CH_HELPFILE)
1373                         {
1374                                 /*
1375                                  * Quit while viewing the help file
1376                                  * just means return to viewing the
1377                                  * previous file.
1378                                  */
1379                                 hshift = save_hshift;
1380                                 bs_mode = save_bs_mode;
1381                                 if (edit_prev(1) == 0)
1382                                         break;
1383                         }
1384                         if (extra != NULL)
1385                                 quit(*extra);
1386                         quit(QUIT_OK);
1387                         break;
1388
1389 /*
1390  * Define abbreviation for a commonly used sequence below.
1391  */
1392 #define DO_SEARCH() \
1393                         if (number <= 0) number = 1;    \
1394                         mca_search();                   \
1395                         cmd_exec();                     \
1396                         multi_search((char *)NULL, (int) number, 0);
1397
1398
1399                 case A_F_SEARCH:
1400                         /*
1401                          * Search forward for a pattern.
1402                          * Get the first char of the pattern.
1403                          */
1404                         search_type = SRCH_FORW;
1405                         if (number <= 0)
1406                                 number = 1;
1407                         mca_search();
1408                         c = getcc();
1409                         goto again;
1410
1411                 case A_B_SEARCH:
1412                         /*
1413                          * Search backward for a pattern.
1414                          * Get the first char of the pattern.
1415                          */
1416                         search_type = SRCH_BACK;
1417                         if (number <= 0)
1418                                 number = 1;
1419                         mca_search();
1420                         c = getcc();
1421                         goto again;
1422
1423                 case A_FILTER:
1424 #if HILITE_SEARCH
1425                         search_type = SRCH_FORW | SRCH_FILTER;
1426                         mca_search();
1427                         c = getcc();
1428                         goto again;
1429 #else
1430                         error("Command not available", NULL_PARG);
1431                         break;
1432 #endif
1433
1434                 case A_AGAIN_SEARCH:
1435                         /*
1436                          * Repeat previous search.
1437                          */
1438                         DO_SEARCH();
1439                         break;
1440                 
1441                 case A_T_AGAIN_SEARCH:
1442                         /*
1443                          * Repeat previous search, multiple files.
1444                          */
1445                         search_type |= SRCH_PAST_EOF;
1446                         DO_SEARCH();
1447                         break;
1448
1449                 case A_REVERSE_SEARCH:
1450                         /*
1451                          * Repeat previous search, in reverse direction.
1452                          */
1453                         save_search_type = search_type;
1454                         search_type = SRCH_REVERSE(search_type);
1455                         DO_SEARCH();
1456                         search_type = save_search_type;
1457                         break;
1458
1459                 case A_T_REVERSE_SEARCH:
1460                         /* 
1461                          * Repeat previous search, 
1462                          * multiple files in reverse direction.
1463                          */
1464                         save_search_type = search_type;
1465                         search_type = SRCH_REVERSE(search_type);
1466                         search_type |= SRCH_PAST_EOF;
1467                         DO_SEARCH();
1468                         search_type = save_search_type;
1469                         break;
1470
1471                 case A_UNDO_SEARCH:
1472                         undo_search();
1473                         break;
1474
1475                 case A_HELP:
1476                         /*
1477                          * Help.
1478                          */
1479                         if (ch_getflags() & CH_HELPFILE)
1480                                 break;
1481                         cmd_exec();
1482                         save_hshift = hshift;
1483                         hshift = 0;
1484                         save_bs_mode = bs_mode;
1485                         bs_mode = BS_SPECIAL;
1486                         (void) edit(FAKE_HELPFILE);
1487                         break;
1488
1489                 case A_EXAMINE:
1490 #if EXAMINE
1491                         /*
1492                          * Edit a new file.  Get the filename.
1493                          */
1494                         if (secure)
1495                         {
1496                                 error("Command not available", NULL_PARG);
1497                                 break;
1498                         }
1499                         start_mca(A_EXAMINE, "Examine: ", ml_examine, 0);
1500                         c = getcc();
1501                         goto again;
1502 #else
1503                         error("Command not available", NULL_PARG);
1504                         break;
1505 #endif
1506                         
1507                 case A_VISUAL:
1508                         /*
1509                          * Invoke an editor on the input file.
1510                          */
1511 #if EDITOR
1512                         if (secure)
1513                         {
1514                                 error("Command not available", NULL_PARG);
1515                                 break;
1516                         }
1517                         if (ch_getflags() & CH_HELPFILE)
1518                                 break;
1519                         if (strcmp(get_filename(curr_ifile), "-") == 0)
1520                         {
1521                                 error("Cannot edit standard input", NULL_PARG);
1522                                 break;
1523                         }
1524                         if (curr_altfilename != NULL)
1525                         {
1526                                 error("WARNING: This file was viewed via LESSOPEN",
1527                                         NULL_PARG);
1528                         }
1529                         start_mca(A_SHELL, "!", ml_shell, 0);
1530                         /*
1531                          * Expand the editor prototype string
1532                          * and pass it to the system to execute.
1533                          * (Make sure the screen is displayed so the
1534                          * expansion of "+%lm" works.)
1535                          */
1536                         make_display();
1537                         cmd_exec();
1538                         lsystem(pr_expand(editproto, 0), (char*)NULL);
1539                         break;
1540 #else
1541                         error("Command not available", NULL_PARG);
1542                         break;
1543 #endif
1544
1545                 case A_NEXT_FILE:
1546                         /*
1547                          * Examine next file.
1548                          */
1549 #if TAGS
1550                         if (ntags())
1551                         {
1552                                 error("No next file", NULL_PARG);
1553                                 break;
1554                         }
1555 #endif
1556                         if (number <= 0)
1557                                 number = 1;
1558                         if (edit_next((int) number))
1559                         {
1560                                 if (get_quit_at_eof() && eof_displayed() && 
1561                                     !(ch_getflags() & CH_HELPFILE))
1562                                         quit(QUIT_OK);
1563                                 parg.p_string = (number > 1) ? "(N-th) " : "";
1564                                 error("No %snext file", &parg);
1565                         }
1566                         break;
1567
1568                 case A_PREV_FILE:
1569                         /*
1570                          * Examine previous file.
1571                          */
1572 #if TAGS
1573                         if (ntags())
1574                         {
1575                                 error("No previous file", NULL_PARG);
1576                                 break;
1577                         }
1578 #endif
1579                         if (number <= 0)
1580                                 number = 1;
1581                         if (edit_prev((int) number))
1582                         {
1583                                 parg.p_string = (number > 1) ? "(N-th) " : "";
1584                                 error("No %sprevious file", &parg);
1585                         }
1586                         break;
1587
1588                 case A_NEXT_TAG:
1589 #if TAGS
1590                         if (number <= 0)
1591                                 number = 1;
1592                         tagfile = nexttag((int) number);
1593                         if (tagfile == NULL)
1594                         {
1595                                 error("No next tag", NULL_PARG);
1596                                 break;
1597                         }
1598                         if (edit(tagfile) == 0)
1599                         {
1600                                 POSITION pos = tagsearch();
1601                                 if (pos != NULL_POSITION)
1602                                         jump_loc(pos, jump_sline);
1603                         }
1604 #else
1605                         error("Command not available", NULL_PARG);
1606 #endif
1607                         break;
1608
1609                 case A_PREV_TAG:
1610 #if TAGS
1611                         if (number <= 0)
1612                                 number = 1;
1613                         tagfile = prevtag((int) number);
1614                         if (tagfile == NULL)
1615                         {
1616                                 error("No previous tag", NULL_PARG);
1617                                 break;
1618                         }
1619                         if (edit(tagfile) == 0)
1620                         {
1621                                 POSITION pos = tagsearch();
1622                                 if (pos != NULL_POSITION)
1623                                         jump_loc(pos, jump_sline);
1624                         }
1625 #else
1626                         error("Command not available", NULL_PARG);
1627 #endif
1628                         break;
1629
1630                 case A_INDEX_FILE:
1631                         /*
1632                          * Examine a particular file.
1633                          */
1634                         if (number <= 0)
1635                                 number = 1;
1636                         if (edit_index((int) number))
1637                                 error("No such file", NULL_PARG);
1638                         break;
1639
1640                 case A_REMOVE_FILE:
1641                         if (ch_getflags() & CH_HELPFILE)
1642                                 break;
1643                         old_ifile = curr_ifile;
1644                         new_ifile = getoff_ifile(curr_ifile);
1645                         if (new_ifile == NULL_IFILE)
1646                         {
1647                                 bell();
1648                                 break;
1649                         }
1650                         if (edit_ifile(new_ifile) != 0)
1651                         {
1652                                 reedit_ifile(old_ifile);
1653                                 break;
1654                         }
1655                         del_ifile(old_ifile);
1656                         break;
1657
1658                 case A_OPT_TOGGLE:
1659                         optflag = OPT_TOGGLE;
1660                         optgetname = FALSE;
1661                         mca_opt_toggle();
1662                         c = getcc();
1663                         goto again;
1664
1665                 case A_DISP_OPTION:
1666                         /*
1667                          * Report a flag setting.
1668                          */
1669                         optflag = OPT_NO_TOGGLE;
1670                         optgetname = FALSE;
1671                         mca_opt_toggle();
1672                         c = getcc();
1673                         goto again;
1674
1675                 case A_FIRSTCMD:
1676                         /*
1677                          * Set an initial command for new files.
1678                          */
1679                         start_mca(A_FIRSTCMD, "+", (void*)NULL, 0);
1680                         c = getcc();
1681                         goto again;
1682
1683                 case A_SHELL:
1684                         /*
1685                          * Shell escape.
1686                          */
1687 #if SHELL_ESCAPE
1688                         if (secure)
1689                         {
1690                                 error("Command not available", NULL_PARG);
1691                                 break;
1692                         }
1693                         start_mca(A_SHELL, "!", ml_shell, 0);
1694                         c = getcc();
1695                         goto again;
1696 #else
1697                         error("Command not available", NULL_PARG);
1698                         break;
1699 #endif
1700
1701                 case A_SETMARK:
1702                         /*
1703                          * Set a mark.
1704                          */
1705                         if (ch_getflags() & CH_HELPFILE)
1706                                 break;
1707                         start_mca(A_SETMARK, "mark: ", (void*)NULL, 0);
1708                         c = getcc();
1709                         if (c == erase_char || c == erase2_char ||
1710                             c == kill_char || c == '\n' || c == '\r')
1711                                 break;
1712                         setmark(c);
1713                         break;
1714
1715                 case A_GOMARK:
1716                         /*
1717                          * Go to a mark.
1718                          */
1719                         start_mca(A_GOMARK, "goto mark: ", (void*)NULL, 0);
1720                         c = getcc();
1721                         if (c == erase_char || c == erase2_char ||
1722                             c == kill_char || c == '\n' || c == '\r')
1723                                 break;
1724                         cmd_exec();
1725                         gomark(c);
1726                         break;
1727
1728                 case A_PIPE:
1729 #if PIPEC
1730                         if (secure)
1731                         {
1732                                 error("Command not available", NULL_PARG);
1733                                 break;
1734                         }
1735                         start_mca(A_PIPE, "|mark: ", (void*)NULL, 0);
1736                         c = getcc();
1737                         if (c == erase_char || c == erase2_char || c == kill_char)
1738                                 break;
1739                         if (c == '\n' || c == '\r')
1740                                 c = '.';
1741                         if (badmark(c))
1742                                 break;
1743                         pipec = c;
1744                         start_mca(A_PIPE, "!", ml_shell, 0);
1745                         c = getcc();
1746                         goto again;
1747 #else
1748                         error("Command not available", NULL_PARG);
1749                         break;
1750 #endif
1751
1752                 case A_B_BRACKET:
1753                 case A_F_BRACKET:
1754                         start_mca(action, "Brackets: ", (void*)NULL, 0);
1755                         c = getcc();
1756                         goto again;
1757
1758                 case A_LSHIFT:
1759                         if (number > 0)
1760                                 shift_count = number;
1761                         else
1762                                 number = (shift_count > 0) ?
1763                                         shift_count : sc_width / 2;
1764                         if (number > hshift)
1765                                 number = hshift;
1766                         hshift -= number;
1767                         screen_trashed = 1;
1768                         break;
1769
1770                 case A_RSHIFT:
1771                         if (number > 0)
1772                                 shift_count = number;
1773                         else
1774                                 number = (shift_count > 0) ?
1775                                         shift_count : sc_width / 2;
1776                         hshift += number;
1777                         screen_trashed = 1;
1778                         break;
1779
1780                 case A_PREFIX:
1781                         /*
1782                          * The command is incomplete (more chars are needed).
1783                          * Display the current char, so the user knows
1784                          * what's going on, and get another character.
1785                          */
1786                         if (mca != A_PREFIX)
1787                         {
1788                                 cmd_reset();
1789                                 start_mca(A_PREFIX, " ", (void*)NULL,
1790                                         CF_QUIT_ON_ERASE);
1791                                 (void) cmd_char(c);
1792                         }
1793                         c = getcc();
1794                         goto again;
1795
1796                 case A_NOACTION:
1797                         break;
1798
1799                 default:
1800                         bell();
1801                         break;
1802                 }
1803         }
1804 }