Bump to 608
[platform/upstream/less.git] / optfunc.c
1 /*
2  * Copyright (C) 1984-2022  Mark Nudelman
3  *
4  * You may distribute under the terms of either the GNU General Public
5  * License or the Less License, as specified in the README file.
6  *
7  * For more information, see the README file.
8  */
9
10
11 /*
12  * Handling functions for command line options.
13  *
14  * Most options are handled by the generic code in option.c.
15  * But all string options, and a few non-string options, require
16  * special handling specific to the particular option.
17  * This special processing is done by the "handling functions" in this file.
18  *
19  * Each handling function is passed a "type" and, if it is a string
20  * option, the string which should be "assigned" to the option.
21  * The type may be one of:
22  *      INIT    The option is being initialized from the command line.
23  *      TOGGLE  The option is being changed from within the program.
24  *      QUERY   The setting of the option is merely being queried.
25  */
26
27 #include "less.h"
28 #include "option.h"
29
30 extern int nbufs;
31 extern int bufspace;
32 extern int pr_type;
33 extern int plusoption;
34 extern int swindow;
35 extern int sc_width;
36 extern int sc_height;
37 extern int secure;
38 extern int dohelp;
39 extern int is_tty;
40 extern char openquote;
41 extern char closequote;
42 extern char *prproto[];
43 extern char *eqproto;
44 extern char *hproto;
45 extern char *wproto;
46 extern char *every_first_cmd;
47 extern IFILE curr_ifile;
48 extern char version[];
49 extern int jump_sline;
50 extern long jump_sline_fraction;
51 extern int shift_count;
52 extern long shift_count_fraction;
53 extern char rscroll_char;
54 extern int rscroll_attr;
55 extern int mousecap;
56 extern int wheel_lines;
57 extern int less_is_more;
58 extern int linenum_width;
59 extern int status_col_width;
60 extern int use_color;
61 extern int want_filesize;
62 extern int header_lines;
63 extern int header_cols;
64 extern int def_search_type;
65 extern int chopline;
66 #if LOGFILE
67 extern char *namelogfile;
68 extern int force_logfile;
69 extern int logfile;
70 #endif
71 #if TAGS
72 public char *tagoption = NULL;
73 extern char *tags;
74 extern char ztags[];
75 #endif
76 #if LESSTEST
77 extern char *ttyin_name;
78 extern int rstat_file;
79 #endif /*LESSTEST*/
80 #if MSDOS_COMPILER
81 extern int nm_fg_color, nm_bg_color;
82 extern int bo_fg_color, bo_bg_color;
83 extern int ul_fg_color, ul_bg_color;
84 extern int so_fg_color, so_bg_color;
85 extern int bl_fg_color, bl_bg_color;
86 extern int sgr_mode;
87 #if MSDOS_COMPILER==WIN32C
88 #ifndef COMMON_LVB_UNDERSCORE
89 #define COMMON_LVB_UNDERSCORE 0x8000
90 #endif
91 #endif
92 #endif
93
94
95 #if LOGFILE
96 /*
97  * Handler for -o option.
98  */
99         public void
100 opt_o(type, s)
101         int type;
102         char *s;
103 {
104         PARG parg;
105         char *filename;
106
107         if (secure)
108         {
109                 error("log file support is not available", NULL_PARG);
110                 return;
111         }
112         switch (type)
113         {
114         case INIT:
115                 namelogfile = save(s);
116                 break;
117         case TOGGLE:
118                 if (ch_getflags() & CH_CANSEEK)
119                 {
120                         error("Input is not a pipe", NULL_PARG);
121                         return;
122                 }
123                 if (logfile >= 0)
124                 {
125                         error("Log file is already in use", NULL_PARG);
126                         return;
127                 }
128                 s = skipsp(s);
129                 if (namelogfile != NULL)
130                         free(namelogfile);
131                 filename = lglob(s);
132                 namelogfile = shell_unquote(filename);
133                 free(filename);
134                 use_logfile(namelogfile);
135                 sync_logfile();
136                 break;
137         case QUERY:
138                 if (logfile < 0)
139                         error("No log file", NULL_PARG);
140                 else
141                 {
142                         parg.p_string = namelogfile;
143                         error("Log file \"%s\"", &parg);
144                 }
145                 break;
146         }
147 }
148
149 /*
150  * Handler for -O option.
151  */
152         public void
153 opt__O(type, s)
154         int type;
155         char *s;
156 {
157         force_logfile = TRUE;
158         opt_o(type, s);
159 }
160 #endif
161
162 /*
163  * Handlers for -j option.
164  */
165         public void
166 opt_j(type, s)
167         int type;
168         char *s;
169 {
170         PARG parg;
171         int len;
172         int err;
173
174         switch (type)
175         {
176         case INIT:
177         case TOGGLE:
178                 if (*s == '.')
179                 {
180                         s++;
181                         jump_sline_fraction = getfraction(&s, "j", &err);
182                         if (err)
183                                 error("Invalid line fraction", NULL_PARG);
184                         else
185                                 calc_jump_sline();
186                 } else
187                 {
188                         int sline = getnum(&s, "j", &err);
189                         if (err)
190                                 error("Invalid line number", NULL_PARG);
191                         else
192                         {
193                                 jump_sline = sline;
194                                 jump_sline_fraction = -1;
195                         }
196                 }
197                 break;
198         case QUERY:
199                 if (jump_sline_fraction < 0)
200                 {
201                         parg.p_int =  jump_sline;
202                         error("Position target at screen line %d", &parg);
203                 } else
204                 {
205                         char buf[24];
206                         SNPRINTF1(buf, sizeof(buf), ".%06ld", jump_sline_fraction);
207                         len = (int) strlen(buf);
208                         while (len > 2 && buf[len-1] == '0')
209                                 len--;
210                         buf[len] = '\0';
211                         parg.p_string = buf;
212                         error("Position target at screen position %s", &parg);
213                 }
214                 break;
215         }
216 }
217
218         public void
219 calc_jump_sline(VOID_PARAM)
220 {
221         if (jump_sline_fraction < 0)
222                 return;
223         jump_sline = sc_height * jump_sline_fraction / NUM_FRAC_DENOM;
224 }
225
226 /*
227  * Handlers for -# option.
228  */
229         public void
230 opt_shift(type, s)
231         int type;
232         char *s;
233 {
234         PARG parg;
235         int len;
236         int err;
237
238         switch (type)
239         {
240         case INIT:
241         case TOGGLE:
242                 if (*s == '.')
243                 {
244                         s++;
245                         shift_count_fraction = getfraction(&s, "#", &err);
246                         if (err)
247                                 error("Invalid column fraction", NULL_PARG);
248                         else
249                                 calc_shift_count();
250                 } else
251                 {
252                         int hs = getnum(&s, "#", &err);
253                         if (err)
254                                 error("Invalid column number", NULL_PARG);
255                         else
256                         {
257                                 shift_count = hs;
258                                 shift_count_fraction = -1;
259                         }
260                 }
261                 break;
262         case QUERY:
263                 if (shift_count_fraction < 0)
264                 {
265                         parg.p_int = shift_count;
266                         error("Horizontal shift %d columns", &parg);
267                 } else
268                 {
269                         char buf[24];
270                         SNPRINTF1(buf, sizeof(buf), ".%06ld", shift_count_fraction);
271                         len = (int) strlen(buf);
272                         while (len > 2 && buf[len-1] == '0')
273                                 len--;
274                         buf[len] = '\0';
275                         parg.p_string = buf;
276                         error("Horizontal shift %s of screen width", &parg);
277                 }
278                 break;
279         }
280 }
281
282         public void
283 calc_shift_count(VOID_PARAM)
284 {
285         if (shift_count_fraction < 0)
286                 return;
287         shift_count = sc_width * shift_count_fraction / NUM_FRAC_DENOM;
288 }
289
290 #if USERFILE
291         public void
292 opt_k(type, s)
293         int type;
294         char *s;
295 {
296         PARG parg;
297
298         switch (type)
299         {
300         case INIT:
301                 if (lesskey(s, 0))
302                 {
303                         parg.p_string = s;
304                         error("Cannot use lesskey file \"%s\"", &parg);
305                 }
306                 break;
307         }
308 }
309
310 #if HAVE_LESSKEYSRC 
311         public void
312 opt_ks(type, s)
313         int type;
314         char *s;
315 {
316         PARG parg;
317
318         switch (type)
319         {
320         case INIT:
321                 if (lesskey_src(s, 0))
322                 {
323                         parg.p_string = s;
324                         error("Cannot use lesskey source file \"%s\"", &parg);
325                 }
326                 break;
327         }
328 }
329 #endif /* HAVE_LESSKEYSRC */
330 #endif /* USERFILE */
331
332 #if TAGS
333 /*
334  * Handler for -t option.
335  */
336         public void
337 opt_t(type, s)
338         int type;
339         char *s;
340 {
341         IFILE save_ifile;
342         POSITION pos;
343
344         switch (type)
345         {
346         case INIT:
347                 tagoption = save(s);
348                 /* Do the rest in main() */
349                 break;
350         case TOGGLE:
351                 if (secure)
352                 {
353                         error("tags support is not available", NULL_PARG);
354                         break;
355                 }
356                 findtag(skipsp(s));
357                 save_ifile = save_curr_ifile();
358                 /*
359                  * Try to open the file containing the tag
360                  * and search for the tag in that file.
361                  */
362                 if (edit_tagfile() || (pos = tagsearch()) == NULL_POSITION)
363                 {
364                         /* Failed: reopen the old file. */
365                         reedit_ifile(save_ifile);
366                         break;
367                 }
368                 unsave_ifile(save_ifile);
369                 jump_loc(pos, jump_sline);
370                 break;
371         }
372 }
373
374 /*
375  * Handler for -T option.
376  */
377         public void
378 opt__T(type, s)
379         int type;
380         char *s;
381 {
382         PARG parg;
383         char *filename;
384
385         switch (type)
386         {
387         case INIT:
388                 tags = save(s);
389                 break;
390         case TOGGLE:
391                 s = skipsp(s);
392                 if (tags != NULL && tags != ztags)
393                         free(tags);
394                 filename = lglob(s);
395                 tags = shell_unquote(filename);
396                 free(filename);
397                 break;
398         case QUERY:
399                 parg.p_string = tags;
400                 error("Tags file \"%s\"", &parg);
401                 break;
402         }
403 }
404 #endif
405
406 /*
407  * Handler for -p option.
408  */
409         public void
410 opt_p(type, s)
411         int type;
412         char *s;
413 {
414         switch (type)
415         {
416         case INIT:
417                 /*
418                  * Unget a command for the specified string.
419                  */
420                 if (less_is_more)
421                 {
422                         /*
423                          * In "more" mode, the -p argument is a command,
424                          * not a search string, so we don't need a slash.
425                          */
426                         every_first_cmd = save(s);
427                 } else
428                 {
429                         plusoption = TRUE;
430                          /*
431                           * {{ This won't work if the "/" command is
432                           *    changed or invalidated by a .lesskey file. }}
433                           */
434                         ungetsc("/");
435                         ungetsc(s);
436                         ungetcc_back(CHAR_END_COMMAND);
437                 }
438                 break;
439         }
440 }
441
442 /*
443  * Handler for -P option.
444  */
445         public void
446 opt__P(type, s)
447         int type;
448         char *s;
449 {
450         char **proto;
451         PARG parg;
452
453         switch (type)
454         {
455         case INIT:
456         case TOGGLE:
457                 /*
458                  * Figure out which prototype string should be changed.
459                  */
460                 switch (*s)
461                 {
462                 case 's':  proto = &prproto[PR_SHORT];  s++;    break;
463                 case 'm':  proto = &prproto[PR_MEDIUM]; s++;    break;
464                 case 'M':  proto = &prproto[PR_LONG];   s++;    break;
465                 case '=':  proto = &eqproto;            s++;    break;
466                 case 'h':  proto = &hproto;             s++;    break;
467                 case 'w':  proto = &wproto;             s++;    break;
468                 default:   proto = &prproto[PR_SHORT];          break;
469                 }
470                 free(*proto);
471                 *proto = save(s);
472                 break;
473         case QUERY:
474                 parg.p_string = prproto[pr_type];
475                 error("%s", &parg);
476                 break;
477         }
478 }
479
480 /*
481  * Handler for the -b option.
482  */
483         /*ARGSUSED*/
484         public void
485 opt_b(type, s)
486         int type;
487         char *s;
488 {
489         switch (type)
490         {
491         case INIT:
492         case TOGGLE:
493                 /*
494                  * Set the new number of buffers.
495                  */
496                 ch_setbufspace(bufspace);
497                 break;
498         case QUERY:
499                 break;
500         }
501 }
502
503 /*
504  * Handler for the -i option.
505  */
506         /*ARGSUSED*/
507         public void
508 opt_i(type, s)
509         int type;
510         char *s;
511 {
512         switch (type)
513         {
514         case TOGGLE:
515                 chg_caseless();
516                 break;
517         case QUERY:
518         case INIT:
519                 break;
520         }
521 }
522
523 /*
524  * Handler for the -V option.
525  */
526         /*ARGSUSED*/
527         public void
528 opt__V(type, s)
529         int type;
530         char *s;
531 {
532         switch (type)
533         {
534         case TOGGLE:
535         case QUERY:
536                 dispversion();
537                 break;
538         case INIT:
539                 set_output(1); /* Force output to stdout per GNU standard for --version output. */
540                 putstr("less ");
541                 putstr(version);
542                 putstr(" (");
543                 putstr(pattern_lib_name());
544                 putstr(" regular expressions)\n");
545                 {
546                         char constant *copyright = 
547                                 "Copyright (C) 1984-2022  Mark Nudelman\n\n";
548                         putstr(copyright);
549                 }
550                 if (version[strlen(version)-1] == 'x')
551                 {
552                         putstr("** This is an EXPERIMENTAL build of the 'less' software,\n");
553                         putstr("** and may not function correctly.\n");
554                         putstr("** Obtain release builds from the web page below.\n\n");
555                 }
556                 putstr("less comes with NO WARRANTY, to the extent permitted by law.\n");
557                 putstr("For information about the terms of redistribution,\n");
558                 putstr("see the file named README in the less distribution.\n");
559                 putstr("Home page: https://greenwoodsoftware.com/less\n");
560                 quit(QUIT_OK);
561                 break;
562         }
563 }
564
565 #if MSDOS_COMPILER
566 /*
567  * Parse an MSDOS color descriptor.
568  */
569         static void
570 colordesc(s, fg_color, bg_color)
571         char *s;
572         int *fg_color;
573         int *bg_color;
574 {
575         int fg, bg;
576 #if MSDOS_COMPILER==WIN32C
577         int ul = 0;
578  
579         if (*s == 'u')
580         {
581                 ul = COMMON_LVB_UNDERSCORE;
582                 s++;
583                 if (*s == '\0')
584                 {
585                         *fg_color = nm_fg_color | ul;
586                         *bg_color = nm_bg_color;
587                         return;
588                 }
589         }
590 #endif
591         if (parse_color(s, &fg, &bg) == CT_NULL)
592         {
593                 PARG p;
594                 p.p_string = s;
595                 error("Invalid color string \"%s\"", &p);
596         } else
597         {
598                 if (fg == CV_NOCHANGE)
599                         fg = nm_fg_color;
600                 if (bg == CV_NOCHANGE)
601                         bg = nm_bg_color;
602 #if MSDOS_COMPILER==WIN32C
603                 fg |= ul;
604 #endif
605                 *fg_color = fg;
606                 *bg_color = bg;
607         }
608 }
609 #endif
610
611         static int
612 color_from_namechar(namechar)
613         char namechar;
614 {
615         switch (namechar)
616         {
617         case 'B': return AT_COLOR_BIN;
618         case 'C': return AT_COLOR_CTRL;
619         case 'E': return AT_COLOR_ERROR;
620         case 'H': return AT_COLOR_HEADER;
621         case 'M': return AT_COLOR_MARK;
622         case 'N': return AT_COLOR_LINENUM;
623         case 'P': return AT_COLOR_PROMPT;
624         case 'R': return AT_COLOR_RSCROLL;
625         case 'S': return AT_COLOR_SEARCH;
626         case 'W': case 'A': return AT_COLOR_ATTN;
627         case 'n': return AT_NORMAL;
628         case 's': return AT_STANDOUT;
629         case 'd': return AT_BOLD;
630         case 'u': return AT_UNDERLINE;
631         case 'k': return AT_BLINK;
632         default:  return -1;
633         }
634 }
635
636 /*
637  * Handler for the -D option.
638  */
639         /*ARGSUSED*/
640         public void
641 opt_D(type, s)
642         int type;
643         char *s;
644 {
645         PARG p;
646         int attr;
647
648         switch (type)
649         {
650         case INIT:
651         case TOGGLE:
652 #if MSDOS_COMPILER
653                 if (*s == 'a')
654                 {
655                         sgr_mode = !sgr_mode;
656                         break;
657                 }
658 #endif
659                 attr = color_from_namechar(s[0]);
660                 if (attr < 0)
661                 {
662                         p.p_char = s[0];
663                         error("Invalid color specifier '%c'", &p);
664                         return;
665                 }
666                 if (!use_color && (attr & AT_COLOR))
667                 {
668                         error("Set --use-color before changing colors", NULL_PARG);
669                         return;
670                 }
671                 s++;
672 #if MSDOS_COMPILER
673                 if (!(attr & AT_COLOR))
674                 {
675                         switch (attr)
676                         {
677                         case AT_NORMAL:
678                                 colordesc(s, &nm_fg_color, &nm_bg_color);
679                                 break;
680                         case AT_BOLD:
681                                 colordesc(s, &bo_fg_color, &bo_bg_color);
682                                 break;
683                         case AT_UNDERLINE:
684                                 colordesc(s, &ul_fg_color, &ul_bg_color);
685                                 break;
686                         case AT_BLINK:
687                                 colordesc(s, &bl_fg_color, &bl_bg_color);
688                                 break;
689                         case AT_STANDOUT:
690                                 colordesc(s, &so_fg_color, &so_bg_color);
691                                 break;
692                         }
693                         if (type == TOGGLE)
694                         {
695                                 at_enter(AT_STANDOUT);
696                                 at_exit();
697                         }
698                 } else
699 #endif
700                 if (set_color_map(attr, s) < 0)
701                 {
702                         p.p_string = s;
703                         error("Invalid color string \"%s\"", &p);
704                         return;
705                 }
706                 break;
707 #if MSDOS_COMPILER
708         case QUERY:
709                 p.p_string = (sgr_mode) ? "on" : "off";
710                 error("SGR mode is %s", &p);
711                 break;
712 #endif
713         }
714 }
715
716 /*
717  * Handler for the -x option.
718  */
719         public void
720 opt_x(type, s)
721         int type;
722         char *s;
723 {
724         extern int tabstops[];
725         extern int ntabstops;
726         extern int tabdefault;
727         char msg[60+((INT_STRLEN_BOUND(int)+1)*TABSTOP_MAX)];
728         int i;
729         PARG p;
730
731         switch (type)
732         {
733         case INIT:
734         case TOGGLE:
735                 /* Start at 1 because tabstops[0] is always zero. */
736                 for (i = 1;  i < TABSTOP_MAX;  )
737                 {
738                         int n = 0;
739                         s = skipsp(s);
740                         while (*s >= '0' && *s <= '9')
741                                 n = (10 * n) + (*s++ - '0');
742                         if (n > tabstops[i-1])
743                                 tabstops[i++] = n;
744                         s = skipsp(s);
745                         if (*s++ != ',')
746                                 break;
747                 }
748                 if (i < 2)
749                         return;
750                 ntabstops = i;
751                 tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2];
752                 break;
753         case QUERY:
754                 strcpy(msg, "Tab stops ");
755                 if (ntabstops > 2)
756                 {
757                         for (i = 1;  i < ntabstops;  i++)
758                         {
759                                 if (i > 1)
760                                         strcat(msg, ",");
761                                 sprintf(msg+strlen(msg), "%d", tabstops[i]);
762                         }
763                         sprintf(msg+strlen(msg), " and then ");
764                 }
765                 sprintf(msg+strlen(msg), "every %d spaces",
766                         tabdefault);
767                 p.p_string = msg;
768                 error("%s", &p);
769                 break;
770         }
771 }
772
773
774 /*
775  * Handler for the -" option.
776  */
777         public void
778 opt_quote(type, s)
779         int type;
780         char *s;
781 {
782         char buf[3];
783         PARG parg;
784
785         switch (type)
786         {
787         case INIT:
788         case TOGGLE:
789                 if (s[0] == '\0')
790                 {
791                         openquote = closequote = '\0';
792                         break;
793                 }
794                 if (s[1] != '\0' && s[2] != '\0')
795                 {
796                         error("-\" must be followed by 1 or 2 chars", NULL_PARG);
797                         return;
798                 }
799                 openquote = s[0];
800                 if (s[1] == '\0')
801                         closequote = openquote;
802                 else
803                         closequote = s[1];
804                 break;
805         case QUERY:
806                 buf[0] = openquote;
807                 buf[1] = closequote;
808                 buf[2] = '\0';
809                 parg.p_string = buf;
810                 error("quotes %s", &parg);
811                 break;
812         }
813 }
814
815 /*
816  * Handler for the --rscroll option.
817  */
818         /*ARGSUSED*/
819         public void
820 opt_rscroll(type, s)
821         int type;
822         char *s;
823 {
824         PARG p;
825
826         switch (type)
827         {
828         case INIT:
829         case TOGGLE: {
830                 char *fmt;
831                 int attr = AT_STANDOUT;
832                 setfmt(s, &fmt, &attr, "*s>");
833                 if (strcmp(fmt, "-") == 0)
834                 {
835                         rscroll_char = 0;
836                 } else
837                 {
838                         rscroll_char = *fmt ? *fmt : '>';
839                         rscroll_attr = attr|AT_COLOR_RSCROLL;
840                 }
841                 break; }
842         case QUERY: {
843                 p.p_string = rscroll_char ? prchar(rscroll_char) : "-";
844                 error("rscroll char is %s", &p);
845                 break; }
846         }
847 }
848
849 /*
850  * "-?" means display a help message.
851  * If from the command line, exit immediately.
852  */
853         /*ARGSUSED*/
854         public void
855 opt_query(type, s)
856         int type;
857         char *s;
858 {
859         switch (type)
860         {
861         case QUERY:
862         case TOGGLE:
863                 error("Use \"h\" for help", NULL_PARG);
864                 break;
865         case INIT:
866                 dohelp = 1;
867         }
868 }
869
870 /*
871  * Handler for the --mouse option.
872  */
873         /*ARGSUSED*/
874         public void
875 opt_mousecap(type, s)
876         int type;
877         char *s;
878 {
879         switch (type)
880         {
881         case TOGGLE:
882                 if (mousecap == OPT_OFF)
883                         deinit_mouse();
884                 else
885                         init_mouse();
886                 break;
887         case INIT:
888         case QUERY:
889                 break;
890         }
891 }
892
893 /*
894  * Handler for the --wheel-lines option.
895  */
896         /*ARGSUSED*/
897         public void
898 opt_wheel_lines(type, s)
899         int type;
900         char *s;
901 {
902         switch (type)
903         {
904         case INIT:
905         case TOGGLE:
906                 if (wheel_lines <= 0)
907                         wheel_lines = default_wheel_lines();
908                 break;
909         case QUERY:
910                 break;
911         }
912 }
913
914 /*
915  * Handler for the --line-number-width option.
916  */
917         /*ARGSUSED*/
918         public void
919 opt_linenum_width(type, s)
920         int type;
921         char *s;
922 {
923         PARG parg;
924
925         switch (type)
926         {
927         case INIT:
928         case TOGGLE:
929                 if (linenum_width > MAX_LINENUM_WIDTH)
930                 {
931                         parg.p_int = MAX_LINENUM_WIDTH;
932                         error("Line number width must not be larger than %d", &parg);
933                         linenum_width = MIN_LINENUM_WIDTH;
934                 } 
935                 break;
936         case QUERY:
937                 break;
938         }
939 }
940
941 /*
942  * Handler for the --status-column-width option.
943  */
944         /*ARGSUSED*/
945         public void
946 opt_status_col_width(type, s)
947         int type;
948         char *s;
949 {
950         PARG parg;
951
952         switch (type)
953         {
954         case INIT:
955         case TOGGLE:
956                 if (status_col_width > MAX_STATUSCOL_WIDTH)
957                 {
958                         parg.p_int = MAX_STATUSCOL_WIDTH;
959                         error("Status column width must not be larger than %d", &parg);
960                         status_col_width = 2;
961                 }
962                 break;
963         case QUERY:
964                 break;
965         }
966 }
967
968 /*
969  * Handler for the --file-size option.
970  */
971         /*ARGSUSED*/
972         public void
973 opt_filesize(type, s)
974         int type;
975         char *s;
976 {
977         switch (type)
978         {
979         case INIT:
980         case TOGGLE:
981                 if (want_filesize && curr_ifile != NULL && ch_length() == NULL_POSITION)
982                         scan_eof();
983                 break;
984         case QUERY:
985                 break;
986         }
987 }
988
989 /*
990  * Handler for the --header option.
991  */
992         /*ARGSUSED*/
993         public void
994 opt_header(type, s)
995         int type;
996         char *s;
997 {
998         int err;
999         int n;
1000
1001         switch (type)
1002         {
1003         case INIT:
1004         case TOGGLE:
1005                 n = getnum(&s, "header", &err);
1006                 if (err)
1007                         error("invalid number of lines", NULL_PARG);
1008                 else
1009                 {
1010                         header_lines = n;
1011                         header_cols = 0;
1012                         if (*s == ',')
1013                         {
1014                                 ++s;
1015                                 n = getnum(&s, "header", &err);
1016                                 if (err)
1017                                         error("invalid number of columns", NULL_PARG);
1018                                 else
1019                                         header_cols = n;
1020                         }
1021                 }
1022                 break;
1023         case QUERY:
1024                 {
1025                         char buf[2*INT_STRLEN_BOUND(int)+2];
1026                         PARG parg;
1027                         SNPRINTF2(buf, sizeof(buf), "%d,%d", header_lines, header_cols);
1028                         parg.p_string = buf;
1029                         error("header (lines,columns) is %s", &parg);
1030                 }
1031                 break;
1032         }
1033 }
1034
1035 /*
1036  * Handler for the --search-options option.
1037  */
1038         /*ARGSUSED*/
1039         public void
1040 opt_search_type(type, s)
1041         int type;
1042         char *s;
1043 {
1044         int st;
1045         PARG parg;
1046         char buf[16];
1047         char *bp;
1048
1049         switch (type)
1050         {
1051         case INIT:
1052         case TOGGLE:
1053                 st = 0;
1054                 for (;  *s != '\0';  s++)
1055                 {
1056                         switch (*s)
1057                         {
1058                         case 'E': case 'e': case CONTROL('E'): st |= SRCH_PAST_EOF;   break;
1059                         case 'F': case 'f': case CONTROL('F'): st |= SRCH_FIRST_FILE; break;
1060                         case 'K': case 'k': case CONTROL('K'): st |= SRCH_NO_MOVE;    break;
1061                         case 'N': case 'n': case CONTROL('N'): st |= SRCH_NO_MATCH;   break;
1062                         case 'R': case 'r': case CONTROL('R'): st |= SRCH_NO_REGEX;   break;
1063                         case 'W': case 'w': case CONTROL('W'): st |= SRCH_WRAP;       break;
1064                         case '-': st = 0; break;
1065                         case '^': break;
1066                         default:
1067                                 parg.p_char = *s;
1068                                 error("invalid search option '%c'", &parg);
1069                                 return;
1070                         }
1071                 }
1072                 def_search_type = norm_search_type(st);
1073                 break;
1074         case QUERY:
1075                 bp = buf;
1076                 if (def_search_type & SRCH_PAST_EOF)   *bp++ = 'E'; 
1077                 if (def_search_type & SRCH_FIRST_FILE) *bp++ = 'F'; 
1078                 if (def_search_type & SRCH_NO_MOVE)    *bp++ = 'K'; 
1079                 if (def_search_type & SRCH_NO_MATCH)   *bp++ = 'N'; 
1080                 if (def_search_type & SRCH_NO_REGEX)   *bp++ = 'R'; 
1081                 if (def_search_type & SRCH_WRAP)       *bp++ = 'W'; 
1082                 if (bp == buf)
1083                         *bp++ = '-';
1084                 *bp = '\0';
1085                 parg.p_string = buf;
1086                 error("search options: %s", &parg);
1087                 break;
1088         }
1089 }
1090
1091 #if LESSTEST
1092 /*
1093  * Handler for the --tty option.
1094  */
1095         /*ARGSUSED*/
1096         public void
1097 opt_ttyin_name(type, s)
1098         int type;
1099         char *s;
1100 {
1101         switch (type)
1102         {
1103         case INIT:
1104                 ttyin_name = s;
1105                 is_tty = 1;
1106                 break;
1107         }
1108 }
1109
1110 /*
1111  * Handler for the --rstat option.
1112  */
1113         /*ARGSUSED*/
1114         public void
1115 opt_rstat(type, s)
1116         int type;
1117         char *s;
1118 {
1119         switch (type)
1120         {
1121         case INIT:
1122                 rstat_file = open(s, O_WRONLY|O_CREAT, 0664);
1123                 if (rstat_file < 0)
1124                 {
1125                         PARG parg;
1126                         parg.p_string = s;
1127                         error("Cannot create rstat file \"%s\"", &parg);
1128                 }
1129                 break;
1130         }
1131 }
1132 #endif /*LESSTEST*/
1133
1134         public int
1135 chop_line(VOID_PARAM)
1136 {
1137         return (chopline || header_cols > 0 || header_lines > 0);
1138 }
1139
1140 /*
1141  * Get the "screen window" size.
1142  */
1143         public int
1144 get_swindow(VOID_PARAM)
1145 {
1146         if (swindow > 0)
1147                 return (swindow);
1148         return (sc_height - header_lines + swindow);
1149 }
1150