xref: /dragonfly/contrib/less/optfunc.c (revision e433da38)
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