xref: /freebsd/contrib/less/optfunc.c (revision c77c488926555ca344ae3a417544cf7a720e1de1)
1a5f0fb15SPaul Saab /*
2*c77c4889SXin LI  * Copyright (C) 1984-2024  Mark Nudelman
3a5f0fb15SPaul Saab  *
4a5f0fb15SPaul Saab  * You may distribute under the terms of either the GNU General Public
5a5f0fb15SPaul Saab  * License or the Less License, as specified in the README file.
6a5f0fb15SPaul Saab  *
796e55cc7SXin LI  * For more information, see the README file.
8a5f0fb15SPaul Saab  */
9a5f0fb15SPaul Saab 
10a5f0fb15SPaul Saab 
11a5f0fb15SPaul Saab /*
12a5f0fb15SPaul Saab  * Handling functions for command line options.
13a5f0fb15SPaul Saab  *
14a5f0fb15SPaul Saab  * Most options are handled by the generic code in option.c.
15a5f0fb15SPaul Saab  * But all string options, and a few non-string options, require
16a5f0fb15SPaul Saab  * special handling specific to the particular option.
17a5f0fb15SPaul Saab  * This special processing is done by the "handling functions" in this file.
18a5f0fb15SPaul Saab  *
19a5f0fb15SPaul Saab  * Each handling function is passed a "type" and, if it is a string
20a5f0fb15SPaul Saab  * option, the string which should be "assigned" to the option.
21a5f0fb15SPaul Saab  * The type may be one of:
22a5f0fb15SPaul Saab  *      INIT    The option is being initialized from the command line.
23a5f0fb15SPaul Saab  *      TOGGLE  The option is being changed from within the program.
24a5f0fb15SPaul Saab  *      QUERY   The setting of the option is merely being queried.
25a5f0fb15SPaul Saab  */
26a5f0fb15SPaul Saab 
27a5f0fb15SPaul Saab #include "less.h"
28a5f0fb15SPaul Saab #include "option.h"
29*c77c4889SXin LI #include "position.h"
30a5f0fb15SPaul Saab 
31000ba3e8STim J. Robbins extern int bufspace;
32a5f0fb15SPaul Saab extern int pr_type;
33*c77c4889SXin LI extern lbool plusoption;
34a5f0fb15SPaul Saab extern int swindow;
35f0be0a1fSXin LI extern int sc_width;
36a5f0fb15SPaul Saab extern int sc_height;
37a5f0fb15SPaul Saab extern int dohelp;
38a5f0fb15SPaul Saab extern char openquote;
39a5f0fb15SPaul Saab extern char closequote;
40a5f0fb15SPaul Saab extern char *prproto[];
41a5f0fb15SPaul Saab extern char *eqproto;
42a5f0fb15SPaul Saab extern char *hproto;
43c9346414SPaul Saab extern char *wproto;
44a15691bfSXin LI extern char *every_first_cmd;
45a5f0fb15SPaul Saab extern IFILE curr_ifile;
46a5f0fb15SPaul Saab extern char version[];
47efd72c2eSXin LI extern int jump_sline;
48f6b74a7dSXin LI extern long jump_sline_fraction;
49f0be0a1fSXin LI extern int shift_count;
50f6b74a7dSXin LI extern long shift_count_fraction;
51*c77c4889SXin LI extern int match_shift;
52*c77c4889SXin LI extern long match_shift_fraction;
53*c77c4889SXin LI extern LWCHAR rscroll_char;
54b2ea2440SXin LI extern int rscroll_attr;
55b7780dbeSXin LI extern int mousecap;
56b7780dbeSXin LI extern int wheel_lines;
57efd72c2eSXin LI extern int less_is_more;
582235c7feSXin LI extern int linenum_width;
592235c7feSXin LI extern int status_col_width;
602235c7feSXin LI extern int use_color;
6130a1828cSXin LI extern int want_filesize;
6295270f73SXin LI extern int header_lines;
6395270f73SXin LI extern int header_cols;
6495270f73SXin LI extern int def_search_type;
6595270f73SXin LI extern int chopline;
66d713e089SXin LI extern int tabstops[];
67d713e089SXin LI extern int ntabstops;
68d713e089SXin LI extern int tabdefault;
69d713e089SXin LI extern char intr_char;
70*c77c4889SXin LI extern int nosearch_header_lines;
71*c77c4889SXin LI extern int nosearch_header_cols;
72*c77c4889SXin LI extern POSITION header_start_pos;
73*c77c4889SXin LI extern char *init_header;
74a5f0fb15SPaul Saab #if LOGFILE
75a5f0fb15SPaul Saab extern char *namelogfile;
76*c77c4889SXin LI extern lbool force_logfile;
77a5f0fb15SPaul Saab extern int logfile;
78a5f0fb15SPaul Saab #endif
79a5f0fb15SPaul Saab #if TAGS
80a5f0fb15SPaul Saab public char *tagoption = NULL;
81a5f0fb15SPaul Saab extern char *tags;
82a15691bfSXin LI extern char ztags[];
83a5f0fb15SPaul Saab #endif
842235c7feSXin LI #if LESSTEST
85*c77c4889SXin LI extern constant char *ttyin_name;
86*c77c4889SXin LI extern int is_tty;
872235c7feSXin LI #endif /*LESSTEST*/
88a5f0fb15SPaul Saab #if MSDOS_COMPILER
89*c77c4889SXin LI extern int nm_fg_color, nm_bg_color, nm_attr;
90*c77c4889SXin LI extern int bo_fg_color, bo_bg_color, bo_attr;
91*c77c4889SXin LI extern int ul_fg_color, ul_bg_color, ul_attr;
92*c77c4889SXin LI extern int so_fg_color, so_bg_color, so_attr;
93*c77c4889SXin LI extern int bl_fg_color, bl_bg_color, bl_attr;
94f6b74a7dSXin LI extern int sgr_mode;
95b2ea2440SXin LI #if MSDOS_COMPILER==WIN32C
96b2ea2440SXin LI #ifndef COMMON_LVB_UNDERSCORE
97b2ea2440SXin LI #define COMMON_LVB_UNDERSCORE 0x8000
98b2ea2440SXin LI #endif
99*c77c4889SXin LI #ifndef COMMON_LVB_REVERSE_VIDEO
100*c77c4889SXin LI #define COMMON_LVB_REVERSE_VIDEO 0x4000
101*c77c4889SXin LI #endif
102b2ea2440SXin LI #endif
103a5f0fb15SPaul Saab #endif
104a5f0fb15SPaul Saab 
105a5f0fb15SPaul Saab 
106a5f0fb15SPaul Saab #if LOGFILE
107a5f0fb15SPaul Saab /*
108a5f0fb15SPaul Saab  * Handler for -o option.
109a5f0fb15SPaul Saab  */
110*c77c4889SXin LI public void opt_o(int type, constant char *s)
111a5f0fb15SPaul Saab {
112a5f0fb15SPaul Saab 	PARG parg;
113b2ea2440SXin LI 	char *filename;
114a5f0fb15SPaul Saab 
115*c77c4889SXin LI 	if (!secure_allow(SF_LOGFILE))
116a5f0fb15SPaul Saab 	{
117a5f0fb15SPaul Saab 		error("log file support is not available", NULL_PARG);
118a5f0fb15SPaul Saab 		return;
119a5f0fb15SPaul Saab 	}
120a5f0fb15SPaul Saab 	switch (type)
121a5f0fb15SPaul Saab 	{
122a5f0fb15SPaul Saab 	case INIT:
123a15691bfSXin LI 		namelogfile = save(s);
124a5f0fb15SPaul Saab 		break;
125a5f0fb15SPaul Saab 	case TOGGLE:
126a5f0fb15SPaul Saab 		if (ch_getflags() & CH_CANSEEK)
127a5f0fb15SPaul Saab 		{
128a5f0fb15SPaul Saab 			error("Input is not a pipe", NULL_PARG);
129a5f0fb15SPaul Saab 			return;
130a5f0fb15SPaul Saab 		}
131a5f0fb15SPaul Saab 		if (logfile >= 0)
132a5f0fb15SPaul Saab 		{
133a5f0fb15SPaul Saab 			error("Log file is already in use", NULL_PARG);
134a5f0fb15SPaul Saab 			return;
135a5f0fb15SPaul Saab 		}
136*c77c4889SXin LI 		s = skipspc(s);
137a15691bfSXin LI 		if (namelogfile != NULL)
138a15691bfSXin LI 			free(namelogfile);
139b2ea2440SXin LI 		filename = lglob(s);
140b2ea2440SXin LI 		namelogfile = shell_unquote(filename);
141b2ea2440SXin LI 		free(filename);
142a5f0fb15SPaul Saab 		use_logfile(namelogfile);
143a5f0fb15SPaul Saab 		sync_logfile();
144a5f0fb15SPaul Saab 		break;
145a5f0fb15SPaul Saab 	case QUERY:
146a5f0fb15SPaul Saab 		if (logfile < 0)
147a5f0fb15SPaul Saab 			error("No log file", NULL_PARG);
148a5f0fb15SPaul Saab 		else
149a5f0fb15SPaul Saab 		{
150000ba3e8STim J. Robbins 			parg.p_string = namelogfile;
151a5f0fb15SPaul Saab 			error("Log file \"%s\"", &parg);
152a5f0fb15SPaul Saab 		}
153a5f0fb15SPaul Saab 		break;
154a5f0fb15SPaul Saab 	}
155a5f0fb15SPaul Saab }
156a5f0fb15SPaul Saab 
157a5f0fb15SPaul Saab /*
158a5f0fb15SPaul Saab  * Handler for -O option.
159a5f0fb15SPaul Saab  */
160*c77c4889SXin LI public void opt__O(int type, constant char *s)
161a5f0fb15SPaul Saab {
162a5f0fb15SPaul Saab 	force_logfile = TRUE;
163a5f0fb15SPaul Saab 	opt_o(type, s);
164a5f0fb15SPaul Saab }
165a5f0fb15SPaul Saab #endif
166a5f0fb15SPaul Saab 
167*c77c4889SXin LI static int toggle_fraction(int *num, long *frac, constant char *s, constant char *printopt, void (*calc)(void))
1687f074f9cSXin LI {
169*c77c4889SXin LI 	lbool err;
170*c77c4889SXin LI 	if (s == NULL)
1717f074f9cSXin LI 	{
172*c77c4889SXin LI 		(*calc)();
173*c77c4889SXin LI 	} else if (*s == '.')
1747f074f9cSXin LI 	{
175*c77c4889SXin LI         long tfrac;
1767f074f9cSXin LI 		s++;
177*c77c4889SXin LI 		tfrac = getfraction(&s, printopt, &err);
1787f074f9cSXin LI 		if (err)
179*c77c4889SXin LI 		{
180*c77c4889SXin LI 			error("Invalid fraction", NULL_PARG);
181*c77c4889SXin LI 			return -1;
182*c77c4889SXin LI 		}
183*c77c4889SXin LI 		*frac = tfrac;
184*c77c4889SXin LI 		(*calc)();
1857f074f9cSXin LI 	} else
1867f074f9cSXin LI 	{
187*c77c4889SXin LI 		int tnum = getnumc(&s, printopt, &err);
1887f074f9cSXin LI 		if (err)
1897f074f9cSXin LI 		{
190*c77c4889SXin LI 			error("Invalid number", NULL_PARG);
191*c77c4889SXin LI 			return -1;
1927f074f9cSXin LI 		}
193*c77c4889SXin LI 		*frac = -1;
194*c77c4889SXin LI 		*num = tnum;
1957f074f9cSXin LI 	}
196*c77c4889SXin LI 	return 0;
197*c77c4889SXin LI }
198*c77c4889SXin LI 
199*c77c4889SXin LI static void query_fraction(int value, long fraction, constant char *int_msg, constant char *frac_msg)
2007f074f9cSXin LI {
201*c77c4889SXin LI 	PARG parg;
202*c77c4889SXin LI 
203*c77c4889SXin LI 	if (fraction < 0)
204*c77c4889SXin LI 	{
205*c77c4889SXin LI 		parg.p_int = value;
206*c77c4889SXin LI 		error(int_msg, &parg);
2077f074f9cSXin LI 	} else
2087f074f9cSXin LI 	{
209f80a33eaSXin LI 		char buf[INT_STRLEN_BOUND(long)+2];
210*c77c4889SXin LI 		size_t len;
211*c77c4889SXin LI 		SNPRINTF1(buf, sizeof(buf), ".%06ld", fraction);
212*c77c4889SXin LI 		len = strlen(buf);
2137f074f9cSXin LI 		while (len > 2 && buf[len-1] == '0')
2147f074f9cSXin LI 			len--;
2157f074f9cSXin LI 		buf[len] = '\0';
2167f074f9cSXin LI 		parg.p_string = buf;
217*c77c4889SXin LI 		error(frac_msg, &parg);
2187f074f9cSXin LI 	}
219*c77c4889SXin LI }
220*c77c4889SXin LI 
221*c77c4889SXin LI /*
222*c77c4889SXin LI  * Handlers for -j option.
223*c77c4889SXin LI  */
224*c77c4889SXin LI public void opt_j(int type, constant char *s)
225*c77c4889SXin LI {
226*c77c4889SXin LI 	switch (type)
227*c77c4889SXin LI 	{
228*c77c4889SXin LI 	case INIT:
229*c77c4889SXin LI 	case TOGGLE:
230*c77c4889SXin LI 		toggle_fraction(&jump_sline, &jump_sline_fraction,
231*c77c4889SXin LI 			s, "j", calc_jump_sline);
232*c77c4889SXin LI 		break;
233*c77c4889SXin LI 	case QUERY:
234*c77c4889SXin LI 		query_fraction(jump_sline, jump_sline_fraction,
235*c77c4889SXin LI 			"Position target at screen line %d", "Position target at screen position %s");
2367f074f9cSXin LI 		break;
2377f074f9cSXin LI 	}
2387f074f9cSXin LI }
2397f074f9cSXin LI 
240d713e089SXin LI public void calc_jump_sline(void)
2417f074f9cSXin LI {
242*c77c4889SXin LI 	if (jump_sline_fraction >= 0)
243f80a33eaSXin LI 		jump_sline = (int) muldiv(sc_height, jump_sline_fraction, NUM_FRAC_DENOM);
244*c77c4889SXin LI 	if (jump_sline <= header_lines)
245*c77c4889SXin LI 		jump_sline = header_lines + 1;
2467f074f9cSXin LI }
2477f074f9cSXin LI 
248f0be0a1fSXin LI /*
249f0be0a1fSXin LI  * Handlers for -# option.
250f0be0a1fSXin LI  */
251*c77c4889SXin LI public void opt_shift(int type, constant char *s)
252f0be0a1fSXin LI {
253f0be0a1fSXin LI 	switch (type)
254f0be0a1fSXin LI 	{
255f0be0a1fSXin LI 	case INIT:
256f0be0a1fSXin LI 	case TOGGLE:
257*c77c4889SXin LI 		toggle_fraction(&shift_count, &shift_count_fraction,
258*c77c4889SXin LI 			s, "#", calc_shift_count);
259f0be0a1fSXin LI 		break;
260f0be0a1fSXin LI 	case QUERY:
261*c77c4889SXin LI 		query_fraction(shift_count, shift_count_fraction,
262*c77c4889SXin LI 			"Horizontal shift %d columns", "Horizontal shift %s of screen width");
263f0be0a1fSXin LI 		break;
264f0be0a1fSXin LI 	}
265f0be0a1fSXin LI }
26630a1828cSXin LI 
267d713e089SXin LI public void calc_shift_count(void)
268f0be0a1fSXin LI {
269f0be0a1fSXin LI 	if (shift_count_fraction < 0)
270f0be0a1fSXin LI 		return;
271f80a33eaSXin LI 	shift_count = (int) muldiv(sc_width, shift_count_fraction, NUM_FRAC_DENOM);
272f0be0a1fSXin LI }
273f0be0a1fSXin LI 
274a5f0fb15SPaul Saab #if USERFILE
275*c77c4889SXin LI public void opt_k(int type, constant char *s)
276a5f0fb15SPaul Saab {
277a5f0fb15SPaul Saab 	PARG parg;
278a5f0fb15SPaul Saab 
279a5f0fb15SPaul Saab 	switch (type)
280a5f0fb15SPaul Saab 	{
281a5f0fb15SPaul Saab 	case INIT:
282a5f0fb15SPaul Saab 		if (lesskey(s, 0))
283a5f0fb15SPaul Saab 		{
284000ba3e8STim J. Robbins 			parg.p_string = s;
285a5f0fb15SPaul Saab 			error("Cannot use lesskey file \"%s\"", &parg);
286a5f0fb15SPaul Saab 		}
287a5f0fb15SPaul Saab 		break;
288a5f0fb15SPaul Saab 	}
289a5f0fb15SPaul Saab }
29030a1828cSXin LI 
29130a1828cSXin LI #if HAVE_LESSKEYSRC
292*c77c4889SXin LI public void opt_ks(int type, constant char *s)
29330a1828cSXin LI {
29430a1828cSXin LI 	PARG parg;
29530a1828cSXin LI 
29630a1828cSXin LI 	switch (type)
29730a1828cSXin LI 	{
29830a1828cSXin LI 	case INIT:
29930a1828cSXin LI 		if (lesskey_src(s, 0))
30030a1828cSXin LI 		{
30130a1828cSXin LI 			parg.p_string = s;
30230a1828cSXin LI 			error("Cannot use lesskey source file \"%s\"", &parg);
30330a1828cSXin LI 		}
30430a1828cSXin LI 		break;
30530a1828cSXin LI 	}
30630a1828cSXin LI }
307*c77c4889SXin LI 
308*c77c4889SXin LI public void opt_kc(int type, constant char *s)
309*c77c4889SXin LI {
310*c77c4889SXin LI 	switch (type)
311*c77c4889SXin LI 	{
312*c77c4889SXin LI 	case INIT:
313*c77c4889SXin LI 		if (lesskey_content(s, 0))
314*c77c4889SXin LI 		{
315*c77c4889SXin LI 			error("Error in lesskey content", NULL_PARG);
316*c77c4889SXin LI 		}
317*c77c4889SXin LI 		break;
318*c77c4889SXin LI 	}
319*c77c4889SXin LI }
320*c77c4889SXin LI 
32130a1828cSXin LI #endif /* HAVE_LESSKEYSRC */
32230a1828cSXin LI #endif /* USERFILE */
323a5f0fb15SPaul Saab 
324*c77c4889SXin LI /*
325*c77c4889SXin LI  * Handler for -S option.
326*c77c4889SXin LI  */
327*c77c4889SXin LI public void opt__S(int type, constant char *s)
328*c77c4889SXin LI {
329*c77c4889SXin LI 	switch (type)
330*c77c4889SXin LI 	{
331*c77c4889SXin LI 	case TOGGLE:
332*c77c4889SXin LI 		pos_rehead();
333*c77c4889SXin LI 		break;
334*c77c4889SXin LI 	}
335*c77c4889SXin LI }
336*c77c4889SXin LI 
337a5f0fb15SPaul Saab #if TAGS
338a5f0fb15SPaul Saab /*
339a5f0fb15SPaul Saab  * Handler for -t option.
340a5f0fb15SPaul Saab  */
341*c77c4889SXin LI public void opt_t(int type, constant char *s)
342a5f0fb15SPaul Saab {
343a5f0fb15SPaul Saab 	IFILE save_ifile;
344a5f0fb15SPaul Saab 	POSITION pos;
345a5f0fb15SPaul Saab 
346a5f0fb15SPaul Saab 	switch (type)
347a5f0fb15SPaul Saab 	{
348a5f0fb15SPaul Saab 	case INIT:
349a15691bfSXin LI 		tagoption = save(s);
350a5f0fb15SPaul Saab 		/* Do the rest in main() */
351a5f0fb15SPaul Saab 		break;
352a5f0fb15SPaul Saab 	case TOGGLE:
353*c77c4889SXin LI 		if (!secure_allow(SF_TAGS))
354a5f0fb15SPaul Saab 		{
355a5f0fb15SPaul Saab 			error("tags support is not available", NULL_PARG);
356a5f0fb15SPaul Saab 			break;
357a5f0fb15SPaul Saab 		}
358*c77c4889SXin LI 		findtag(skipspc(s));
359a5f0fb15SPaul Saab 		save_ifile = save_curr_ifile();
3606dcb072bSXin LI 		/*
3616dcb072bSXin LI 		 * Try to open the file containing the tag
3626dcb072bSXin LI 		 * and search for the tag in that file.
3636dcb072bSXin LI 		 */
3646dcb072bSXin LI 		if (edit_tagfile() || (pos = tagsearch()) == NULL_POSITION)
365a5f0fb15SPaul Saab 		{
3666dcb072bSXin LI 			/* Failed: reopen the old file. */
367a5f0fb15SPaul Saab 			reedit_ifile(save_ifile);
368a5f0fb15SPaul Saab 			break;
369a5f0fb15SPaul Saab 		}
370a5f0fb15SPaul Saab 		unsave_ifile(save_ifile);
371a5f0fb15SPaul Saab 		jump_loc(pos, jump_sline);
372a5f0fb15SPaul Saab 		break;
373a5f0fb15SPaul Saab 	}
374a5f0fb15SPaul Saab }
375a5f0fb15SPaul Saab 
376a5f0fb15SPaul Saab /*
377a5f0fb15SPaul Saab  * Handler for -T option.
378a5f0fb15SPaul Saab  */
379*c77c4889SXin LI public void opt__T(int type, constant char *s)
380a5f0fb15SPaul Saab {
381a5f0fb15SPaul Saab 	PARG parg;
382b2ea2440SXin LI 	char *filename;
383a5f0fb15SPaul Saab 
384a5f0fb15SPaul Saab 	switch (type)
385a5f0fb15SPaul Saab 	{
386a5f0fb15SPaul Saab 	case INIT:
387a15691bfSXin LI 		tags = save(s);
388a5f0fb15SPaul Saab 		break;
389a5f0fb15SPaul Saab 	case TOGGLE:
390*c77c4889SXin LI 		s = skipspc(s);
391a15691bfSXin LI 		if (tags != NULL && tags != ztags)
392a15691bfSXin LI 			free(tags);
393b2ea2440SXin LI 		filename = lglob(s);
394b2ea2440SXin LI 		tags = shell_unquote(filename);
395b2ea2440SXin LI 		free(filename);
396a5f0fb15SPaul Saab 		break;
397a5f0fb15SPaul Saab 	case QUERY:
398000ba3e8STim J. Robbins 		parg.p_string = tags;
399a5f0fb15SPaul Saab 		error("Tags file \"%s\"", &parg);
400a5f0fb15SPaul Saab 		break;
401a5f0fb15SPaul Saab 	}
402a5f0fb15SPaul Saab }
403a5f0fb15SPaul Saab #endif
404a5f0fb15SPaul Saab 
405a5f0fb15SPaul Saab /*
406a5f0fb15SPaul Saab  * Handler for -p option.
407a5f0fb15SPaul Saab  */
408*c77c4889SXin LI public void opt_p(int type, constant char *s)
409a5f0fb15SPaul Saab {
410a5f0fb15SPaul Saab 	switch (type)
411a5f0fb15SPaul Saab 	{
412a5f0fb15SPaul Saab 	case INIT:
413a5f0fb15SPaul Saab 		/*
414a15691bfSXin LI 		 * Unget a command for the specified string.
415a5f0fb15SPaul Saab 		 */
416a15691bfSXin LI 		if (less_is_more)
417a15691bfSXin LI 		{
4186dcb072bSXin LI 			/*
4196dcb072bSXin LI 			 * In "more" mode, the -p argument is a command,
4206dcb072bSXin LI 			 * not a search string, so we don't need a slash.
4216dcb072bSXin LI 			 */
422a15691bfSXin LI 			every_first_cmd = save(s);
423a15691bfSXin LI 		} else
424a15691bfSXin LI 		{
425a15691bfSXin LI 			plusoption = TRUE;
426a15691bfSXin LI 			 /*
427a15691bfSXin LI 			  * {{ This won't work if the "/" command is
428a15691bfSXin LI 			  *    changed or invalidated by a .lesskey file. }}
429a15691bfSXin LI 			  */
430a5f0fb15SPaul Saab 			ungetsc("/");
4312235c7feSXin LI 			ungetsc(s);
432*c77c4889SXin LI 			ungetcc_end_command();
433a15691bfSXin LI 		}
434a5f0fb15SPaul Saab 		break;
435a5f0fb15SPaul Saab 	}
436a5f0fb15SPaul Saab }
437a5f0fb15SPaul Saab 
438a5f0fb15SPaul Saab /*
439a5f0fb15SPaul Saab  * Handler for -P option.
440a5f0fb15SPaul Saab  */
441*c77c4889SXin LI public void opt__P(int type, constant char *s)
442a5f0fb15SPaul Saab {
4431ea31627SRobert Watson 	char **proto;
444a5f0fb15SPaul Saab 	PARG parg;
445a5f0fb15SPaul Saab 
446a5f0fb15SPaul Saab 	switch (type)
447a5f0fb15SPaul Saab 	{
448a5f0fb15SPaul Saab 	case INIT:
449a5f0fb15SPaul Saab 	case TOGGLE:
450a5f0fb15SPaul Saab 		/*
451a5f0fb15SPaul Saab 		 * Figure out which prototype string should be changed.
452a5f0fb15SPaul Saab 		 */
453a5f0fb15SPaul Saab 		switch (*s)
454a5f0fb15SPaul Saab 		{
455a5f0fb15SPaul Saab 		case 's':  proto = &prproto[PR_SHORT];  s++;    break;
456a5f0fb15SPaul Saab 		case 'm':  proto = &prproto[PR_MEDIUM]; s++;    break;
457a5f0fb15SPaul Saab 		case 'M':  proto = &prproto[PR_LONG];   s++;    break;
458a5f0fb15SPaul Saab 		case '=':  proto = &eqproto;            s++;    break;
459a5f0fb15SPaul Saab 		case 'h':  proto = &hproto;             s++;    break;
460c9346414SPaul Saab 		case 'w':  proto = &wproto;             s++;    break;
461a5f0fb15SPaul Saab 		default:   proto = &prproto[PR_SHORT];          break;
462a5f0fb15SPaul Saab 		}
463a5f0fb15SPaul Saab 		free(*proto);
464a5f0fb15SPaul Saab 		*proto = save(s);
465a5f0fb15SPaul Saab 		break;
466a5f0fb15SPaul Saab 	case QUERY:
467a5f0fb15SPaul Saab 		parg.p_string = prproto[pr_type];
468a5f0fb15SPaul Saab 		error("%s", &parg);
469a5f0fb15SPaul Saab 		break;
470a5f0fb15SPaul Saab 	}
471a5f0fb15SPaul Saab }
472a5f0fb15SPaul Saab 
473a5f0fb15SPaul Saab /*
474a5f0fb15SPaul Saab  * Handler for the -b option.
475a5f0fb15SPaul Saab  */
476a5f0fb15SPaul Saab 	/*ARGSUSED*/
477*c77c4889SXin LI public void opt_b(int type, constant char *s)
478a5f0fb15SPaul Saab {
479a5f0fb15SPaul Saab 	switch (type)
480a5f0fb15SPaul Saab 	{
481a5f0fb15SPaul Saab 	case INIT:
482000ba3e8STim J. Robbins 	case TOGGLE:
483000ba3e8STim J. Robbins 		/*
484000ba3e8STim J. Robbins 		 * Set the new number of buffers.
485000ba3e8STim J. Robbins 		 */
486*c77c4889SXin LI 		ch_setbufspace((ssize_t) bufspace);
487000ba3e8STim J. Robbins 		break;
488000ba3e8STim J. Robbins 	case QUERY:
489a5f0fb15SPaul Saab 		break;
490a5f0fb15SPaul Saab 	}
491a5f0fb15SPaul Saab }
492a5f0fb15SPaul Saab 
493a5f0fb15SPaul Saab /*
494a5f0fb15SPaul Saab  * Handler for the -i option.
495a5f0fb15SPaul Saab  */
496a5f0fb15SPaul Saab 	/*ARGSUSED*/
497*c77c4889SXin LI public void opt_i(int type, constant char *s)
498a5f0fb15SPaul Saab {
499a5f0fb15SPaul Saab 	switch (type)
500a5f0fb15SPaul Saab 	{
501a5f0fb15SPaul Saab 	case TOGGLE:
502a5f0fb15SPaul Saab 		chg_caseless();
503a5f0fb15SPaul Saab 		break;
504a5f0fb15SPaul Saab 	case QUERY:
505a5f0fb15SPaul Saab 	case INIT:
506a5f0fb15SPaul Saab 		break;
507a5f0fb15SPaul Saab 	}
508a5f0fb15SPaul Saab }
509a5f0fb15SPaul Saab 
510a5f0fb15SPaul Saab /*
511a5f0fb15SPaul Saab  * Handler for the -V option.
512a5f0fb15SPaul Saab  */
513a5f0fb15SPaul Saab 	/*ARGSUSED*/
514*c77c4889SXin LI public void opt__V(int type, constant char *s)
515a5f0fb15SPaul Saab {
516a5f0fb15SPaul Saab 	switch (type)
517a5f0fb15SPaul Saab 	{
518a5f0fb15SPaul Saab 	case TOGGLE:
519a5f0fb15SPaul Saab 	case QUERY:
520a5f0fb15SPaul Saab 		dispversion();
521a5f0fb15SPaul Saab 		break;
522a5f0fb15SPaul Saab 	case INIT:
5232235c7feSXin LI 		set_output(1); /* Force output to stdout per GNU standard for --version output. */
524a5f0fb15SPaul Saab 		putstr("less ");
525a5f0fb15SPaul Saab 		putstr(version);
52696e55cc7SXin LI 		putstr(" (");
527b7780dbeSXin LI 		putstr(pattern_lib_name());
52896e55cc7SXin LI 		putstr(" regular expressions)\n");
5292235c7feSXin LI 		{
53030a1828cSXin LI 			char constant *copyright =
531*c77c4889SXin LI 				"Copyright (C) 1984-2024  Mark Nudelman\n\n";
5322235c7feSXin LI 			putstr(copyright);
5332235c7feSXin LI 		}
5342235c7feSXin LI 		if (version[strlen(version)-1] == 'x')
5352235c7feSXin LI 		{
5362235c7feSXin LI 			putstr("** This is an EXPERIMENTAL build of the 'less' software,\n");
5372235c7feSXin LI 			putstr("** and may not function correctly.\n");
5382235c7feSXin LI 			putstr("** Obtain release builds from the web page below.\n\n");
5392235c7feSXin LI 		}
540d713e089SXin LI #if LESSTEST
541d713e089SXin LI 		putstr("This build supports LESSTEST.\n");
542d713e089SXin LI #endif /*LESSTEST*/
543a5f0fb15SPaul Saab 		putstr("less comes with NO WARRANTY, to the extent permitted by law.\n");
544a5f0fb15SPaul Saab 		putstr("For information about the terms of redistribution,\n");
545a5f0fb15SPaul Saab 		putstr("see the file named README in the less distribution.\n");
5462235c7feSXin LI 		putstr("Home page: https://greenwoodsoftware.com/less\n");
547a5f0fb15SPaul Saab 		quit(QUIT_OK);
548a5f0fb15SPaul Saab 		break;
549a5f0fb15SPaul Saab 	}
550a5f0fb15SPaul Saab }
551a5f0fb15SPaul Saab 
552a5f0fb15SPaul Saab #if MSDOS_COMPILER
553a5f0fb15SPaul Saab /*
554a5f0fb15SPaul Saab  * Parse an MSDOS color descriptor.
555a5f0fb15SPaul Saab  */
556*c77c4889SXin LI static void colordesc(constant char *s, int *fg_color, int *bg_color, int *dattr)
557a5f0fb15SPaul Saab {
558a5f0fb15SPaul Saab 	int fg, bg;
559*c77c4889SXin LI 	CHAR_ATTR attr;
560*c77c4889SXin LI 	if (parse_color(s, &fg, &bg, &attr) == CT_NULL)
561b2ea2440SXin LI 	{
5622235c7feSXin LI 		PARG p;
5632235c7feSXin LI 		p.p_string = s;
5642235c7feSXin LI 		error("Invalid color string \"%s\"", &p);
5652235c7feSXin LI 	} else
5662235c7feSXin LI 	{
567a5f0fb15SPaul Saab 		*fg_color = fg;
568a5f0fb15SPaul Saab 		*bg_color = bg;
569*c77c4889SXin LI 		*dattr = 0;
570*c77c4889SXin LI #if MSDOS_COMPILER==WIN32C
571*c77c4889SXin LI 		if (attr & CATTR_UNDERLINE)
572*c77c4889SXin LI 			*dattr |= COMMON_LVB_UNDERSCORE;
573*c77c4889SXin LI 		if (attr & CATTR_STANDOUT)
574*c77c4889SXin LI 			*dattr |= COMMON_LVB_REVERSE_VIDEO;
575*c77c4889SXin LI #endif
576a5f0fb15SPaul Saab 	}
5772235c7feSXin LI }
5782235c7feSXin LI #endif
5792235c7feSXin LI 
580d713e089SXin LI static int color_from_namechar(char namechar)
5812235c7feSXin LI {
5822235c7feSXin LI 	switch (namechar)
5832235c7feSXin LI 	{
5842235c7feSXin LI 	case 'B': return AT_COLOR_BIN;
5852235c7feSXin LI 	case 'C': return AT_COLOR_CTRL;
5862235c7feSXin LI 	case 'E': return AT_COLOR_ERROR;
58795270f73SXin LI 	case 'H': return AT_COLOR_HEADER;
5882235c7feSXin LI 	case 'M': return AT_COLOR_MARK;
5892235c7feSXin LI 	case 'N': return AT_COLOR_LINENUM;
5902235c7feSXin LI 	case 'P': return AT_COLOR_PROMPT;
5912235c7feSXin LI 	case 'R': return AT_COLOR_RSCROLL;
5922235c7feSXin LI 	case 'S': return AT_COLOR_SEARCH;
59395270f73SXin LI 	case 'W': case 'A': return AT_COLOR_ATTN;
5942235c7feSXin LI 	case 'n': return AT_NORMAL;
5952235c7feSXin LI 	case 's': return AT_STANDOUT;
5962235c7feSXin LI 	case 'd': return AT_BOLD;
5972235c7feSXin LI 	case 'u': return AT_UNDERLINE;
5982235c7feSXin LI 	case 'k': return AT_BLINK;
599d713e089SXin LI 	default:
600d713e089SXin LI 		if (namechar >= '1' && namechar <= '0'+NUM_SEARCH_COLORS)
601d713e089SXin LI 			return AT_COLOR_SUBSEARCH(namechar-'0');
602d713e089SXin LI 		return -1;
6032235c7feSXin LI 	}
6042235c7feSXin LI }
605a5f0fb15SPaul Saab 
606a5f0fb15SPaul Saab /*
607a5f0fb15SPaul Saab  * Handler for the -D option.
608a5f0fb15SPaul Saab  */
609a5f0fb15SPaul Saab 	/*ARGSUSED*/
610*c77c4889SXin LI public void opt_D(int type, constant char *s)
611a5f0fb15SPaul Saab {
612f6b74a7dSXin LI 	PARG p;
6132235c7feSXin LI 	int attr;
614f6b74a7dSXin LI 
615a5f0fb15SPaul Saab 	switch (type)
616a5f0fb15SPaul Saab 	{
617a5f0fb15SPaul Saab 	case INIT:
618a5f0fb15SPaul Saab 	case TOGGLE:
6192235c7feSXin LI #if MSDOS_COMPILER
6202235c7feSXin LI 		if (*s == 'a')
621a5f0fb15SPaul Saab 		{
622f6b74a7dSXin LI 			sgr_mode = !sgr_mode;
623f6b74a7dSXin LI 			break;
6242235c7feSXin LI 		}
6252235c7feSXin LI #endif
6262235c7feSXin LI 		attr = color_from_namechar(s[0]);
6272235c7feSXin LI 		if (attr < 0)
6282235c7feSXin LI 		{
6292235c7feSXin LI 			p.p_char = s[0];
6302235c7feSXin LI 			error("Invalid color specifier '%c'", &p);
6312235c7feSXin LI 			return;
6322235c7feSXin LI 		}
6332235c7feSXin LI 		if (!use_color && (attr & AT_COLOR))
6342235c7feSXin LI 		{
6352235c7feSXin LI 			error("Set --use-color before changing colors", NULL_PARG);
6362235c7feSXin LI 			return;
6372235c7feSXin LI 		}
6382235c7feSXin LI 		s++;
6392235c7feSXin LI #if MSDOS_COMPILER
6402235c7feSXin LI 		if (!(attr & AT_COLOR))
6412235c7feSXin LI 		{
6422235c7feSXin LI 			switch (attr)
6432235c7feSXin LI 			{
6442235c7feSXin LI 			case AT_NORMAL:
645*c77c4889SXin LI 				colordesc(s, &nm_fg_color, &nm_bg_color, &nm_attr);
6462235c7feSXin LI 				break;
6472235c7feSXin LI 			case AT_BOLD:
648*c77c4889SXin LI 				colordesc(s, &bo_fg_color, &bo_bg_color, &bo_attr);
6492235c7feSXin LI 				break;
6502235c7feSXin LI 			case AT_UNDERLINE:
651*c77c4889SXin LI 				colordesc(s, &ul_fg_color, &ul_bg_color, &ul_attr);
6522235c7feSXin LI 				break;
6532235c7feSXin LI 			case AT_BLINK:
654*c77c4889SXin LI 				colordesc(s, &bl_fg_color, &bl_bg_color, &bl_attr);
6552235c7feSXin LI 				break;
6562235c7feSXin LI 			case AT_STANDOUT:
657*c77c4889SXin LI 				colordesc(s, &so_fg_color, &so_bg_color, &so_attr);
658a5f0fb15SPaul Saab 				break;
659a5f0fb15SPaul Saab 			}
660a5f0fb15SPaul Saab 			if (type == TOGGLE)
661a5f0fb15SPaul Saab 			{
662*c77c4889SXin LI 				init_win_colors();
6636dcb072bSXin LI 				at_enter(AT_STANDOUT);
6646dcb072bSXin LI 				at_exit();
665a5f0fb15SPaul Saab 			}
6662235c7feSXin LI 		} else
6672235c7feSXin LI #endif
6682235c7feSXin LI 		if (set_color_map(attr, s) < 0)
6692235c7feSXin LI 		{
6702235c7feSXin LI 			p.p_string = s;
6712235c7feSXin LI 			error("Invalid color string \"%s\"", &p);
6722235c7feSXin LI 			return;
6732235c7feSXin LI 		}
674a5f0fb15SPaul Saab 		break;
6752235c7feSXin LI #if MSDOS_COMPILER
676a5f0fb15SPaul Saab 	case QUERY:
677f6b74a7dSXin LI 		p.p_string = (sgr_mode) ? "on" : "off";
678f6b74a7dSXin LI 		error("SGR mode is %s", &p);
679a5f0fb15SPaul Saab 		break;
680a5f0fb15SPaul Saab #endif
6812235c7feSXin LI 	}
6822235c7feSXin LI }
683a5f0fb15SPaul Saab 
684a5f0fb15SPaul Saab /*
685d713e089SXin LI  */
686*c77c4889SXin LI public void set_tabs(constant char *s, size_t len)
687d713e089SXin LI {
688d713e089SXin LI 	int i;
689*c77c4889SXin LI 	constant char *es = s + len;
690d713e089SXin LI 	/* Start at 1 because tabstops[0] is always zero. */
691d713e089SXin LI 	for (i = 1;  i < TABSTOP_MAX;  )
692d713e089SXin LI 	{
693d713e089SXin LI 		int n = 0;
694*c77c4889SXin LI 		lbool v = FALSE;
695d713e089SXin LI 		while (s < es && *s == ' ')
696d713e089SXin LI 			s++;
697d713e089SXin LI 		for (; s < es && *s >= '0' && *s <= '9'; s++)
698d713e089SXin LI 		{
699*c77c4889SXin LI 			v = v || ckd_mul(&n, n, 10);
700*c77c4889SXin LI 			v = v || ckd_add(&n, n, *s - '0');
701d713e089SXin LI 		}
702d713e089SXin LI 		if (!v && n > tabstops[i-1])
703d713e089SXin LI 			tabstops[i++] = n;
704d713e089SXin LI 		while (s < es && *s == ' ')
705d713e089SXin LI 			s++;
706d713e089SXin LI 		if (s == es || *s++ != ',')
707d713e089SXin LI 			break;
708d713e089SXin LI 	}
709d713e089SXin LI 	if (i < 2)
710d713e089SXin LI 		return;
711d713e089SXin LI 	ntabstops = i;
712d713e089SXin LI 	tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2];
713d713e089SXin LI }
714d713e089SXin LI 
715d713e089SXin LI /*
716c9346414SPaul Saab  * Handler for the -x option.
717c9346414SPaul Saab  */
718*c77c4889SXin LI public void opt_x(int type, constant char *s)
719c9346414SPaul Saab {
72095270f73SXin LI 	char msg[60+((INT_STRLEN_BOUND(int)+1)*TABSTOP_MAX)];
721c9346414SPaul Saab 	int i;
722c9346414SPaul Saab 	PARG p;
723c9346414SPaul Saab 
724c9346414SPaul Saab 	switch (type)
725c9346414SPaul Saab 	{
726c9346414SPaul Saab 	case INIT:
727c9346414SPaul Saab 	case TOGGLE:
728d713e089SXin LI 		set_tabs(s, strlen(s));
729c9346414SPaul Saab 		break;
730c9346414SPaul Saab 	case QUERY:
731c9346414SPaul Saab 		strcpy(msg, "Tab stops ");
732c9346414SPaul Saab 		if (ntabstops > 2)
733c9346414SPaul Saab 		{
734c9346414SPaul Saab 			for (i = 1;  i < ntabstops;  i++)
735c9346414SPaul Saab 			{
736c9346414SPaul Saab 				if (i > 1)
737c9346414SPaul Saab 					strcat(msg, ",");
738c9346414SPaul Saab 				sprintf(msg+strlen(msg), "%d", tabstops[i]);
739c9346414SPaul Saab 			}
740c9346414SPaul Saab 			sprintf(msg+strlen(msg), " and then ");
741c9346414SPaul Saab 		}
742c9346414SPaul Saab 		sprintf(msg+strlen(msg), "every %d spaces",
743c9346414SPaul Saab 			tabdefault);
744c9346414SPaul Saab 		p.p_string = msg;
745c9346414SPaul Saab 		error("%s", &p);
746c9346414SPaul Saab 		break;
747c9346414SPaul Saab 	}
748c9346414SPaul Saab }
749c9346414SPaul Saab 
750c9346414SPaul Saab 
751c9346414SPaul Saab /*
752a5f0fb15SPaul Saab  * Handler for the -" option.
753a5f0fb15SPaul Saab  */
754*c77c4889SXin LI public void opt_quote(int type, constant char *s)
755a5f0fb15SPaul Saab {
756a5f0fb15SPaul Saab 	char buf[3];
757a5f0fb15SPaul Saab 	PARG parg;
758a5f0fb15SPaul Saab 
759a5f0fb15SPaul Saab 	switch (type)
760a5f0fb15SPaul Saab 	{
761a5f0fb15SPaul Saab 	case INIT:
762a5f0fb15SPaul Saab 	case TOGGLE:
763000ba3e8STim J. Robbins 		if (s[0] == '\0')
764000ba3e8STim J. Robbins 		{
765000ba3e8STim J. Robbins 			openquote = closequote = '\0';
766000ba3e8STim J. Robbins 			break;
767000ba3e8STim J. Robbins 		}
768a5f0fb15SPaul Saab 		if (s[1] != '\0' && s[2] != '\0')
769a5f0fb15SPaul Saab 		{
770a5f0fb15SPaul Saab 			error("-\" must be followed by 1 or 2 chars", NULL_PARG);
771a5f0fb15SPaul Saab 			return;
772a5f0fb15SPaul Saab 		}
773a5f0fb15SPaul Saab 		openquote = s[0];
774a5f0fb15SPaul Saab 		if (s[1] == '\0')
775a5f0fb15SPaul Saab 			closequote = openquote;
776a5f0fb15SPaul Saab 		else
777a5f0fb15SPaul Saab 			closequote = s[1];
778a5f0fb15SPaul Saab 		break;
779a5f0fb15SPaul Saab 	case QUERY:
780a5f0fb15SPaul Saab 		buf[0] = openquote;
781a5f0fb15SPaul Saab 		buf[1] = closequote;
782a5f0fb15SPaul Saab 		buf[2] = '\0';
783a5f0fb15SPaul Saab 		parg.p_string = buf;
784a5f0fb15SPaul Saab 		error("quotes %s", &parg);
785a5f0fb15SPaul Saab 		break;
786a5f0fb15SPaul Saab 	}
787a5f0fb15SPaul Saab }
788a5f0fb15SPaul Saab 
789a5f0fb15SPaul Saab /*
790b2ea2440SXin LI  * Handler for the --rscroll option.
791b2ea2440SXin LI  */
792b2ea2440SXin LI 	/*ARGSUSED*/
793*c77c4889SXin LI public void opt_rscroll(int type, constant char *s)
794b2ea2440SXin LI {
795b2ea2440SXin LI 	PARG p;
796b2ea2440SXin LI 
797b2ea2440SXin LI 	switch (type)
798b2ea2440SXin LI 	{
799b2ea2440SXin LI 	case INIT:
800b2ea2440SXin LI 	case TOGGLE: {
801*c77c4889SXin LI 		constant char *fmt;
802b2ea2440SXin LI 		int attr = AT_STANDOUT;
803d713e089SXin LI 		setfmt(s, &fmt, &attr, "*s>", FALSE);
804b2ea2440SXin LI 		if (strcmp(fmt, "-") == 0)
805b2ea2440SXin LI 		{
806b2ea2440SXin LI 			rscroll_char = 0;
807b2ea2440SXin LI 		} else
808b2ea2440SXin LI 		{
8092235c7feSXin LI 			rscroll_attr = attr|AT_COLOR_RSCROLL;
810*c77c4889SXin LI 			if (*fmt == '\0')
811*c77c4889SXin LI 				rscroll_char = '>';
812*c77c4889SXin LI 			else
813*c77c4889SXin LI 			{
814*c77c4889SXin LI 				LWCHAR ch = step_charc(&fmt, +1, fmt+strlen(fmt));
815*c77c4889SXin LI 				if (pwidth(ch, rscroll_attr, 0, 0) > 1)
816*c77c4889SXin LI 					error("cannot set rscroll to a wide character", NULL_PARG);
817*c77c4889SXin LI 				else
818*c77c4889SXin LI 					rscroll_char = ch;
819*c77c4889SXin LI 			}
820b2ea2440SXin LI 		}
821b2ea2440SXin LI 		break; }
822b2ea2440SXin LI 	case QUERY: {
823*c77c4889SXin LI 		p.p_string = rscroll_char ? prchar((LWCHAR) rscroll_char) : "-";
824d713e089SXin LI 		error("rscroll character is %s", &p);
825b2ea2440SXin LI 		break; }
826b2ea2440SXin LI 	}
827b2ea2440SXin LI }
828b2ea2440SXin LI 
829b2ea2440SXin LI /*
830a5f0fb15SPaul Saab  * "-?" means display a help message.
831a5f0fb15SPaul Saab  * If from the command line, exit immediately.
832a5f0fb15SPaul Saab  */
833a5f0fb15SPaul Saab 	/*ARGSUSED*/
834*c77c4889SXin LI public void opt_query(int type, constant char *s)
835a5f0fb15SPaul Saab {
836a5f0fb15SPaul Saab 	switch (type)
837a5f0fb15SPaul Saab 	{
838a5f0fb15SPaul Saab 	case QUERY:
839a5f0fb15SPaul Saab 	case TOGGLE:
840a5f0fb15SPaul Saab 		error("Use \"h\" for help", NULL_PARG);
841a5f0fb15SPaul Saab 		break;
842a5f0fb15SPaul Saab 	case INIT:
843a5f0fb15SPaul Saab 		dohelp = 1;
844a5f0fb15SPaul Saab 	}
845a5f0fb15SPaul Saab }
846a5f0fb15SPaul Saab 
847*c77c4889SXin LI 	/*ARGSUSED*/
848*c77c4889SXin LI public void opt_match_shift(int type, constant char *s)
849*c77c4889SXin LI {
850*c77c4889SXin LI 	switch (type)
851*c77c4889SXin LI 	{
852*c77c4889SXin LI 	case INIT:
853*c77c4889SXin LI 	case TOGGLE:
854*c77c4889SXin LI 		toggle_fraction(&match_shift, &match_shift_fraction,
855*c77c4889SXin LI 			s, "--match-shift", calc_match_shift);
856*c77c4889SXin LI 		break;
857*c77c4889SXin LI 	case QUERY:
858*c77c4889SXin LI 		query_fraction(match_shift, match_shift_fraction,
859*c77c4889SXin LI 			"Search match shift is %d", "Search match shift is %s of screen width");
860*c77c4889SXin LI 		break;
861*c77c4889SXin LI 	}
862*c77c4889SXin LI }
863*c77c4889SXin LI 
864*c77c4889SXin LI public void calc_match_shift(void)
865*c77c4889SXin LI {
866*c77c4889SXin LI 	if (match_shift_fraction < 0)
867*c77c4889SXin LI 		return;
868*c77c4889SXin LI 	match_shift = (int) muldiv(sc_width, match_shift_fraction, NUM_FRAC_DENOM);
869*c77c4889SXin LI }
870*c77c4889SXin LI 
871a5f0fb15SPaul Saab /*
872b7780dbeSXin LI  * Handler for the --mouse option.
873b7780dbeSXin LI  */
874b7780dbeSXin LI 	/*ARGSUSED*/
875*c77c4889SXin LI public void opt_mousecap(int type, constant char *s)
876b7780dbeSXin LI {
877b7780dbeSXin LI 	switch (type)
878b7780dbeSXin LI 	{
879b7780dbeSXin LI 	case TOGGLE:
880b7780dbeSXin LI 		if (mousecap == OPT_OFF)
881b7780dbeSXin LI 			deinit_mouse();
882b7780dbeSXin LI 		else
883b7780dbeSXin LI 			init_mouse();
884b7780dbeSXin LI 		break;
885b7780dbeSXin LI 	case INIT:
886b7780dbeSXin LI 	case QUERY:
887b7780dbeSXin LI 		break;
888b7780dbeSXin LI 	}
889b7780dbeSXin LI }
890b7780dbeSXin LI 
891b7780dbeSXin LI /*
892b7780dbeSXin LI  * Handler for the --wheel-lines option.
893b7780dbeSXin LI  */
894b7780dbeSXin LI 	/*ARGSUSED*/
895*c77c4889SXin LI public void opt_wheel_lines(int type, constant char *s)
896b7780dbeSXin LI {
897b7780dbeSXin LI 	switch (type)
898b7780dbeSXin LI 	{
899b7780dbeSXin LI 	case INIT:
900b7780dbeSXin LI 	case TOGGLE:
901b7780dbeSXin LI 		if (wheel_lines <= 0)
902b7780dbeSXin LI 			wheel_lines = default_wheel_lines();
903b7780dbeSXin LI 		break;
904b7780dbeSXin LI 	case QUERY:
905b7780dbeSXin LI 		break;
906b7780dbeSXin LI 	}
907b7780dbeSXin LI }
908b7780dbeSXin LI 
909b7780dbeSXin LI /*
9102235c7feSXin LI  * Handler for the --line-number-width option.
9112235c7feSXin LI  */
9122235c7feSXin LI 	/*ARGSUSED*/
913*c77c4889SXin LI public void opt_linenum_width(int type, constant char *s)
9142235c7feSXin LI {
9152235c7feSXin LI 	PARG parg;
9162235c7feSXin LI 
9172235c7feSXin LI 	switch (type)
9182235c7feSXin LI 	{
9192235c7feSXin LI 	case INIT:
9202235c7feSXin LI 	case TOGGLE:
9212235c7feSXin LI 		if (linenum_width > MAX_LINENUM_WIDTH)
9222235c7feSXin LI 		{
9232235c7feSXin LI 			parg.p_int = MAX_LINENUM_WIDTH;
9242235c7feSXin LI 			error("Line number width must not be larger than %d", &parg);
9252235c7feSXin LI 			linenum_width = MIN_LINENUM_WIDTH;
9262235c7feSXin LI 		}
9272235c7feSXin LI 		break;
9282235c7feSXin LI 	case QUERY:
9292235c7feSXin LI 		break;
9302235c7feSXin LI 	}
9312235c7feSXin LI }
9322235c7feSXin LI 
9332235c7feSXin LI /*
9342235c7feSXin LI  * Handler for the --status-column-width option.
9352235c7feSXin LI  */
9362235c7feSXin LI 	/*ARGSUSED*/
937*c77c4889SXin LI public void opt_status_col_width(int type, constant char *s)
9382235c7feSXin LI {
9392235c7feSXin LI 	PARG parg;
9402235c7feSXin LI 
9412235c7feSXin LI 	switch (type)
9422235c7feSXin LI 	{
9432235c7feSXin LI 	case INIT:
9442235c7feSXin LI 	case TOGGLE:
9452235c7feSXin LI 		if (status_col_width > MAX_STATUSCOL_WIDTH)
9462235c7feSXin LI 		{
9472235c7feSXin LI 			parg.p_int = MAX_STATUSCOL_WIDTH;
9482235c7feSXin LI 			error("Status column width must not be larger than %d", &parg);
9492235c7feSXin LI 			status_col_width = 2;
9502235c7feSXin LI 		}
9512235c7feSXin LI 		break;
9522235c7feSXin LI 	case QUERY:
9532235c7feSXin LI 		break;
9542235c7feSXin LI 	}
9552235c7feSXin LI }
9562235c7feSXin LI 
95730a1828cSXin LI /*
95830a1828cSXin LI  * Handler for the --file-size option.
95930a1828cSXin LI  */
96030a1828cSXin LI 	/*ARGSUSED*/
961*c77c4889SXin LI public void opt_filesize(int type, constant char *s)
96230a1828cSXin LI {
96330a1828cSXin LI 	switch (type)
96430a1828cSXin LI 	{
96530a1828cSXin LI 	case INIT:
96630a1828cSXin LI 	case TOGGLE:
96730a1828cSXin LI 		if (want_filesize && curr_ifile != NULL && ch_length() == NULL_POSITION)
96830a1828cSXin LI 			scan_eof();
96930a1828cSXin LI 		break;
97030a1828cSXin LI 	case QUERY:
97130a1828cSXin LI 		break;
97230a1828cSXin LI 	}
97330a1828cSXin LI }
97430a1828cSXin LI 
97595270f73SXin LI /*
976d713e089SXin LI  * Handler for the --intr option.
977d713e089SXin LI  */
978d713e089SXin LI 	/*ARGSUSED*/
979*c77c4889SXin LI public void opt_intr(int type, constant char *s)
980d713e089SXin LI {
981d713e089SXin LI 	PARG p;
982d713e089SXin LI 
983d713e089SXin LI 	switch (type)
984d713e089SXin LI 	{
985d713e089SXin LI 	case INIT:
986d713e089SXin LI 	case TOGGLE:
987d713e089SXin LI 		intr_char = *s;
988d713e089SXin LI 		if (intr_char == '^' && s[1] != '\0')
989d713e089SXin LI 			intr_char = CONTROL(s[1]);
990d713e089SXin LI 		break;
991d713e089SXin LI 	case QUERY: {
992*c77c4889SXin LI 		p.p_string = prchar((LWCHAR) intr_char);
993d713e089SXin LI 		error("interrupt character is %s", &p);
994d713e089SXin LI 		break; }
995d713e089SXin LI 	}
996d713e089SXin LI }
997d713e089SXin LI 
998d713e089SXin LI /*
999*c77c4889SXin LI  * Return the next number from a comma-separated list.
1000*c77c4889SXin LI  * Return -1 if the list entry is missing or empty.
1001*c77c4889SXin LI  * Updates *sp to point to the first char of the next number in the list.
1002*c77c4889SXin LI  */
1003*c77c4889SXin LI public int next_cnum(constant char **sp, constant char *printopt, constant char *errmsg, lbool *errp)
1004*c77c4889SXin LI {
1005*c77c4889SXin LI 	int n;
1006*c77c4889SXin LI 	*errp = FALSE;
1007*c77c4889SXin LI 	if (**sp == '\0') /* at end of line */
1008*c77c4889SXin LI 		return -1;
1009*c77c4889SXin LI 	if (**sp == ',') /* that's the next comma; we have an empty string */
1010*c77c4889SXin LI 	{
1011*c77c4889SXin LI 		++(*sp);
1012*c77c4889SXin LI 		return -1;
1013*c77c4889SXin LI 	}
1014*c77c4889SXin LI 	n = getnumc(sp, printopt, errp);
1015*c77c4889SXin LI 	if (*errp)
1016*c77c4889SXin LI 	{
1017*c77c4889SXin LI 		PARG parg;
1018*c77c4889SXin LI 		parg.p_string = errmsg;
1019*c77c4889SXin LI 		error("invalid %s", &parg);
1020*c77c4889SXin LI 		return -1;
1021*c77c4889SXin LI 	}
1022*c77c4889SXin LI 	if (**sp == ',')
1023*c77c4889SXin LI 		++(*sp);
1024*c77c4889SXin LI 	return n;
1025*c77c4889SXin LI }
1026*c77c4889SXin LI 
1027*c77c4889SXin LI /*
1028*c77c4889SXin LI  * Parse a parameter to the --header option.
1029*c77c4889SXin LI  * Value is "L,C,N", where each field is a decimal number or empty.
1030*c77c4889SXin LI  */
1031*c77c4889SXin LI static lbool parse_header(constant char *s, int *lines, int *cols, POSITION *start_pos)
1032*c77c4889SXin LI {
1033*c77c4889SXin LI 	int n;
1034*c77c4889SXin LI 	lbool err;
1035*c77c4889SXin LI 
1036*c77c4889SXin LI 	if (*s == '-')
1037*c77c4889SXin LI 		s = "0,0";
1038*c77c4889SXin LI 
1039*c77c4889SXin LI 	n = next_cnum(&s, "header", "number of lines", &err);
1040*c77c4889SXin LI 	if (err) return FALSE;
1041*c77c4889SXin LI 	if (n >= 0) *lines = n;
1042*c77c4889SXin LI 
1043*c77c4889SXin LI 	n = next_cnum(&s, "header", "number of columns", &err);
1044*c77c4889SXin LI 	if (err) return FALSE;
1045*c77c4889SXin LI 	if (n >= 0) *cols = n;
1046*c77c4889SXin LI 
1047*c77c4889SXin LI 	n = next_cnum(&s, "header", "line number", &err);
1048*c77c4889SXin LI 	if (err) return FALSE;
1049*c77c4889SXin LI 	if (n > 0)
1050*c77c4889SXin LI 	{
1051*c77c4889SXin LI 		LINENUM lnum = (LINENUM) n;
1052*c77c4889SXin LI 		if (lnum < 1) lnum = 1;
1053*c77c4889SXin LI 		*start_pos = find_pos(lnum);
1054*c77c4889SXin LI 	}
1055*c77c4889SXin LI 	return TRUE;
1056*c77c4889SXin LI }
1057*c77c4889SXin LI 
1058*c77c4889SXin LI /*
105995270f73SXin LI  * Handler for the --header option.
106095270f73SXin LI  */
106195270f73SXin LI 	/*ARGSUSED*/
1062*c77c4889SXin LI public void opt_header(int type, constant char *s)
106395270f73SXin LI {
106495270f73SXin LI 	switch (type)
106595270f73SXin LI 	{
106695270f73SXin LI 	case INIT:
1067*c77c4889SXin LI 		/* Can't call parse_header now because input file is not yet opened,
1068*c77c4889SXin LI 		 * so find_pos won't work. */
1069*c77c4889SXin LI 		init_header = save(s);
107095270f73SXin LI 		break;
1071*c77c4889SXin LI 	case TOGGLE: {
1072*c77c4889SXin LI 		int lines = header_lines;
1073*c77c4889SXin LI 		int cols = header_cols;
1074*c77c4889SXin LI 		POSITION start_pos = (type == INIT) ? ch_zero() : position(TOP);
1075*c77c4889SXin LI 		if (start_pos == NULL_POSITION) start_pos = ch_zero();
1076*c77c4889SXin LI 		if (!parse_header(s, &lines, &cols, &start_pos))
1077*c77c4889SXin LI 			break;
1078*c77c4889SXin LI 		header_lines = lines;
1079*c77c4889SXin LI 		header_cols = cols;
1080*c77c4889SXin LI 		set_header(start_pos);
1081*c77c4889SXin LI 		calc_jump_sline();
1082*c77c4889SXin LI 		break; }
1083*c77c4889SXin LI     case QUERY: {
1084*c77c4889SXin LI         char buf[3*INT_STRLEN_BOUND(long)+3];
108595270f73SXin LI         PARG parg;
1086*c77c4889SXin LI         SNPRINTF3(buf, sizeof(buf), "%ld,%ld,%ld", (long) header_lines, (long) header_cols, (long) find_linenum(header_start_pos));
108795270f73SXin LI         parg.p_string = buf;
1088*c77c4889SXin LI         error("Header (lines,columns,line-number) is %s", &parg);
1089*c77c4889SXin LI         break; }
109095270f73SXin LI 	}
109195270f73SXin LI }
109295270f73SXin LI 
109395270f73SXin LI /*
109495270f73SXin LI  * Handler for the --search-options option.
109595270f73SXin LI  */
109695270f73SXin LI 	/*ARGSUSED*/
1097*c77c4889SXin LI public void opt_search_type(int type, constant char *s)
109895270f73SXin LI {
109995270f73SXin LI 	int st;
110095270f73SXin LI 	PARG parg;
110195270f73SXin LI 	char buf[16];
110295270f73SXin LI 	char *bp;
1103d713e089SXin LI 	int i;
110495270f73SXin LI 
110595270f73SXin LI 	switch (type)
110695270f73SXin LI 	{
110795270f73SXin LI 	case INIT:
110895270f73SXin LI 	case TOGGLE:
110995270f73SXin LI 		st = 0;
111095270f73SXin LI 		for (;  *s != '\0';  s++)
111195270f73SXin LI 		{
111295270f73SXin LI 			switch (*s)
111395270f73SXin LI 			{
111495270f73SXin LI 			case 'E': case 'e': case CONTROL('E'): st |= SRCH_PAST_EOF;   break;
111595270f73SXin LI 			case 'F': case 'f': case CONTROL('F'): st |= SRCH_FIRST_FILE; break;
111695270f73SXin LI 			case 'K': case 'k': case CONTROL('K'): st |= SRCH_NO_MOVE;    break;
111795270f73SXin LI 			case 'N': case 'n': case CONTROL('N'): st |= SRCH_NO_MATCH;   break;
111895270f73SXin LI 			case 'R': case 'r': case CONTROL('R'): st |= SRCH_NO_REGEX;   break;
111995270f73SXin LI 			case 'W': case 'w': case CONTROL('W'): st |= SRCH_WRAP;       break;
112095270f73SXin LI 			case '-': st = 0; break;
112195270f73SXin LI 			case '^': break;
112295270f73SXin LI 			default:
1123d713e089SXin LI 				if (*s >= '1' && *s <= '0'+NUM_SEARCH_COLORS)
1124d713e089SXin LI 				{
1125d713e089SXin LI 					st |= SRCH_SUBSEARCH(*s-'0');
1126d713e089SXin LI 					break;
1127d713e089SXin LI 				}
112895270f73SXin LI 				parg.p_char = *s;
112995270f73SXin LI 				error("invalid search option '%c'", &parg);
113095270f73SXin LI 				return;
113195270f73SXin LI 			}
113295270f73SXin LI 		}
113395270f73SXin LI 		def_search_type = norm_search_type(st);
113495270f73SXin LI 		break;
113595270f73SXin LI 	case QUERY:
113695270f73SXin LI 		bp = buf;
113795270f73SXin LI 		if (def_search_type & SRCH_PAST_EOF)   *bp++ = 'E';
113895270f73SXin LI 		if (def_search_type & SRCH_FIRST_FILE) *bp++ = 'F';
113995270f73SXin LI 		if (def_search_type & SRCH_NO_MOVE)    *bp++ = 'K';
114095270f73SXin LI 		if (def_search_type & SRCH_NO_MATCH)   *bp++ = 'N';
114195270f73SXin LI 		if (def_search_type & SRCH_NO_REGEX)   *bp++ = 'R';
114295270f73SXin LI 		if (def_search_type & SRCH_WRAP)       *bp++ = 'W';
1143d713e089SXin LI 		for (i = 1;  i <= NUM_SEARCH_COLORS;  i++)
1144d713e089SXin LI 			if (def_search_type & SRCH_SUBSEARCH(i))
1145*c77c4889SXin LI 				*bp++ = (char) ('0'+i);
114695270f73SXin LI 		if (bp == buf)
114795270f73SXin LI 			*bp++ = '-';
114895270f73SXin LI 		*bp = '\0';
114995270f73SXin LI 		parg.p_string = buf;
115095270f73SXin LI 		error("search options: %s", &parg);
115195270f73SXin LI 		break;
115295270f73SXin LI 	}
115395270f73SXin LI }
115495270f73SXin LI 
1155*c77c4889SXin LI /*
1156*c77c4889SXin LI  * Handler for the --no-search-headers, --no-search-header-lines
1157*c77c4889SXin LI  * and --no-search-header-cols options.
1158*c77c4889SXin LI  */
1159*c77c4889SXin LI static void do_nosearch_headers(int type, int no_header_lines, int no_header_cols)
1160*c77c4889SXin LI {
1161*c77c4889SXin LI 	switch (type)
1162*c77c4889SXin LI 	{
1163*c77c4889SXin LI 	case INIT:
1164*c77c4889SXin LI 	case TOGGLE:
1165*c77c4889SXin LI 		nosearch_header_lines = no_header_lines;
1166*c77c4889SXin LI 		nosearch_header_cols = no_header_cols;
1167*c77c4889SXin LI 		break;
1168*c77c4889SXin LI 	case QUERY:
1169*c77c4889SXin LI 		if (nosearch_header_lines && nosearch_header_cols)
1170*c77c4889SXin LI 			error("Search does not include header lines or columns", NULL_PARG);
1171*c77c4889SXin LI 		else if (nosearch_header_lines)
1172*c77c4889SXin LI 			error("Search includes header columns but not header lines", NULL_PARG);
1173*c77c4889SXin LI 		else if (nosearch_header_cols)
1174*c77c4889SXin LI 			error("Search includes header lines but not header columns", NULL_PARG);
1175*c77c4889SXin LI 		else
1176*c77c4889SXin LI 			error("Search includes header lines and columns", NULL_PARG);
1177*c77c4889SXin LI 	}
1178*c77c4889SXin LI }
1179*c77c4889SXin LI 
1180*c77c4889SXin LI 	/*ARGSUSED*/
1181*c77c4889SXin LI public void opt_nosearch_headers(int type, constant char *s)
1182*c77c4889SXin LI {
1183*c77c4889SXin LI 	do_nosearch_headers(type, 1, 1);
1184*c77c4889SXin LI }
1185*c77c4889SXin LI 
1186*c77c4889SXin LI 	/*ARGSUSED*/
1187*c77c4889SXin LI public void opt_nosearch_header_lines(int type, constant char *s)
1188*c77c4889SXin LI {
1189*c77c4889SXin LI 	do_nosearch_headers(type, 1, 0);
1190*c77c4889SXin LI }
1191*c77c4889SXin LI 
1192*c77c4889SXin LI 	/*ARGSUSED*/
1193*c77c4889SXin LI public void opt_nosearch_header_cols(int type, constant char *s)
1194*c77c4889SXin LI {
1195*c77c4889SXin LI 	do_nosearch_headers(type, 0, 1);
1196*c77c4889SXin LI }
1197*c77c4889SXin LI 
11982235c7feSXin LI #if LESSTEST
11992235c7feSXin LI /*
12002235c7feSXin LI  * Handler for the --tty option.
12012235c7feSXin LI  */
12022235c7feSXin LI 	/*ARGSUSED*/
1203*c77c4889SXin LI public void opt_ttyin_name(int type, constant char *s)
12042235c7feSXin LI {
12052235c7feSXin LI 	switch (type)
12062235c7feSXin LI 	{
12072235c7feSXin LI 	case INIT:
12082235c7feSXin LI 		ttyin_name = s;
12092235c7feSXin LI 		is_tty = 1;
12102235c7feSXin LI 		break;
12112235c7feSXin LI 	}
12122235c7feSXin LI }
12132235c7feSXin LI #endif /*LESSTEST*/
12142235c7feSXin LI 
1215d713e089SXin LI public int chop_line(void)
121695270f73SXin LI {
121795270f73SXin LI 	return (chopline || header_cols > 0 || header_lines > 0);
121895270f73SXin LI }
121995270f73SXin LI 
12202235c7feSXin LI /*
1221a5f0fb15SPaul Saab  * Get the "screen window" size.
1222a5f0fb15SPaul Saab  */
1223d713e089SXin LI public int get_swindow(void)
1224a5f0fb15SPaul Saab {
1225a5f0fb15SPaul Saab 	if (swindow > 0)
1226a5f0fb15SPaul Saab 		return (swindow);
122795270f73SXin LI 	return (sc_height - header_lines + swindow);
1228a5f0fb15SPaul Saab }
1229a5f0fb15SPaul Saab 
1230