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