Home | History | Annotate | Line # | Download | only in dist
      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  */
    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  */
    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  */
    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 
    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  */
    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 
    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
    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
    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  */
    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  */
    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  */
    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  */
    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*/
    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*/
    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*/
    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  */
    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 
    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*/
    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  */
    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  */
    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  */
    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*/
    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*/
    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*/
    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*/
    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*/
    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*/
    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*/
    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*/
    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*/
    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*/
   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*/
   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 
   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  */
   1092 public int get_swindow(void)
   1093 {
   1094 	if (swindow > 0)
   1095 		return (swindow);
   1096 	return (sc_height - header_lines + swindow);
   1097 }
   1098 
   1099