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