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