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