Merge branch 'vendor/FILE'
[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     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 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  * Main command processor.
960  * Accept and execute commands until a quit command.
961  */
962         public void
963 commands()
964 {
965         register int c;
966         register int action;
967         register char *cbuf;
968         int newaction;
969         int save_search_type;
970         char *extra;
971         char tbuf[2];
972         PARG parg;
973         IFILE old_ifile;
974         IFILE new_ifile;
975         char *tagfile;
976
977         search_type = SRCH_FORW;
978         wscroll = (sc_height + 1) / 2;
979         newaction = A_NOACTION;
980
981         for (;;)
982         {
983                 mca = 0;
984                 cmd_accept();
985                 number = 0;
986                 curropt = NULL;
987
988                 /*
989                  * See if any signals need processing.
990                  */
991                 if (sigs)
992                 {
993                         psignals();
994                         if (quitting)
995                                 quit(QUIT_SAVED_STATUS);
996                 }
997
998                 /*
999                  * See if window size changed, for systems that don't
1000                  * generate SIGWINCH.
1001                  */
1002                 check_winch();
1003
1004                 /*
1005                  * Display prompt and accept a character.
1006                  */
1007                 cmd_reset();
1008                 prompt();
1009                 if (sigs)
1010                         continue;
1011                 if (newaction == A_NOACTION)
1012                         c = getcc();
1013
1014         again:
1015                 if (sigs)
1016                         continue;
1017
1018                 if (newaction != A_NOACTION)
1019                 {
1020                         action = newaction;
1021                         newaction = A_NOACTION;
1022                 } else
1023                 {
1024                         /*
1025                          * If we are in a multicharacter command, call mca_char.
1026                          * Otherwise we call fcmd_decode to determine the
1027                          * action to be performed.
1028                          */
1029                         if (mca)
1030                                 switch (mca_char(c))
1031                                 {
1032                                 case MCA_MORE:
1033                                         /*
1034                                          * Need another character.
1035                                          */
1036                                         c = getcc();
1037                                         goto again;
1038                                 case MCA_DONE:
1039                                         /*
1040                                          * Command has been handled by mca_char.
1041                                          * Start clean with a prompt.
1042                                          */
1043                                         continue;
1044                                 case NO_MCA:
1045                                         /*
1046                                          * Not a multi-char command
1047                                          * (at least, not anymore).
1048                                          */
1049                                         break;
1050                                 }
1051
1052                         /*
1053                          * Decode the command character and decide what to do.
1054                          */
1055                         if (mca)
1056                         {
1057                                 /*
1058                                  * We're in a multichar command.
1059                                  * Add the character to the command buffer
1060                                  * and display it on the screen.
1061                                  * If the user backspaces past the start 
1062                                  * of the line, abort the command.
1063                                  */
1064                                 if (cmd_char(c) == CC_QUIT || len_cmdbuf() == 0)
1065                                         continue;
1066                                 cbuf = get_cmdbuf();
1067                         } else
1068                         {
1069                                 /*
1070                                  * Don't use cmd_char if we're starting fresh
1071                                  * at the beginning of a command, because we
1072                                  * don't want to echo the command until we know
1073                                  * it is a multichar command.  We also don't
1074                                  * want erase_char/kill_char to be treated
1075                                  * as line editing characters.
1076                                  */
1077                                 tbuf[0] = c;
1078                                 tbuf[1] = '\0';
1079                                 cbuf = tbuf;
1080                         }
1081                         extra = NULL;
1082                         action = fcmd_decode(cbuf, &extra);
1083                         /*
1084                          * If an "extra" string was returned,
1085                          * process it as a string of command characters.
1086                          */
1087                         if (extra != NULL)
1088                                 ungetsc(extra);
1089                 }
1090                 /*
1091                  * Clear the cmdbuf string.
1092                  * (But not if we're in the prefix of a command,
1093                  * because the partial command string is kept there.)
1094                  */
1095                 if (action != A_PREFIX)
1096                         cmd_reset();
1097
1098                 switch (action)
1099                 {
1100                 case A_DIGIT:
1101                         /*
1102                          * First digit of a number.
1103                          */
1104                         start_mca(A_DIGIT, ":", (void*)NULL, CF_QUIT_ON_ERASE);
1105                         goto again;
1106
1107                 case A_F_WINDOW:
1108                         /*
1109                          * Forward one window (and set the window size).
1110                          */
1111                         if (number > 0)
1112                                 swindow = (int) number;
1113                         /* FALLTHRU */
1114                 case A_F_SCREEN:
1115                         /*
1116                          * Forward one screen.
1117                          */
1118                         if (number <= 0)
1119                                 number = get_swindow();
1120                         cmd_exec();
1121                         if (show_attn)
1122                                 set_attnpos(bottompos);
1123                         forward((int) number, 0, 1);
1124                         break;
1125
1126                 case A_B_WINDOW:
1127                         /*
1128                          * Backward one window (and set the window size).
1129                          */
1130                         if (number > 0)
1131                                 swindow = (int) number;
1132                         /* FALLTHRU */
1133                 case A_B_SCREEN:
1134                         /*
1135                          * Backward one screen.
1136                          */
1137                         if (number <= 0)
1138                                 number = get_swindow();
1139                         cmd_exec();
1140                         backward((int) number, 0, 1);
1141                         break;
1142
1143                 case A_F_LINE:
1144                         /*
1145                          * Forward N (default 1) line.
1146                          */
1147                         if (number <= 0)
1148                                 number = 1;
1149                         cmd_exec();
1150                         if (show_attn == OPT_ONPLUS && number > 1)
1151                                 set_attnpos(bottompos);
1152                         forward((int) number, 0, 0);
1153                         break;
1154
1155                 case A_B_LINE:
1156                         /*
1157                          * Backward N (default 1) line.
1158                          */
1159                         if (number <= 0)
1160                                 number = 1;
1161                         cmd_exec();
1162                         backward((int) number, 0, 0);
1163                         break;
1164
1165                 case A_FF_LINE:
1166                         /*
1167                          * Force forward N (default 1) line.
1168                          */
1169                         if (number <= 0)
1170                                 number = 1;
1171                         cmd_exec();
1172                         if (show_attn == OPT_ONPLUS && number > 1)
1173                                 set_attnpos(bottompos);
1174                         forward((int) number, 1, 0);
1175                         break;
1176
1177                 case A_BF_LINE:
1178                         /*
1179                          * Force backward N (default 1) line.
1180                          */
1181                         if (number <= 0)
1182                                 number = 1;
1183                         cmd_exec();
1184                         backward((int) number, 1, 0);
1185                         break;
1186                 
1187                 case A_FF_SCREEN:
1188                         /*
1189                          * Force forward one screen.
1190                          */
1191                         if (number <= 0)
1192                                 number = get_swindow();
1193                         cmd_exec();
1194                         if (show_attn == OPT_ONPLUS)
1195                                 set_attnpos(bottompos);
1196                         forward((int) number, 1, 0);
1197                         break;
1198
1199                 case A_F_FOREVER:
1200                         /*
1201                          * Forward forever, ignoring EOF.
1202                          */
1203                         if (ch_getflags() & CH_HELPFILE)
1204                                 break;
1205                         cmd_exec();
1206                         jump_forw();
1207                         ignore_eoi = 1;
1208                         while (!sigs)
1209                         {
1210                                 make_display();
1211                                 forward(1, 0, 0);
1212                         }
1213                         ignore_eoi = 0;
1214                         /*
1215                          * This gets us back in "F mode" after processing 
1216                          * a non-abort signal (e.g. window-change).  
1217                          */
1218                         if (sigs && !ABORT_SIGS())
1219                                 newaction = A_F_FOREVER;
1220                         break;
1221
1222                 case A_F_SCROLL:
1223                         /*
1224                          * Forward N lines 
1225                          * (default same as last 'd' or 'u' command).
1226                          */
1227                         if (number > 0)
1228                                 wscroll = (int) number;
1229                         cmd_exec();
1230                         if (show_attn == OPT_ONPLUS)
1231                                 set_attnpos(bottompos);
1232                         forward(wscroll, 0, 0);
1233                         break;
1234
1235                 case A_B_SCROLL:
1236                         /*
1237                          * Forward N lines 
1238                          * (default same as last 'd' or 'u' command).
1239                          */
1240                         if (number > 0)
1241                                 wscroll = (int) number;
1242                         cmd_exec();
1243                         backward(wscroll, 0, 0);
1244                         break;
1245
1246                 case A_FREPAINT:
1247                         /*
1248                          * Flush buffers, then repaint screen.
1249                          * Don't flush the buffers on a pipe!
1250                          */
1251                         clear_buffers();
1252                         /* FALLTHRU */
1253                 case A_REPAINT:
1254                         /*
1255                          * Repaint screen.
1256                          */
1257                         cmd_exec();
1258                         repaint();
1259                         break;
1260
1261                 case A_GOLINE:
1262                         /*
1263                          * Go to line N, default beginning of file.
1264                          */
1265                         if (number <= 0)
1266                                 number = 1;
1267                         cmd_exec();
1268                         jump_back(number);
1269                         break;
1270
1271                 case A_PERCENT:
1272                         /*
1273                          * Go to a specified percentage into the file.
1274                          */
1275                         if (number < 0)
1276                         {
1277                                 number = 0;
1278                                 fraction = 0;
1279                         }
1280                         if (number > 100)
1281                         {
1282                                 number = 100;
1283                                 fraction = 0;
1284                         }
1285                         cmd_exec();
1286                         jump_percent((int) number, fraction);
1287                         break;
1288
1289                 case A_GOEND:
1290                         /*
1291                          * Go to line N, default end of file.
1292                          */
1293                         cmd_exec();
1294                         if (number <= 0)
1295                                 jump_forw();
1296                         else
1297                                 jump_back(number);
1298                         break;
1299
1300                 case A_GOPOS:
1301                         /*
1302                          * Go to a specified byte position in the file.
1303                          */
1304                         cmd_exec();
1305                         if (number < 0)
1306                                 number = 0;
1307                         jump_line_loc((POSITION) number, jump_sline);
1308                         break;
1309
1310                 case A_STAT:
1311                         /*
1312                          * Print file name, etc.
1313                          */
1314                         if (ch_getflags() & CH_HELPFILE)
1315                                 break;
1316                         cmd_exec();
1317                         parg.p_string = eq_message();
1318                         error("%s", &parg);
1319                         break;
1320
1321                 case A_VERSION:
1322                         /*
1323                          * Print version number, without the "@(#)".
1324                          */
1325                         cmd_exec();
1326                         dispversion();
1327                         break;
1328
1329                 case A_QUIT:
1330                         /*
1331                          * Exit.
1332                          */
1333                         if (curr_ifile != NULL_IFILE && 
1334                             ch_getflags() & CH_HELPFILE)
1335                         {
1336                                 /*
1337                                  * Quit while viewing the help file
1338                                  * just means return to viewing the
1339                                  * previous file.
1340                                  */
1341                                 hshift = save_hshift;
1342                                 if (edit_prev(1) == 0)
1343                                         break;
1344                         }
1345                         if (extra != NULL)
1346                                 quit(*extra);
1347                         quit(QUIT_OK);
1348                         break;
1349
1350 /*
1351  * Define abbreviation for a commonly used sequence below.
1352  */
1353 #define DO_SEARCH() \
1354                         if (number <= 0) number = 1;    \
1355                         mca_search();                   \
1356                         cmd_exec();                     \
1357                         multi_search((char *)NULL, (int) number);
1358
1359
1360                 case A_F_SEARCH:
1361                         /*
1362                          * Search forward for a pattern.
1363                          * Get the first char of the pattern.
1364                          */
1365                         search_type = SRCH_FORW;
1366                         if (number <= 0)
1367                                 number = 1;
1368                         mca_search();
1369                         c = getcc();
1370                         goto again;
1371
1372                 case A_B_SEARCH:
1373                         /*
1374                          * Search backward for a pattern.
1375                          * Get the first char of the pattern.
1376                          */
1377                         search_type = SRCH_BACK;
1378                         if (number <= 0)
1379                                 number = 1;
1380                         mca_search();
1381                         c = getcc();
1382                         goto again;
1383
1384                 case A_FILTER:
1385 #if HILITE_SEARCH
1386                         search_type = SRCH_FORW | SRCH_FILTER;
1387                         mca_search();
1388                         c = getcc();
1389                         goto again;
1390 #else
1391                         error("Command not available", NULL_PARG);
1392                         break;
1393 #endif
1394
1395                 case A_AGAIN_SEARCH:
1396                         /*
1397                          * Repeat previous search.
1398                          */
1399                         DO_SEARCH();
1400                         break;
1401                 
1402                 case A_T_AGAIN_SEARCH:
1403                         /*
1404                          * Repeat previous search, multiple files.
1405                          */
1406                         search_type |= SRCH_PAST_EOF;
1407                         DO_SEARCH();
1408                         break;
1409
1410                 case A_REVERSE_SEARCH:
1411                         /*
1412                          * Repeat previous search, in reverse direction.
1413                          */
1414                         save_search_type = search_type;
1415                         search_type = SRCH_REVERSE(search_type);
1416                         DO_SEARCH();
1417                         search_type = save_search_type;
1418                         break;
1419
1420                 case A_T_REVERSE_SEARCH:
1421                         /* 
1422                          * Repeat previous search, 
1423                          * multiple files in reverse direction.
1424                          */
1425                         save_search_type = search_type;
1426                         search_type = SRCH_REVERSE(search_type);
1427                         search_type |= SRCH_PAST_EOF;
1428                         DO_SEARCH();
1429                         search_type = save_search_type;
1430                         break;
1431
1432                 case A_UNDO_SEARCH:
1433                         undo_search();
1434                         break;
1435
1436                 case A_HELP:
1437                         /*
1438                          * Help.
1439                          */
1440                         if (ch_getflags() & CH_HELPFILE)
1441                                 break;
1442                         cmd_exec();
1443                         save_hshift = hshift;
1444                         hshift = 0;
1445                         (void) edit(FAKE_HELPFILE);
1446                         break;
1447
1448                 case A_EXAMINE:
1449 #if EXAMINE
1450                         /*
1451                          * Edit a new file.  Get the filename.
1452                          */
1453                         if (secure)
1454                         {
1455                                 error("Command not available", NULL_PARG);
1456                                 break;
1457                         }
1458                         start_mca(A_EXAMINE, "Examine: ", ml_examine, 0);
1459                         c = getcc();
1460                         goto again;
1461 #else
1462                         error("Command not available", NULL_PARG);
1463                         break;
1464 #endif
1465                         
1466                 case A_VISUAL:
1467                         /*
1468                          * Invoke an editor on the input file.
1469                          */
1470 #if EDITOR
1471                         if (secure)
1472                         {
1473                                 error("Command not available", NULL_PARG);
1474                                 break;
1475                         }
1476                         if (ch_getflags() & CH_HELPFILE)
1477                                 break;
1478                         if (strcmp(get_filename(curr_ifile), "-") == 0)
1479                         {
1480                                 error("Cannot edit standard input", NULL_PARG);
1481                                 break;
1482                         }
1483                         if (curr_altfilename != NULL)
1484                         {
1485                                 error("WARNING: This file was viewed via LESSOPEN",
1486                                         NULL_PARG);
1487                         }
1488                         start_mca(A_SHELL, "!", ml_shell, 0);
1489                         /*
1490                          * Expand the editor prototype string
1491                          * and pass it to the system to execute.
1492                          * (Make sure the screen is displayed so the
1493                          * expansion of "+%lm" works.)
1494                          */
1495                         make_display();
1496                         cmd_exec();
1497                         lsystem(pr_expand(editproto, 0), (char*)NULL);
1498                         break;
1499 #else
1500                         error("Command not available", NULL_PARG);
1501                         break;
1502 #endif
1503
1504                 case A_NEXT_FILE:
1505                         /*
1506                          * Examine next file.
1507                          */
1508 #if TAGS
1509                         if (ntags())
1510                         {
1511                                 error("No next file", NULL_PARG);
1512                                 break;
1513                         }
1514 #endif
1515                         if (number <= 0)
1516                                 number = 1;
1517                         if (edit_next((int) number))
1518                         {
1519                                 if (get_quit_at_eof() && eof_displayed() && 
1520                                     !(ch_getflags() & CH_HELPFILE))
1521                                         quit(QUIT_OK);
1522                                 parg.p_string = (number > 1) ? "(N-th) " : "";
1523                                 error("No %snext file", &parg);
1524                         }
1525                         break;
1526
1527                 case A_PREV_FILE:
1528                         /*
1529                          * Examine previous file.
1530                          */
1531 #if TAGS
1532                         if (ntags())
1533                         {
1534                                 error("No previous file", NULL_PARG);
1535                                 break;
1536                         }
1537 #endif
1538                         if (number <= 0)
1539                                 number = 1;
1540                         if (edit_prev((int) number))
1541                         {
1542                                 parg.p_string = (number > 1) ? "(N-th) " : "";
1543                                 error("No %sprevious file", &parg);
1544                         }
1545                         break;
1546
1547                 case A_NEXT_TAG:
1548 #if TAGS
1549                         if (number <= 0)
1550                                 number = 1;
1551                         tagfile = nexttag((int) number);
1552                         if (tagfile == NULL)
1553                         {
1554                                 error("No next tag", NULL_PARG);
1555                                 break;
1556                         }
1557                         if (edit(tagfile) == 0)
1558                         {
1559                                 POSITION pos = tagsearch();
1560                                 if (pos != NULL_POSITION)
1561                                         jump_loc(pos, jump_sline);
1562                         }
1563 #else
1564                         error("Command not available", NULL_PARG);
1565 #endif
1566                         break;
1567
1568                 case A_PREV_TAG:
1569 #if TAGS
1570                         if (number <= 0)
1571                                 number = 1;
1572                         tagfile = prevtag((int) number);
1573                         if (tagfile == NULL)
1574                         {
1575                                 error("No previous tag", NULL_PARG);
1576                                 break;
1577                         }
1578                         if (edit(tagfile) == 0)
1579                         {
1580                                 POSITION pos = tagsearch();
1581                                 if (pos != NULL_POSITION)
1582                                         jump_loc(pos, jump_sline);
1583                         }
1584 #else
1585                         error("Command not available", NULL_PARG);
1586 #endif
1587                         break;
1588
1589                 case A_INDEX_FILE:
1590                         /*
1591                          * Examine a particular file.
1592                          */
1593                         if (number <= 0)
1594                                 number = 1;
1595                         if (edit_index((int) number))
1596                                 error("No such file", NULL_PARG);
1597                         break;
1598
1599                 case A_REMOVE_FILE:
1600                         if (ch_getflags() & CH_HELPFILE)
1601                                 break;
1602                         old_ifile = curr_ifile;
1603                         new_ifile = getoff_ifile(curr_ifile);
1604                         if (new_ifile == NULL_IFILE)
1605                         {
1606                                 bell();
1607                                 break;
1608                         }
1609                         if (edit_ifile(new_ifile) != 0)
1610                         {
1611                                 reedit_ifile(old_ifile);
1612                                 break;
1613                         }
1614                         del_ifile(old_ifile);
1615                         break;
1616
1617                 case A_OPT_TOGGLE:
1618                         optflag = OPT_TOGGLE;
1619                         optgetname = FALSE;
1620                         mca_opt_toggle();
1621                         c = getcc();
1622                         goto again;
1623
1624                 case A_DISP_OPTION:
1625                         /*
1626                          * Report a flag setting.
1627                          */
1628                         optflag = OPT_NO_TOGGLE;
1629                         optgetname = FALSE;
1630                         mca_opt_toggle();
1631                         c = getcc();
1632                         goto again;
1633
1634                 case A_FIRSTCMD:
1635                         /*
1636                          * Set an initial command for new files.
1637                          */
1638                         start_mca(A_FIRSTCMD, "+", (void*)NULL, 0);
1639                         c = getcc();
1640                         goto again;
1641
1642                 case A_SHELL:
1643                         /*
1644                          * Shell escape.
1645                          */
1646 #if SHELL_ESCAPE
1647                         if (secure)
1648                         {
1649                                 error("Command not available", NULL_PARG);
1650                                 break;
1651                         }
1652                         start_mca(A_SHELL, "!", ml_shell, 0);
1653                         c = getcc();
1654                         goto again;
1655 #else
1656                         error("Command not available", NULL_PARG);
1657                         break;
1658 #endif
1659
1660                 case A_SETMARK:
1661                         /*
1662                          * Set a mark.
1663                          */
1664                         if (ch_getflags() & CH_HELPFILE)
1665                                 break;
1666                         start_mca(A_SETMARK, "mark: ", (void*)NULL, 0);
1667                         c = getcc();
1668                         if (c == erase_char || c == erase2_char ||
1669                             c == kill_char || c == '\n' || c == '\r')
1670                                 break;
1671                         setmark(c);
1672                         break;
1673
1674                 case A_GOMARK:
1675                         /*
1676                          * Go to a mark.
1677                          */
1678                         start_mca(A_GOMARK, "goto mark: ", (void*)NULL, 0);
1679                         c = getcc();
1680                         if (c == erase_char || c == erase2_char ||
1681                             c == kill_char || c == '\n' || c == '\r')
1682                                 break;
1683                         cmd_exec();
1684                         gomark(c);
1685                         break;
1686
1687                 case A_PIPE:
1688 #if PIPEC
1689                         if (secure)
1690                         {
1691                                 error("Command not available", NULL_PARG);
1692                                 break;
1693                         }
1694                         start_mca(A_PIPE, "|mark: ", (void*)NULL, 0);
1695                         c = getcc();
1696                         if (c == erase_char || c == erase2_char || c == kill_char)
1697                                 break;
1698                         if (c == '\n' || c == '\r')
1699                                 c = '.';
1700                         if (badmark(c))
1701                                 break;
1702                         pipec = c;
1703                         start_mca(A_PIPE, "!", ml_shell, 0);
1704                         c = getcc();
1705                         goto again;
1706 #else
1707                         error("Command not available", NULL_PARG);
1708                         break;
1709 #endif
1710
1711                 case A_B_BRACKET:
1712                 case A_F_BRACKET:
1713                         start_mca(action, "Brackets: ", (void*)NULL, 0);
1714                         c = getcc();
1715                         goto again;
1716
1717                 case A_LSHIFT:
1718                         if (number > 0)
1719                                 shift_count = number;
1720                         else
1721                                 number = (shift_count > 0) ?
1722                                         shift_count : sc_width / 2;
1723                         if (number > hshift)
1724                                 number = hshift;
1725                         hshift -= number;
1726                         screen_trashed = 1;
1727                         break;
1728
1729                 case A_RSHIFT:
1730                         if (number > 0)
1731                                 shift_count = number;
1732                         else
1733                                 number = (shift_count > 0) ?
1734                                         shift_count : sc_width / 2;
1735                         hshift += number;
1736                         screen_trashed = 1;
1737                         break;
1738
1739                 case A_PREFIX:
1740                         /*
1741                          * The command is incomplete (more chars are needed).
1742                          * Display the current char, so the user knows
1743                          * what's going on, and get another character.
1744                          */
1745                         if (mca != A_PREFIX)
1746                         {
1747                                 cmd_reset();
1748                                 start_mca(A_PREFIX, " ", (void*)NULL,
1749                                         CF_QUIT_ON_ERASE);
1750                                 (void) cmd_char(c);
1751                         }
1752                         c = getcc();
1753                         goto again;
1754
1755                 case A_NOACTION:
1756                         break;
1757
1758                 default:
1759                         bell();
1760                         break;
1761                 }
1762         }
1763 }