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