xref: /freebsd/contrib/less/option.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  * Process command line options.
13a5f0fb15SPaul Saab  *
14a5f0fb15SPaul Saab  * Each option is a single letter which controls a program variable.
15a5f0fb15SPaul Saab  * The options have defaults which may be changed via
16a5f0fb15SPaul Saab  * the command line option, toggled via the "-" command,
17a5f0fb15SPaul Saab  * or queried via the "_" command.
18a5f0fb15SPaul Saab  */
19a5f0fb15SPaul Saab 
20a5f0fb15SPaul Saab #include "less.h"
21a5f0fb15SPaul Saab #include "option.h"
22a5f0fb15SPaul Saab 
23000ba3e8STim J. Robbins static struct loption *pendopt;
24*c77c4889SXin LI public lbool plusoption = FALSE;
25a5f0fb15SPaul Saab 
26*c77c4889SXin LI static constant char *optstring(constant char *s, char **p_str, constant char *printopt, constant char *validchars);
27d713e089SXin LI static int flip_triple(int val, int lc);
28a5f0fb15SPaul Saab 
297f074f9cSXin LI extern int less_is_more;
307f074f9cSXin LI extern int quit_at_eof;
31a5f0fb15SPaul Saab extern char *every_first_cmd;
327bd2567cSXin LI extern int opt_use_backslash;
33a5f0fb15SPaul Saab 
34a5f0fb15SPaul Saab /*
3533096f16SXin LI  * Return a printable description of an option.
3633096f16SXin LI  */
37*c77c4889SXin LI static constant char * opt_desc(struct loption *o)
3833096f16SXin LI {
3933096f16SXin LI 	static char buf[OPTNAME_MAX + 10];
4033096f16SXin LI 	if (o->oletter == OLETTER_NONE)
4133096f16SXin LI 		SNPRINTF1(buf, sizeof(buf), "--%s", o->onames->oname);
4233096f16SXin LI 	else
4333096f16SXin LI 		SNPRINTF2(buf, sizeof(buf), "-%c (--%s)", o->oletter, o->onames->oname);
4433096f16SXin LI 	return (buf);
4533096f16SXin LI }
4633096f16SXin LI 
4733096f16SXin LI /*
4833096f16SXin LI  * Return a string suitable for printing as the "name" of an option.
4933096f16SXin LI  * For example, if the option letter is 'x', just return "-x".
5033096f16SXin LI  */
51*c77c4889SXin LI public constant char * propt(char c)
5233096f16SXin LI {
5395270f73SXin LI 	static char buf[MAX_PRCHAR_LEN+2];
5433096f16SXin LI 
55*c77c4889SXin LI 	sprintf(buf, "-%s", prchar((LWCHAR) c));
5633096f16SXin LI 	return (buf);
5733096f16SXin LI }
5833096f16SXin LI 
5933096f16SXin LI /*
60a5f0fb15SPaul Saab  * Scan an argument (either from the command line or from the
61a5f0fb15SPaul Saab  * LESS environment variable) and process it.
62a5f0fb15SPaul Saab  */
63*c77c4889SXin LI public void scan_option(constant char *s)
64a5f0fb15SPaul Saab {
651ea31627SRobert Watson 	struct loption *o;
66*c77c4889SXin LI 	char optc;
67*c77c4889SXin LI 	constant char *optname;
68*c77c4889SXin LI 	constant char *printopt;
69a5f0fb15SPaul Saab 	char *str;
70*c77c4889SXin LI 	lbool set_default;
71a5f0fb15SPaul Saab 	int lc;
72*c77c4889SXin LI 	lbool ambig;
73a5f0fb15SPaul Saab 	PARG parg;
74a5f0fb15SPaul Saab 
75a5f0fb15SPaul Saab 	if (s == NULL)
76a5f0fb15SPaul Saab 		return;
77a5f0fb15SPaul Saab 
78a5f0fb15SPaul Saab 	/*
79a5f0fb15SPaul Saab 	 * If we have a pending option which requires an argument,
80a5f0fb15SPaul Saab 	 * handle it now.
81a5f0fb15SPaul Saab 	 * This happens if the previous option was, for example, "-P"
82a5f0fb15SPaul Saab 	 * without a following string.  In that case, the current
83a5f0fb15SPaul Saab 	 * option is simply the argument for the previous option.
84a5f0fb15SPaul Saab 	 */
85a5f0fb15SPaul Saab 	if (pendopt != NULL)
86a5f0fb15SPaul Saab 	{
87*c77c4889SXin LI 		if (!(pendopt->otype & UNSUPPORTED))
88*c77c4889SXin LI 		{
89a5f0fb15SPaul Saab 			switch (pendopt->otype & OTYPE)
90a5f0fb15SPaul Saab 			{
91a5f0fb15SPaul Saab 			case STRING:
92a5f0fb15SPaul Saab 				(*pendopt->ofunc)(INIT, s);
93a5f0fb15SPaul Saab 				break;
94a5f0fb15SPaul Saab 			case NUMBER:
9533096f16SXin LI 				printopt = opt_desc(pendopt);
96*c77c4889SXin LI 				*(pendopt->ovar) = getnumc(&s, printopt, NULL);
97a5f0fb15SPaul Saab 				break;
98a5f0fb15SPaul Saab 			}
99*c77c4889SXin LI 		}
100a5f0fb15SPaul Saab 		pendopt = NULL;
101a5f0fb15SPaul Saab 		return;
102a5f0fb15SPaul Saab 	}
103a5f0fb15SPaul Saab 
104a5f0fb15SPaul Saab 	set_default = FALSE;
105a5f0fb15SPaul Saab 	optname = NULL;
106a5f0fb15SPaul Saab 
107a5f0fb15SPaul Saab 	while (*s != '\0')
108a5f0fb15SPaul Saab 	{
109a5f0fb15SPaul Saab 		/*
110a5f0fb15SPaul Saab 		 * Check some special cases first.
111a5f0fb15SPaul Saab 		 */
112a5f0fb15SPaul Saab 		switch (optc = *s++)
113a5f0fb15SPaul Saab 		{
114a5f0fb15SPaul Saab 		case ' ':
115a5f0fb15SPaul Saab 		case '\t':
116a5f0fb15SPaul Saab 		case END_OPTION_STRING:
117a5f0fb15SPaul Saab 			continue;
118a5f0fb15SPaul Saab 		case '-':
119a5f0fb15SPaul Saab 			/*
120a5f0fb15SPaul Saab 			 * "--" indicates an option name instead of a letter.
121a5f0fb15SPaul Saab 			 */
122a5f0fb15SPaul Saab 			if (*s == '-')
123a5f0fb15SPaul Saab 				optname = ++s;
124a5f0fb15SPaul Saab 			/*
125*c77c4889SXin LI 			 * "-+" or "--+" means set these options back to their defaults.
126*c77c4889SXin LI 			 * (They may have been set otherwise by previous options.)
127a5f0fb15SPaul Saab 			 */
128a5f0fb15SPaul Saab 			set_default = (*s == '+');
129a5f0fb15SPaul Saab 			if (set_default)
130a5f0fb15SPaul Saab 				s++;
131*c77c4889SXin LI 			if (optname != NULL)
132*c77c4889SXin LI 			{
133*c77c4889SXin LI 				optname = s;
134*c77c4889SXin LI 				break;
135*c77c4889SXin LI 			}
136a5f0fb15SPaul Saab 			continue;
137a5f0fb15SPaul Saab 		case '+':
138a5f0fb15SPaul Saab 			/*
139a5f0fb15SPaul Saab 			 * An option prefixed by a "+" is ungotten, so
140a5f0fb15SPaul Saab 			 * that it is interpreted as less commands
141a5f0fb15SPaul Saab 			 * processed at the start of the first input file.
142a5f0fb15SPaul Saab 			 * "++" means process the commands at the start of
143a5f0fb15SPaul Saab 			 * EVERY input file.
144a5f0fb15SPaul Saab 			 */
145a5f0fb15SPaul Saab 			plusoption = TRUE;
146000ba3e8STim J. Robbins 			s = optstring(s, &str, propt('+'), NULL);
1474cc5fc9aSXin LI 			if (s == NULL)
1484cc5fc9aSXin LI 				return;
149c9346414SPaul Saab 			if (*str == '+')
150b7780dbeSXin LI 			{
151b7780dbeSXin LI 				if (every_first_cmd != NULL)
152b7780dbeSXin LI 					free(every_first_cmd);
15321fa6541SXin LI 				every_first_cmd = save(str+1);
154b7780dbeSXin LI 			} else
155a15691bfSXin LI 			{
156c9346414SPaul Saab 				ungetsc(str);
157*c77c4889SXin LI 				ungetcc_end_command();
158a15691bfSXin LI 			}
1594cc5fc9aSXin LI 			free(str);
160a5f0fb15SPaul Saab 			continue;
161a5f0fb15SPaul Saab 		case '0':  case '1':  case '2':  case '3':  case '4':
162a5f0fb15SPaul Saab 		case '5':  case '6':  case '7':  case '8':  case '9':
163a5f0fb15SPaul Saab 			/*
164a5f0fb15SPaul Saab 			 * Special "more" compatibility form "-<number>"
165a5f0fb15SPaul Saab 			 * instead of -z<number> to set the scrolling
166a5f0fb15SPaul Saab 			 * window size.
167a5f0fb15SPaul Saab 			 */
168a5f0fb15SPaul Saab 			s--;
169a5f0fb15SPaul Saab 			optc = 'z';
170a5f0fb15SPaul Saab 			break;
1717f074f9cSXin LI 		case 'n':
1727f074f9cSXin LI 			if (less_is_more)
1737f074f9cSXin LI 				optc = 'z';
1747f074f9cSXin LI 			break;
175a5f0fb15SPaul Saab 		}
176a5f0fb15SPaul Saab 
177a5f0fb15SPaul Saab 		/*
178a5f0fb15SPaul Saab 		 * Not a special case.
179a5f0fb15SPaul Saab 		 * Look up the option letter in the option table.
180a5f0fb15SPaul Saab 		 */
181*c77c4889SXin LI 		ambig = FALSE;
182a5f0fb15SPaul Saab 		if (optname == NULL)
183a5f0fb15SPaul Saab 		{
184a5f0fb15SPaul Saab 			printopt = propt(optc);
1856dcb072bSXin LI 			lc = ASCII_IS_LOWER(optc);
186a5f0fb15SPaul Saab 			o = findopt(optc);
187a5f0fb15SPaul Saab 		} else
188a5f0fb15SPaul Saab 		{
189a5f0fb15SPaul Saab 			printopt = optname;
1906dcb072bSXin LI 			lc = ASCII_IS_LOWER(optname[0]);
191*c77c4889SXin LI 			o = findopt_name(&optname, NULL, &ambig);
192a5f0fb15SPaul Saab 			s = optname;
193a5f0fb15SPaul Saab 			optname = NULL;
194a5f0fb15SPaul Saab 			if (*s == '\0' || *s == ' ')
195a5f0fb15SPaul Saab 			{
196a5f0fb15SPaul Saab 				/*
197a5f0fb15SPaul Saab 				 * The option name matches exactly.
198a5f0fb15SPaul Saab 				 */
199a5f0fb15SPaul Saab 				;
200a5f0fb15SPaul Saab 			} else if (*s == '=')
201a5f0fb15SPaul Saab 			{
202a5f0fb15SPaul Saab 				/*
203a5f0fb15SPaul Saab 				 * The option name is followed by "=value".
204a5f0fb15SPaul Saab 				 */
205a5f0fb15SPaul Saab 				if (o != NULL &&
206a5f0fb15SPaul Saab 				    (o->otype & OTYPE) != STRING &&
207a5f0fb15SPaul Saab 				    (o->otype & OTYPE) != NUMBER)
208a5f0fb15SPaul Saab 				{
209a5f0fb15SPaul Saab 					parg.p_string = printopt;
210a5f0fb15SPaul Saab 					error("The %s option should not be followed by =",
211a5f0fb15SPaul Saab 						&parg);
2124cc5fc9aSXin LI 					return;
213a5f0fb15SPaul Saab 				}
214a5f0fb15SPaul Saab 				s++;
215a5f0fb15SPaul Saab 			} else
216a5f0fb15SPaul Saab 			{
217a5f0fb15SPaul Saab 				/*
218a5f0fb15SPaul Saab 				 * The specified name is longer than the
219a5f0fb15SPaul Saab 				 * real option name.
220a5f0fb15SPaul Saab 				 */
221a5f0fb15SPaul Saab 				o = NULL;
222a5f0fb15SPaul Saab 			}
223a5f0fb15SPaul Saab 		}
224a5f0fb15SPaul Saab 		if (o == NULL)
225a5f0fb15SPaul Saab 		{
226a5f0fb15SPaul Saab 			parg.p_string = printopt;
227*c77c4889SXin LI 			if (ambig)
228a5f0fb15SPaul Saab 				error("%s is an ambiguous abbreviation (\"less --help\" for help)",
229a5f0fb15SPaul Saab 					&parg);
230a5f0fb15SPaul Saab 			else
231a5f0fb15SPaul Saab 				error("There is no %s option (\"less --help\" for help)",
232a5f0fb15SPaul Saab 					&parg);
2334cc5fc9aSXin LI 			return;
234a5f0fb15SPaul Saab 		}
235a5f0fb15SPaul Saab 
236a5f0fb15SPaul Saab 		str = NULL;
237a5f0fb15SPaul Saab 		switch (o->otype & OTYPE)
238a5f0fb15SPaul Saab 		{
239a5f0fb15SPaul Saab 		case BOOL:
240*c77c4889SXin LI 			if (o->otype & UNSUPPORTED)
241*c77c4889SXin LI 				break;
242*c77c4889SXin LI 			if (o->ovar != NULL)
243*c77c4889SXin LI 			{
244a5f0fb15SPaul Saab 				if (set_default)
245a5f0fb15SPaul Saab 					*(o->ovar) = o->odefault;
246a5f0fb15SPaul Saab 				else
247a5f0fb15SPaul Saab 					*(o->ovar) = ! o->odefault;
248*c77c4889SXin LI 			}
249a5f0fb15SPaul Saab 			break;
250a5f0fb15SPaul Saab 		case TRIPLE:
251*c77c4889SXin LI 			if (o->otype & UNSUPPORTED)
252*c77c4889SXin LI 				break;
253*c77c4889SXin LI 			if (o->ovar != NULL)
254*c77c4889SXin LI 			{
255a5f0fb15SPaul Saab 				if (set_default)
256a5f0fb15SPaul Saab 					*(o->ovar) = o->odefault;
257a5f0fb15SPaul Saab 				else
258a5f0fb15SPaul Saab 					*(o->ovar) = flip_triple(o->odefault, lc);
259*c77c4889SXin LI 			}
260a5f0fb15SPaul Saab 			break;
261a5f0fb15SPaul Saab 		case STRING:
262a5f0fb15SPaul Saab 			if (*s == '\0')
263a5f0fb15SPaul Saab 			{
264a5f0fb15SPaul Saab 				/*
265a5f0fb15SPaul Saab 				 * Set pendopt and return.
266a5f0fb15SPaul Saab 				 * We will get the string next time
267a5f0fb15SPaul Saab 				 * scan_option is called.
268a5f0fb15SPaul Saab 				 */
269a5f0fb15SPaul Saab 				pendopt = o;
270a5f0fb15SPaul Saab 				return;
271a5f0fb15SPaul Saab 			}
272a5f0fb15SPaul Saab 			/*
273a5f0fb15SPaul Saab 			 * Don't do anything here.
274a5f0fb15SPaul Saab 			 * All processing of STRING options is done by
275a5f0fb15SPaul Saab 			 * the handling function.
276a5f0fb15SPaul Saab 			 */
277000ba3e8STim J. Robbins 			while (*s == ' ')
278000ba3e8STim J. Robbins 				s++;
279000ba3e8STim J. Robbins 			s = optstring(s, &str, printopt, o->odesc[1]);
2804cc5fc9aSXin LI 			if (s == NULL)
2814cc5fc9aSXin LI 				return;
282a5f0fb15SPaul Saab 			break;
283a5f0fb15SPaul Saab 		case NUMBER:
284a5f0fb15SPaul Saab 			if (*s == '\0')
285a5f0fb15SPaul Saab 			{
286a5f0fb15SPaul Saab 				pendopt = o;
287a5f0fb15SPaul Saab 				return;
288a5f0fb15SPaul Saab 			}
289*c77c4889SXin LI 			if (o->otype & UNSUPPORTED)
290*c77c4889SXin LI 				break;
291*c77c4889SXin LI 			*(o->ovar) = getnumc(&s, printopt, NULL);
292a5f0fb15SPaul Saab 			break;
293a5f0fb15SPaul Saab 		}
294a5f0fb15SPaul Saab 		/*
295a5f0fb15SPaul Saab 		 * If the option has a handling function, call it.
296a5f0fb15SPaul Saab 		 */
297*c77c4889SXin LI 		if (o->ofunc != NULL && !(o->otype & UNSUPPORTED))
298a5f0fb15SPaul Saab 			(*o->ofunc)(INIT, str);
2994cc5fc9aSXin LI 		if (str != NULL)
3004cc5fc9aSXin LI 			free(str);
301a5f0fb15SPaul Saab 	}
302a5f0fb15SPaul Saab }
303a5f0fb15SPaul Saab 
304a5f0fb15SPaul Saab /*
305a5f0fb15SPaul Saab  * Toggle command line flags from within the program.
306a5f0fb15SPaul Saab  * Used by the "-" and "_" commands.
307a5f0fb15SPaul Saab  * how_toggle may be:
308a5f0fb15SPaul Saab  *      OPT_NO_TOGGLE   just report the current setting, without changing it.
309a5f0fb15SPaul Saab  *      OPT_TOGGLE      invert the current setting
310a5f0fb15SPaul Saab  *      OPT_UNSET       set to the default value
311a5f0fb15SPaul Saab  *      OPT_SET         set to the inverse of the default value
312a5f0fb15SPaul Saab  */
313*c77c4889SXin LI public void toggle_option(struct loption *o, int lower, constant char *s, int how_toggle)
314a5f0fb15SPaul Saab {
3151ea31627SRobert Watson 	int num;
316a5f0fb15SPaul Saab 	int no_prompt;
317*c77c4889SXin LI 	lbool err;
318a5f0fb15SPaul Saab 	PARG parg;
319a5f0fb15SPaul Saab 
320a5f0fb15SPaul Saab 	no_prompt = (how_toggle & OPT_NO_PROMPT);
321a5f0fb15SPaul Saab 	how_toggle &= ~OPT_NO_PROMPT;
322a5f0fb15SPaul Saab 
323a5f0fb15SPaul Saab 	if (o == NULL)
324a5f0fb15SPaul Saab 	{
32533096f16SXin LI 		error("No such option", NULL_PARG);
326a5f0fb15SPaul Saab 		return;
327a5f0fb15SPaul Saab 	}
328a5f0fb15SPaul Saab 
329a5f0fb15SPaul Saab 	if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE))
330a5f0fb15SPaul Saab 	{
33133096f16SXin LI 		parg.p_string = opt_desc(o);
332a5f0fb15SPaul Saab 		error("Cannot change the %s option", &parg);
333a5f0fb15SPaul Saab 		return;
334a5f0fb15SPaul Saab 	}
335a5f0fb15SPaul Saab 
336a5f0fb15SPaul Saab 	if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY))
337a5f0fb15SPaul Saab 	{
33833096f16SXin LI 		parg.p_string = opt_desc(o);
339a5f0fb15SPaul Saab 		error("Cannot query the %s option", &parg);
340a5f0fb15SPaul Saab 		return;
341a5f0fb15SPaul Saab 	}
342a5f0fb15SPaul Saab 
343a5f0fb15SPaul Saab 	/*
344a5f0fb15SPaul Saab 	 * Check for something which appears to be a do_toggle
345a5f0fb15SPaul Saab 	 * (because the "-" command was used), but really is not.
346a5f0fb15SPaul Saab 	 * This could be a string option with no string, or
347a5f0fb15SPaul Saab 	 * a number option with no number.
348a5f0fb15SPaul Saab 	 */
349a5f0fb15SPaul Saab 	switch (o->otype & OTYPE)
350a5f0fb15SPaul Saab 	{
351a5f0fb15SPaul Saab 	case STRING:
352a5f0fb15SPaul Saab 	case NUMBER:
353a5f0fb15SPaul Saab 		if (how_toggle == OPT_TOGGLE && *s == '\0')
354a5f0fb15SPaul Saab 			how_toggle = OPT_NO_TOGGLE;
355a5f0fb15SPaul Saab 		break;
356a5f0fb15SPaul Saab 	}
357a5f0fb15SPaul Saab 
358a5f0fb15SPaul Saab #if HILITE_SEARCH
359a5f0fb15SPaul Saab 	if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
360*c77c4889SXin LI 		repaint_hilite(FALSE);
361a5f0fb15SPaul Saab #endif
362a5f0fb15SPaul Saab 
363a5f0fb15SPaul Saab 	/*
364a5f0fb15SPaul Saab 	 * Now actually toggle (change) the variable.
365a5f0fb15SPaul Saab 	 */
366a5f0fb15SPaul Saab 	if (how_toggle != OPT_NO_TOGGLE)
367a5f0fb15SPaul Saab 	{
368a5f0fb15SPaul Saab 		switch (o->otype & OTYPE)
369a5f0fb15SPaul Saab 		{
370a5f0fb15SPaul Saab 		case BOOL:
371a5f0fb15SPaul Saab 			/*
372a5f0fb15SPaul Saab 			 * Boolean.
373a5f0fb15SPaul Saab 			 */
374*c77c4889SXin LI 			if (o->ovar != NULL)
375*c77c4889SXin LI 			{
376a5f0fb15SPaul Saab 				switch (how_toggle)
377a5f0fb15SPaul Saab 				{
378a5f0fb15SPaul Saab 				case OPT_TOGGLE:
379a5f0fb15SPaul Saab 					*(o->ovar) = ! *(o->ovar);
380a5f0fb15SPaul Saab 					break;
381a5f0fb15SPaul Saab 				case OPT_UNSET:
382a5f0fb15SPaul Saab 					*(o->ovar) = o->odefault;
383a5f0fb15SPaul Saab 					break;
384a5f0fb15SPaul Saab 				case OPT_SET:
385a5f0fb15SPaul Saab 					*(o->ovar) = ! o->odefault;
386a5f0fb15SPaul Saab 					break;
387a5f0fb15SPaul Saab 				}
388*c77c4889SXin LI 			}
389a5f0fb15SPaul Saab 			break;
390a5f0fb15SPaul Saab 		case TRIPLE:
391a5f0fb15SPaul Saab 			/*
392a5f0fb15SPaul Saab 			 * Triple:
393a5f0fb15SPaul Saab 			 *      If user gave the lower case letter, then switch
394a5f0fb15SPaul Saab 			 *      to 1 unless already 1, in which case make it 0.
395a5f0fb15SPaul Saab 			 *      If user gave the upper case letter, then switch
396a5f0fb15SPaul Saab 			 *      to 2 unless already 2, in which case make it 0.
397a5f0fb15SPaul Saab 			 */
398*c77c4889SXin LI 			if (o->ovar != NULL)
399*c77c4889SXin LI 			{
400a5f0fb15SPaul Saab 				switch (how_toggle)
401a5f0fb15SPaul Saab 				{
402a5f0fb15SPaul Saab 				case OPT_TOGGLE:
40333096f16SXin LI 					*(o->ovar) = flip_triple(*(o->ovar), lower);
404a5f0fb15SPaul Saab 					break;
405a5f0fb15SPaul Saab 				case OPT_UNSET:
406a5f0fb15SPaul Saab 					*(o->ovar) = o->odefault;
407a5f0fb15SPaul Saab 					break;
408a5f0fb15SPaul Saab 				case OPT_SET:
40933096f16SXin LI 					*(o->ovar) = flip_triple(o->odefault, lower);
410a5f0fb15SPaul Saab 					break;
411a5f0fb15SPaul Saab 				}
412*c77c4889SXin LI 			}
413a5f0fb15SPaul Saab 			break;
414a5f0fb15SPaul Saab 		case STRING:
415a5f0fb15SPaul Saab 			/*
416a5f0fb15SPaul Saab 			 * String: don't do anything here.
417a5f0fb15SPaul Saab 			 *      The handling function will do everything.
418a5f0fb15SPaul Saab 			 */
419a5f0fb15SPaul Saab 			switch (how_toggle)
420a5f0fb15SPaul Saab 			{
421a5f0fb15SPaul Saab 			case OPT_SET:
422a5f0fb15SPaul Saab 			case OPT_UNSET:
423a5f0fb15SPaul Saab 				error("Cannot use \"-+\" or \"--\" for a string option",
424a5f0fb15SPaul Saab 					NULL_PARG);
425a5f0fb15SPaul Saab 				return;
426a5f0fb15SPaul Saab 			}
427a5f0fb15SPaul Saab 			break;
428a5f0fb15SPaul Saab 		case NUMBER:
429a5f0fb15SPaul Saab 			/*
430a5f0fb15SPaul Saab 			 * Number: set the variable to the given number.
431a5f0fb15SPaul Saab 			 */
432a5f0fb15SPaul Saab 			switch (how_toggle)
433a5f0fb15SPaul Saab 			{
434a5f0fb15SPaul Saab 			case OPT_TOGGLE:
435*c77c4889SXin LI 				num = getnumc(&s, NULL, &err);
436a5f0fb15SPaul Saab 				if (!err)
437a5f0fb15SPaul Saab 					*(o->ovar) = num;
438a5f0fb15SPaul Saab 				break;
439a5f0fb15SPaul Saab 			case OPT_UNSET:
440a5f0fb15SPaul Saab 				*(o->ovar) = o->odefault;
441a5f0fb15SPaul Saab 				break;
442a5f0fb15SPaul Saab 			case OPT_SET:
443a5f0fb15SPaul Saab 				error("Can't use \"-!\" for a numeric option",
444a5f0fb15SPaul Saab 					NULL_PARG);
445a5f0fb15SPaul Saab 				return;
446a5f0fb15SPaul Saab 			}
447a5f0fb15SPaul Saab 			break;
448a5f0fb15SPaul Saab 		}
449a5f0fb15SPaul Saab 	}
450a5f0fb15SPaul Saab 
451a5f0fb15SPaul Saab 	/*
452a5f0fb15SPaul Saab 	 * Call the handling function for any special action
453a5f0fb15SPaul Saab 	 * specific to this option.
454a5f0fb15SPaul Saab 	 */
455a5f0fb15SPaul Saab 	if (o->ofunc != NULL)
456a5f0fb15SPaul Saab 		(*o->ofunc)((how_toggle==OPT_NO_TOGGLE) ? QUERY : TOGGLE, s);
457a5f0fb15SPaul Saab 
458a5f0fb15SPaul Saab #if HILITE_SEARCH
459a5f0fb15SPaul Saab 	if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
460a5f0fb15SPaul Saab 		chg_hilite();
461a5f0fb15SPaul Saab #endif
462a5f0fb15SPaul Saab 
463a5f0fb15SPaul Saab 	if (!no_prompt)
464a5f0fb15SPaul Saab 	{
465a5f0fb15SPaul Saab 		/*
466a5f0fb15SPaul Saab 		 * Print a message describing the new setting.
467a5f0fb15SPaul Saab 		 */
468a5f0fb15SPaul Saab 		switch (o->otype & OTYPE)
469a5f0fb15SPaul Saab 		{
470a5f0fb15SPaul Saab 		case BOOL:
471a5f0fb15SPaul Saab 		case TRIPLE:
472a5f0fb15SPaul Saab 			/*
473a5f0fb15SPaul Saab 			 * Print the odesc message.
474a5f0fb15SPaul Saab 			 */
475*c77c4889SXin LI 			if (o->ovar != NULL)
476a5f0fb15SPaul Saab 				error(o->odesc[*(o->ovar)], NULL_PARG);
477a5f0fb15SPaul Saab 			break;
478a5f0fb15SPaul Saab 		case NUMBER:
479a5f0fb15SPaul Saab 			/*
480a5f0fb15SPaul Saab 			 * The message is in odesc[1] and has a %d for
481a5f0fb15SPaul Saab 			 * the value of the variable.
482a5f0fb15SPaul Saab 			 */
483a5f0fb15SPaul Saab 			parg.p_int = *(o->ovar);
484a5f0fb15SPaul Saab 			error(o->odesc[1], &parg);
485a5f0fb15SPaul Saab 			break;
486a5f0fb15SPaul Saab 		case STRING:
487a5f0fb15SPaul Saab 			/*
488a5f0fb15SPaul Saab 			 * Message was already printed by the handling function.
489a5f0fb15SPaul Saab 			 */
490a5f0fb15SPaul Saab 			break;
491a5f0fb15SPaul Saab 		}
492a5f0fb15SPaul Saab 	}
493a5f0fb15SPaul Saab 
494a5f0fb15SPaul Saab 	if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT))
495*c77c4889SXin LI 		screen_trashed();
496a5f0fb15SPaul Saab }
497a5f0fb15SPaul Saab 
498a5f0fb15SPaul Saab /*
499a5f0fb15SPaul Saab  * "Toggle" a triple-valued option.
500a5f0fb15SPaul Saab  */
501d713e089SXin LI static int flip_triple(int val, int lc)
502a5f0fb15SPaul Saab {
503a5f0fb15SPaul Saab 	if (lc)
504a5f0fb15SPaul Saab 		return ((val == OPT_ON) ? OPT_OFF : OPT_ON);
505a5f0fb15SPaul Saab 	else
506a5f0fb15SPaul Saab 		return ((val == OPT_ONPLUS) ? OPT_OFF : OPT_ONPLUS);
507a5f0fb15SPaul Saab }
508a5f0fb15SPaul Saab 
509a5f0fb15SPaul Saab /*
51033096f16SXin LI  * Determine if an option takes a parameter.
511a5f0fb15SPaul Saab  */
512d713e089SXin LI public int opt_has_param(struct loption *o)
513a5f0fb15SPaul Saab {
514a5f0fb15SPaul Saab 	if (o == NULL)
51533096f16SXin LI 		return (0);
51633096f16SXin LI 	if (o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE))
51733096f16SXin LI 		return (0);
51833096f16SXin LI 	return (1);
519a5f0fb15SPaul Saab }
520a5f0fb15SPaul Saab 
521a5f0fb15SPaul Saab /*
522a5f0fb15SPaul Saab  * Return the prompt to be used for a given option letter.
523a5f0fb15SPaul Saab  * Only string and number valued options have prompts.
524a5f0fb15SPaul Saab  */
525*c77c4889SXin LI public constant char * opt_prompt(struct loption *o)
526a5f0fb15SPaul Saab {
527a5f0fb15SPaul Saab 	if (o == NULL || (o->otype & (STRING|NUMBER)) == 0)
52833096f16SXin LI 		return ("?");
529a5f0fb15SPaul Saab 	return (o->odesc[0]);
530a5f0fb15SPaul Saab }
531a5f0fb15SPaul Saab 
532a5f0fb15SPaul Saab /*
5336f26c71dSXin LI  * If the specified option can be toggled, return NULL.
5346f26c71dSXin LI  * Otherwise return an appropriate error message.
5356f26c71dSXin LI  */
536*c77c4889SXin LI public constant char * opt_toggle_disallowed(int c)
5376f26c71dSXin LI {
5386f26c71dSXin LI 	switch (c)
5396f26c71dSXin LI 	{
5406f26c71dSXin LI 	case 'o':
5416f26c71dSXin LI 		if (ch_getflags() & CH_CANSEEK)
5426f26c71dSXin LI 			return "Input is not a pipe";
5436f26c71dSXin LI 		break;
5446f26c71dSXin LI 	}
5456f26c71dSXin LI 	return NULL;
5466f26c71dSXin LI }
5476f26c71dSXin LI 
5486f26c71dSXin LI /*
549a5f0fb15SPaul Saab  * Return whether or not there is a string option pending;
550a5f0fb15SPaul Saab  * that is, if the previous option was a string-valued option letter
551a5f0fb15SPaul Saab  * (like -P) without a following string.
552a5f0fb15SPaul Saab  * In that case, the current option is taken to be the string for
553a5f0fb15SPaul Saab  * the previous option.
554a5f0fb15SPaul Saab  */
555*c77c4889SXin LI public lbool isoptpending(void)
556a5f0fb15SPaul Saab {
557a5f0fb15SPaul Saab 	return (pendopt != NULL);
558a5f0fb15SPaul Saab }
559a5f0fb15SPaul Saab 
560a5f0fb15SPaul Saab /*
561a5f0fb15SPaul Saab  * Print error message about missing string.
562a5f0fb15SPaul Saab  */
563*c77c4889SXin LI static void nostring(constant char *printopt)
564a5f0fb15SPaul Saab {
565a5f0fb15SPaul Saab 	PARG parg;
566a5f0fb15SPaul Saab 	parg.p_string = printopt;
567a5f0fb15SPaul Saab 	error("Value is required after %s", &parg);
568a5f0fb15SPaul Saab }
569a5f0fb15SPaul Saab 
570a5f0fb15SPaul Saab /*
571a5f0fb15SPaul Saab  * Print error message if a STRING type option is not followed by a string.
572a5f0fb15SPaul Saab  */
573d713e089SXin LI public void nopendopt(void)
574a5f0fb15SPaul Saab {
57533096f16SXin LI 	nostring(opt_desc(pendopt));
576a5f0fb15SPaul Saab }
577a5f0fb15SPaul Saab 
578a5f0fb15SPaul Saab /*
579a5f0fb15SPaul Saab  * Scan to end of string or to an END_OPTION_STRING character.
580a5f0fb15SPaul Saab  * In the latter case, replace the char with a null char.
581a5f0fb15SPaul Saab  * Return a pointer to the remainder of the string, if any.
582*c77c4889SXin LI  * validchars is of the form "[-][.]d[,]".
583*c77c4889SXin LI  *   "-" means an optional leading "-" is allowed
584*c77c4889SXin LI  *   "." means an optional leading "." is allowed (after any "-")
585*c77c4889SXin LI  *   "d" indicates a string of one or more digits (0-9)
586*c77c4889SXin LI  *   "," indicates a comma-separated list of digit strings is allowed
587*c77c4889SXin LI  *   "s" means a space char terminates the argument
588a5f0fb15SPaul Saab  */
589*c77c4889SXin LI static constant char * optstring(constant char *s, char **p_str, constant char *printopt, constant char *validchars)
590a5f0fb15SPaul Saab {
591*c77c4889SXin LI 	constant char *p;
5921ea31627SRobert Watson 	char *out;
593a5f0fb15SPaul Saab 
594a5f0fb15SPaul Saab 	if (*s == '\0')
595a5f0fb15SPaul Saab 	{
596a5f0fb15SPaul Saab 		nostring(printopt);
5974cc5fc9aSXin LI 		return (NULL);
598a5f0fb15SPaul Saab 	}
5994cc5fc9aSXin LI 	/* Alloc could be more than needed, but not worth trimming. */
6004cc5fc9aSXin LI 	*p_str = (char *) ecalloc(strlen(s)+1, sizeof(char));
6014cc5fc9aSXin LI 	out = *p_str;
6024cc5fc9aSXin LI 
603a5f0fb15SPaul Saab 	for (p = s;  *p != '\0';  p++)
604000ba3e8STim J. Robbins 	{
6057bd2567cSXin LI 		if (opt_use_backslash && *p == '\\' && p[1] != '\0')
6064cc5fc9aSXin LI 		{
6074cc5fc9aSXin LI 			/* Take next char literally. */
6084cc5fc9aSXin LI 			++p;
6094cc5fc9aSXin LI 		} else
6104cc5fc9aSXin LI 		{
611*c77c4889SXin LI 			if (validchars != NULL)
612*c77c4889SXin LI 			{
613*c77c4889SXin LI 				if (validchars[0] == 's')
614*c77c4889SXin LI 				{
615*c77c4889SXin LI 					if (*p == ' ')
616*c77c4889SXin LI 						break;
617*c77c4889SXin LI 				} else if (*p == '-')
618*c77c4889SXin LI 				{
619*c77c4889SXin LI 					if (validchars[0] != '-')
620*c77c4889SXin LI 						break;
621*c77c4889SXin LI 					++validchars;
622*c77c4889SXin LI 				} else if (*p == '.')
623*c77c4889SXin LI 				{
624*c77c4889SXin LI 					if (validchars[0] == '-')
625*c77c4889SXin LI 						++validchars;
626*c77c4889SXin LI 					if (validchars[0] != '.')
627*c77c4889SXin LI 						break;
628*c77c4889SXin LI 					++validchars;
629*c77c4889SXin LI 				} else if (*p == ',')
630*c77c4889SXin LI 				{
631*c77c4889SXin LI 					if (validchars[0] == '\0' || validchars[1] != ',')
632*c77c4889SXin LI 						break;
633*c77c4889SXin LI 				} else if (*p >= '0' && *p <= '9')
634*c77c4889SXin LI 				{
635*c77c4889SXin LI 					while (validchars[0] == '-' || validchars[0] == '.')
636*c77c4889SXin LI 						++validchars;
637*c77c4889SXin LI 					if (validchars[0] != 'd')
638*c77c4889SXin LI 						break;
639*c77c4889SXin LI 				} else
640*c77c4889SXin LI 					break;
641*c77c4889SXin LI 			}
642*c77c4889SXin LI 			if (*p == END_OPTION_STRING)
6434cc5fc9aSXin LI 				/* End of option string. */
644c9346414SPaul Saab 				break;
645c9346414SPaul Saab 		}
6464cc5fc9aSXin LI 		*out++ = *p;
647000ba3e8STim J. Robbins 	}
6484cc5fc9aSXin LI 	*out = '\0';
649a5f0fb15SPaul Saab 	return (p);
650a5f0fb15SPaul Saab }
651a5f0fb15SPaul Saab 
652a5f0fb15SPaul Saab /*
6537f074f9cSXin LI  */
654*c77c4889SXin LI static int num_error(constant char *printopt, lbool *errp, lbool overflow)
6557f074f9cSXin LI {
6567f074f9cSXin LI 	PARG parg;
6577f074f9cSXin LI 
6587f074f9cSXin LI 	if (errp != NULL)
6597f074f9cSXin LI 	{
6607f074f9cSXin LI 		*errp = TRUE;
6617f074f9cSXin LI 		return (-1);
6627f074f9cSXin LI 	}
6637f074f9cSXin LI 	if (printopt != NULL)
6647f074f9cSXin LI 	{
6657f074f9cSXin LI 		parg.p_string = printopt;
666d713e089SXin LI 		error((overflow
667d713e089SXin LI 		       ? "Number too large in '%s'"
668d713e089SXin LI 		       : "Number is required after %s"),
669d713e089SXin LI 		      &parg);
6707f074f9cSXin LI 	}
6717f074f9cSXin LI 	return (-1);
6727f074f9cSXin LI }
6737f074f9cSXin LI 
6747f074f9cSXin LI /*
675a5f0fb15SPaul Saab  * Translate a string into a number.
676a5f0fb15SPaul Saab  * Like atoi(), but takes a pointer to a char *, and updates
677a5f0fb15SPaul Saab  * the char * to point after the translated number.
678a5f0fb15SPaul Saab  */
679*c77c4889SXin LI public int getnumc(constant char **sp, constant char *printopt, lbool *errp)
680a5f0fb15SPaul Saab {
681*c77c4889SXin LI 	constant char *s = *sp;
6821ea31627SRobert Watson 	int n;
683*c77c4889SXin LI 	lbool neg;
684a5f0fb15SPaul Saab 
685*c77c4889SXin LI 	s = skipspc(s);
686a5f0fb15SPaul Saab 	neg = FALSE;
687a5f0fb15SPaul Saab 	if (*s == '-')
688a5f0fb15SPaul Saab 	{
689a5f0fb15SPaul Saab 		neg = TRUE;
690a5f0fb15SPaul Saab 		s++;
691a5f0fb15SPaul Saab 	}
692a5f0fb15SPaul Saab 	if (*s < '0' || *s > '9')
693d713e089SXin LI 		return (num_error(printopt, errp, FALSE));
694a5f0fb15SPaul Saab 
695*c77c4889SXin LI 	n = lstrtoic(s, sp, 10);
696d713e089SXin LI 	if (n < 0)
697d713e089SXin LI 		return (num_error(printopt, errp, TRUE));
698a5f0fb15SPaul Saab 	if (errp != NULL)
699a5f0fb15SPaul Saab 		*errp = FALSE;
700a5f0fb15SPaul Saab 	if (neg)
701a5f0fb15SPaul Saab 		n = -n;
702a5f0fb15SPaul Saab 	return (n);
703a5f0fb15SPaul Saab }
7047f074f9cSXin LI 
705*c77c4889SXin LI public int getnum(char **sp, constant char *printopt, lbool *errp)
706*c77c4889SXin LI {
707*c77c4889SXin LI 	constant char *cs = *sp;
708*c77c4889SXin LI 	int r = getnumc(&cs, printopt, errp);
709*c77c4889SXin LI 	*sp = (char *) cs;
710*c77c4889SXin LI 	return r;
711*c77c4889SXin LI }
712*c77c4889SXin LI 
7137f074f9cSXin LI /*
7147f074f9cSXin LI  * Translate a string into a fraction, represented by the part of a
7157f074f9cSXin LI  * number which would follow a decimal point.
7167f074f9cSXin LI  * The value of the fraction is returned as parts per NUM_FRAC_DENOM.
7177f074f9cSXin LI  * That is, if "n" is returned, the fraction intended is n/NUM_FRAC_DENOM.
7187f074f9cSXin LI  */
719*c77c4889SXin LI public long getfraction(constant char **sp, constant char *printopt, lbool *errp)
7207f074f9cSXin LI {
721*c77c4889SXin LI 	constant char *s;
7227f074f9cSXin LI 	long frac = 0;
7237f074f9cSXin LI 	int fraclen = 0;
7247f074f9cSXin LI 
725*c77c4889SXin LI 	s = skipspc(*sp);
7267f074f9cSXin LI 	if (*s < '0' || *s > '9')
727d713e089SXin LI 		return (num_error(printopt, errp, FALSE));
7287f074f9cSXin LI 
7297f074f9cSXin LI 	for ( ;  *s >= '0' && *s <= '9';  s++)
7307f074f9cSXin LI 	{
731d713e089SXin LI 		if (NUM_LOG_FRAC_DENOM <= fraclen)
732d713e089SXin LI 			continue;
7337f074f9cSXin LI 		frac = (frac * 10) + (*s - '0');
7347f074f9cSXin LI 		fraclen++;
7357f074f9cSXin LI 	}
7367f074f9cSXin LI 	while (fraclen++ < NUM_LOG_FRAC_DENOM)
7377f074f9cSXin LI 		frac *= 10;
7387f074f9cSXin LI 	*sp = s;
7397f074f9cSXin LI 	if (errp != NULL)
7407f074f9cSXin LI 		*errp = FALSE;
7417f074f9cSXin LI 	return (frac);
7427f074f9cSXin LI }
7437f074f9cSXin LI 
744*c77c4889SXin LI /*
745*c77c4889SXin LI  * Set the UNSUPPORTED bit in every option listed
746*c77c4889SXin LI  * in the LESS_UNSUPPORT environment variable.
747*c77c4889SXin LI  */
748*c77c4889SXin LI public void init_unsupport(void)
749*c77c4889SXin LI {
750*c77c4889SXin LI 	constant char *s = lgetenv("LESS_UNSUPPORT");
751*c77c4889SXin LI 	if (isnullenv(s))
752*c77c4889SXin LI 		return;
753*c77c4889SXin LI 	for (;;)
754*c77c4889SXin LI 	{
755*c77c4889SXin LI 		struct loption *opt;
756*c77c4889SXin LI 		s = skipspc(s);
757*c77c4889SXin LI 		if (*s == '\0') break;
758*c77c4889SXin LI 		if (*s == '-' && *++s == '\0') break;
759*c77c4889SXin LI 		if (*s == '-') /* long option name */
760*c77c4889SXin LI 		{
761*c77c4889SXin LI 			++s;
762*c77c4889SXin LI 			opt = findopt_name(&s, NULL, NULL);
763*c77c4889SXin LI 		} else /* short (single-char) option */
764*c77c4889SXin LI 		{
765*c77c4889SXin LI 			opt = findopt(*s);
766*c77c4889SXin LI 			if (opt != NULL) ++s;
767*c77c4889SXin LI 		}
768*c77c4889SXin LI 		if (opt != NULL)
769*c77c4889SXin LI 			opt->otype |= UNSUPPORTED;
770*c77c4889SXin LI 	}
771*c77c4889SXin LI }
7727f074f9cSXin LI 
7737f074f9cSXin LI /*
7747f074f9cSXin LI  * Get the value of the -e flag.
7757f074f9cSXin LI  */
776d713e089SXin LI public int get_quit_at_eof(void)
7777f074f9cSXin LI {
7787f074f9cSXin LI 	if (!less_is_more)
7797f074f9cSXin LI 		return quit_at_eof;
7807f074f9cSXin LI 	/* When less_is_more is set, the -e flag semantics are different. */
781a15691bfSXin LI 	return quit_at_eof ? OPT_ONPLUS : OPT_ON;
7827f074f9cSXin LI }
783