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