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