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