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