xref: /freebsd/contrib/less/option.c (revision d713e0891ff9ab8246245c3206851d486ecfdd37)
1a5f0fb15SPaul Saab /*
2*d713e089SXin LI  * Copyright (C) 1984-2023  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;
24a5f0fb15SPaul Saab public int plusoption = FALSE;
25a5f0fb15SPaul Saab 
26*d713e089SXin LI static char *optstring(char *s, char **p_str, char *printopt, char *validchars);
27*d713e089SXin LI static int flip_triple(int val, int lc);
28a5f0fb15SPaul Saab 
29a5f0fb15SPaul Saab extern int screen_trashed;
307f074f9cSXin LI extern int less_is_more;
317f074f9cSXin LI extern int quit_at_eof;
32a5f0fb15SPaul Saab extern char *every_first_cmd;
337bd2567cSXin LI extern int opt_use_backslash;
34a5f0fb15SPaul Saab 
35a5f0fb15SPaul Saab /*
3633096f16SXin LI  * Return a printable description of an option.
3733096f16SXin LI  */
38*d713e089SXin LI static char * opt_desc(struct loption *o)
3933096f16SXin LI {
4033096f16SXin LI 	static char buf[OPTNAME_MAX + 10];
4133096f16SXin LI 	if (o->oletter == OLETTER_NONE)
4233096f16SXin LI 		SNPRINTF1(buf, sizeof(buf), "--%s", o->onames->oname);
4333096f16SXin LI 	else
4433096f16SXin LI 		SNPRINTF2(buf, sizeof(buf), "-%c (--%s)", o->oletter, o->onames->oname);
4533096f16SXin LI 	return (buf);
4633096f16SXin LI }
4733096f16SXin LI 
4833096f16SXin LI /*
4933096f16SXin LI  * Return a string suitable for printing as the "name" of an option.
5033096f16SXin LI  * For example, if the option letter is 'x', just return "-x".
5133096f16SXin LI  */
52*d713e089SXin LI public char * propt(int c)
5333096f16SXin LI {
5495270f73SXin LI 	static char buf[MAX_PRCHAR_LEN+2];
5533096f16SXin LI 
5633096f16SXin LI 	sprintf(buf, "-%s", prchar(c));
5733096f16SXin LI 	return (buf);
5833096f16SXin LI }
5933096f16SXin LI 
6033096f16SXin LI /*
61a5f0fb15SPaul Saab  * Scan an argument (either from the command line or from the
62a5f0fb15SPaul Saab  * LESS environment variable) and process it.
63a5f0fb15SPaul Saab  */
64*d713e089SXin LI public void scan_option(char *s)
65a5f0fb15SPaul Saab {
661ea31627SRobert Watson 	struct loption *o;
671ea31627SRobert Watson 	int optc;
68a5f0fb15SPaul Saab 	char *optname;
69a5f0fb15SPaul Saab 	char *printopt;
70a5f0fb15SPaul Saab 	char *str;
71a5f0fb15SPaul Saab 	int set_default;
72a5f0fb15SPaul Saab 	int lc;
73a5f0fb15SPaul Saab 	int err;
74a5f0fb15SPaul Saab 	PARG parg;
75a5f0fb15SPaul Saab 
76a5f0fb15SPaul Saab 	if (s == NULL)
77a5f0fb15SPaul Saab 		return;
78a5f0fb15SPaul Saab 
79a5f0fb15SPaul Saab 	/*
80a5f0fb15SPaul Saab 	 * If we have a pending option which requires an argument,
81a5f0fb15SPaul Saab 	 * handle it now.
82a5f0fb15SPaul Saab 	 * This happens if the previous option was, for example, "-P"
83a5f0fb15SPaul Saab 	 * without a following string.  In that case, the current
84a5f0fb15SPaul Saab 	 * option is simply the argument for the previous option.
85a5f0fb15SPaul Saab 	 */
86a5f0fb15SPaul Saab 	if (pendopt != NULL)
87a5f0fb15SPaul Saab 	{
88a5f0fb15SPaul Saab 		switch (pendopt->otype & OTYPE)
89a5f0fb15SPaul Saab 		{
90a5f0fb15SPaul Saab 		case STRING:
91a5f0fb15SPaul Saab 			(*pendopt->ofunc)(INIT, s);
92a5f0fb15SPaul Saab 			break;
93a5f0fb15SPaul Saab 		case NUMBER:
9433096f16SXin LI 			printopt = opt_desc(pendopt);
95a5f0fb15SPaul Saab 			*(pendopt->ovar) = getnum(&s, printopt, (int*)NULL);
96a5f0fb15SPaul Saab 			break;
97a5f0fb15SPaul Saab 		}
98a5f0fb15SPaul Saab 		pendopt = NULL;
99a5f0fb15SPaul Saab 		return;
100a5f0fb15SPaul Saab 	}
101a5f0fb15SPaul Saab 
102a5f0fb15SPaul Saab 	set_default = FALSE;
103a5f0fb15SPaul Saab 	optname = NULL;
104a5f0fb15SPaul Saab 
105a5f0fb15SPaul Saab 	while (*s != '\0')
106a5f0fb15SPaul Saab 	{
107a5f0fb15SPaul Saab 		/*
108a5f0fb15SPaul Saab 		 * Check some special cases first.
109a5f0fb15SPaul Saab 		 */
110a5f0fb15SPaul Saab 		switch (optc = *s++)
111a5f0fb15SPaul Saab 		{
112a5f0fb15SPaul Saab 		case ' ':
113a5f0fb15SPaul Saab 		case '\t':
114a5f0fb15SPaul Saab 		case END_OPTION_STRING:
115a5f0fb15SPaul Saab 			continue;
116a5f0fb15SPaul Saab 		case '-':
117a5f0fb15SPaul Saab 			/*
118a5f0fb15SPaul Saab 			 * "--" indicates an option name instead of a letter.
119a5f0fb15SPaul Saab 			 */
120a5f0fb15SPaul Saab 			if (*s == '-')
121a5f0fb15SPaul Saab 			{
122a5f0fb15SPaul Saab 				optname = ++s;
123a5f0fb15SPaul Saab 				break;
124a5f0fb15SPaul Saab 			}
125a5f0fb15SPaul Saab 			/*
126a5f0fb15SPaul Saab 			 * "-+" means set these options back to their defaults.
127a5f0fb15SPaul Saab 			 * (They may have been set otherwise by previous
128a5f0fb15SPaul Saab 			 * options.)
129a5f0fb15SPaul Saab 			 */
130a5f0fb15SPaul Saab 			set_default = (*s == '+');
131a5f0fb15SPaul Saab 			if (set_default)
132a5f0fb15SPaul Saab 				s++;
133a5f0fb15SPaul Saab 			continue;
134a5f0fb15SPaul Saab 		case '+':
135a5f0fb15SPaul Saab 			/*
136a5f0fb15SPaul Saab 			 * An option prefixed by a "+" is ungotten, so
137a5f0fb15SPaul Saab 			 * that it is interpreted as less commands
138a5f0fb15SPaul Saab 			 * processed at the start of the first input file.
139a5f0fb15SPaul Saab 			 * "++" means process the commands at the start of
140a5f0fb15SPaul Saab 			 * EVERY input file.
141a5f0fb15SPaul Saab 			 */
142a5f0fb15SPaul Saab 			plusoption = TRUE;
143000ba3e8STim J. Robbins 			s = optstring(s, &str, propt('+'), NULL);
1444cc5fc9aSXin LI 			if (s == NULL)
1454cc5fc9aSXin LI 				return;
146c9346414SPaul Saab 			if (*str == '+')
147b7780dbeSXin LI 			{
148b7780dbeSXin LI 				if (every_first_cmd != NULL)
149b7780dbeSXin LI 					free(every_first_cmd);
15021fa6541SXin LI 				every_first_cmd = save(str+1);
151b7780dbeSXin LI 			} else
152a15691bfSXin LI 			{
153c9346414SPaul Saab 				ungetsc(str);
1542235c7feSXin LI 				ungetcc_back(CHAR_END_COMMAND);
155a15691bfSXin LI 			}
1564cc5fc9aSXin LI 			free(str);
157a5f0fb15SPaul Saab 			continue;
158a5f0fb15SPaul Saab 		case '0':  case '1':  case '2':  case '3':  case '4':
159a5f0fb15SPaul Saab 		case '5':  case '6':  case '7':  case '8':  case '9':
160a5f0fb15SPaul Saab 			/*
161a5f0fb15SPaul Saab 			 * Special "more" compatibility form "-<number>"
162a5f0fb15SPaul Saab 			 * instead of -z<number> to set the scrolling
163a5f0fb15SPaul Saab 			 * window size.
164a5f0fb15SPaul Saab 			 */
165a5f0fb15SPaul Saab 			s--;
166a5f0fb15SPaul Saab 			optc = 'z';
167a5f0fb15SPaul Saab 			break;
1687f074f9cSXin LI 		case 'n':
1697f074f9cSXin LI 			if (less_is_more)
1707f074f9cSXin LI 				optc = 'z';
1717f074f9cSXin LI 			break;
172a5f0fb15SPaul Saab 		}
173a5f0fb15SPaul Saab 
174a5f0fb15SPaul Saab 		/*
175a5f0fb15SPaul Saab 		 * Not a special case.
176a5f0fb15SPaul Saab 		 * Look up the option letter in the option table.
177a5f0fb15SPaul Saab 		 */
178a5f0fb15SPaul Saab 		err = 0;
179a5f0fb15SPaul Saab 		if (optname == NULL)
180a5f0fb15SPaul Saab 		{
181a5f0fb15SPaul Saab 			printopt = propt(optc);
1826dcb072bSXin LI 			lc = ASCII_IS_LOWER(optc);
183a5f0fb15SPaul Saab 			o = findopt(optc);
184a5f0fb15SPaul Saab 		} else
185a5f0fb15SPaul Saab 		{
186a5f0fb15SPaul Saab 			printopt = optname;
1876dcb072bSXin LI 			lc = ASCII_IS_LOWER(optname[0]);
188a5f0fb15SPaul Saab 			o = findopt_name(&optname, NULL, &err);
189a5f0fb15SPaul Saab 			s = optname;
190a5f0fb15SPaul Saab 			optname = NULL;
191a5f0fb15SPaul Saab 			if (*s == '\0' || *s == ' ')
192a5f0fb15SPaul Saab 			{
193a5f0fb15SPaul Saab 				/*
194a5f0fb15SPaul Saab 				 * The option name matches exactly.
195a5f0fb15SPaul Saab 				 */
196a5f0fb15SPaul Saab 				;
197a5f0fb15SPaul Saab 			} else if (*s == '=')
198a5f0fb15SPaul Saab 			{
199a5f0fb15SPaul Saab 				/*
200a5f0fb15SPaul Saab 				 * The option name is followed by "=value".
201a5f0fb15SPaul Saab 				 */
202a5f0fb15SPaul Saab 				if (o != NULL &&
203a5f0fb15SPaul Saab 				    (o->otype & OTYPE) != STRING &&
204a5f0fb15SPaul Saab 				    (o->otype & OTYPE) != NUMBER)
205a5f0fb15SPaul Saab 				{
206a5f0fb15SPaul Saab 					parg.p_string = printopt;
207a5f0fb15SPaul Saab 					error("The %s option should not be followed by =",
208a5f0fb15SPaul Saab 						&parg);
2094cc5fc9aSXin LI 					return;
210a5f0fb15SPaul Saab 				}
211a5f0fb15SPaul Saab 				s++;
212a5f0fb15SPaul Saab 			} else
213a5f0fb15SPaul Saab 			{
214a5f0fb15SPaul Saab 				/*
215a5f0fb15SPaul Saab 				 * The specified name is longer than the
216a5f0fb15SPaul Saab 				 * real option name.
217a5f0fb15SPaul Saab 				 */
218a5f0fb15SPaul Saab 				o = NULL;
219a5f0fb15SPaul Saab 			}
220a5f0fb15SPaul Saab 		}
221a5f0fb15SPaul Saab 		if (o == NULL)
222a5f0fb15SPaul Saab 		{
223a5f0fb15SPaul Saab 			parg.p_string = printopt;
224a5f0fb15SPaul Saab 			if (err == OPT_AMBIG)
225a5f0fb15SPaul Saab 				error("%s is an ambiguous abbreviation (\"less --help\" for help)",
226a5f0fb15SPaul Saab 					&parg);
227a5f0fb15SPaul Saab 			else
228a5f0fb15SPaul Saab 				error("There is no %s option (\"less --help\" for help)",
229a5f0fb15SPaul Saab 					&parg);
2304cc5fc9aSXin LI 			return;
231a5f0fb15SPaul Saab 		}
232a5f0fb15SPaul Saab 
233a5f0fb15SPaul Saab 		str = NULL;
234a5f0fb15SPaul Saab 		switch (o->otype & OTYPE)
235a5f0fb15SPaul Saab 		{
236a5f0fb15SPaul Saab 		case BOOL:
237a5f0fb15SPaul Saab 			if (set_default)
238a5f0fb15SPaul Saab 				*(o->ovar) = o->odefault;
239a5f0fb15SPaul Saab 			else
240a5f0fb15SPaul Saab 				*(o->ovar) = ! o->odefault;
241a5f0fb15SPaul Saab 			break;
242a5f0fb15SPaul Saab 		case TRIPLE:
243a5f0fb15SPaul Saab 			if (set_default)
244a5f0fb15SPaul Saab 				*(o->ovar) = o->odefault;
245a5f0fb15SPaul Saab 			else
246a5f0fb15SPaul Saab 				*(o->ovar) = flip_triple(o->odefault, lc);
247a5f0fb15SPaul Saab 			break;
248a5f0fb15SPaul Saab 		case STRING:
249a5f0fb15SPaul Saab 			if (*s == '\0')
250a5f0fb15SPaul Saab 			{
251a5f0fb15SPaul Saab 				/*
252a5f0fb15SPaul Saab 				 * Set pendopt and return.
253a5f0fb15SPaul Saab 				 * We will get the string next time
254a5f0fb15SPaul Saab 				 * scan_option is called.
255a5f0fb15SPaul Saab 				 */
256a5f0fb15SPaul Saab 				pendopt = o;
257a5f0fb15SPaul Saab 				return;
258a5f0fb15SPaul Saab 			}
259a5f0fb15SPaul Saab 			/*
260a5f0fb15SPaul Saab 			 * Don't do anything here.
261a5f0fb15SPaul Saab 			 * All processing of STRING options is done by
262a5f0fb15SPaul Saab 			 * the handling function.
263a5f0fb15SPaul Saab 			 */
264000ba3e8STim J. Robbins 			while (*s == ' ')
265000ba3e8STim J. Robbins 				s++;
266000ba3e8STim J. Robbins 			s = optstring(s, &str, printopt, o->odesc[1]);
2674cc5fc9aSXin LI 			if (s == NULL)
2684cc5fc9aSXin LI 				return;
269a5f0fb15SPaul Saab 			break;
270a5f0fb15SPaul Saab 		case NUMBER:
271a5f0fb15SPaul Saab 			if (*s == '\0')
272a5f0fb15SPaul Saab 			{
273a5f0fb15SPaul Saab 				pendopt = o;
274a5f0fb15SPaul Saab 				return;
275a5f0fb15SPaul Saab 			}
276a5f0fb15SPaul Saab 			*(o->ovar) = getnum(&s, printopt, (int*)NULL);
277a5f0fb15SPaul Saab 			break;
278a5f0fb15SPaul Saab 		}
279a5f0fb15SPaul Saab 		/*
280a5f0fb15SPaul Saab 		 * If the option has a handling function, call it.
281a5f0fb15SPaul Saab 		 */
282a5f0fb15SPaul Saab 		if (o->ofunc != NULL)
283a5f0fb15SPaul Saab 			(*o->ofunc)(INIT, str);
2844cc5fc9aSXin LI 		if (str != NULL)
2854cc5fc9aSXin LI 			free(str);
286a5f0fb15SPaul Saab 	}
287a5f0fb15SPaul Saab }
288a5f0fb15SPaul Saab 
289a5f0fb15SPaul Saab /*
290a5f0fb15SPaul Saab  * Toggle command line flags from within the program.
291a5f0fb15SPaul Saab  * Used by the "-" and "_" commands.
292a5f0fb15SPaul Saab  * how_toggle may be:
293a5f0fb15SPaul Saab  *      OPT_NO_TOGGLE   just report the current setting, without changing it.
294a5f0fb15SPaul Saab  *      OPT_TOGGLE      invert the current setting
295a5f0fb15SPaul Saab  *      OPT_UNSET       set to the default value
296a5f0fb15SPaul Saab  *      OPT_SET         set to the inverse of the default value
297a5f0fb15SPaul Saab  */
298*d713e089SXin LI public void toggle_option(struct loption *o, int lower, char *s, int how_toggle)
299a5f0fb15SPaul Saab {
3001ea31627SRobert Watson 	int num;
301a5f0fb15SPaul Saab 	int no_prompt;
302a5f0fb15SPaul Saab 	int err;
303a5f0fb15SPaul Saab 	PARG parg;
304a5f0fb15SPaul Saab 
305a5f0fb15SPaul Saab 	no_prompt = (how_toggle & OPT_NO_PROMPT);
306a5f0fb15SPaul Saab 	how_toggle &= ~OPT_NO_PROMPT;
307a5f0fb15SPaul Saab 
308a5f0fb15SPaul Saab 	if (o == NULL)
309a5f0fb15SPaul Saab 	{
31033096f16SXin LI 		error("No such option", NULL_PARG);
311a5f0fb15SPaul Saab 		return;
312a5f0fb15SPaul Saab 	}
313a5f0fb15SPaul Saab 
314a5f0fb15SPaul Saab 	if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE))
315a5f0fb15SPaul Saab 	{
31633096f16SXin LI 		parg.p_string = opt_desc(o);
317a5f0fb15SPaul Saab 		error("Cannot change the %s option", &parg);
318a5f0fb15SPaul Saab 		return;
319a5f0fb15SPaul Saab 	}
320a5f0fb15SPaul Saab 
321a5f0fb15SPaul Saab 	if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY))
322a5f0fb15SPaul Saab 	{
32333096f16SXin LI 		parg.p_string = opt_desc(o);
324a5f0fb15SPaul Saab 		error("Cannot query the %s option", &parg);
325a5f0fb15SPaul Saab 		return;
326a5f0fb15SPaul Saab 	}
327a5f0fb15SPaul Saab 
328a5f0fb15SPaul Saab 	/*
329a5f0fb15SPaul Saab 	 * Check for something which appears to be a do_toggle
330a5f0fb15SPaul Saab 	 * (because the "-" command was used), but really is not.
331a5f0fb15SPaul Saab 	 * This could be a string option with no string, or
332a5f0fb15SPaul Saab 	 * a number option with no number.
333a5f0fb15SPaul Saab 	 */
334a5f0fb15SPaul Saab 	switch (o->otype & OTYPE)
335a5f0fb15SPaul Saab 	{
336a5f0fb15SPaul Saab 	case STRING:
337a5f0fb15SPaul Saab 	case NUMBER:
338a5f0fb15SPaul Saab 		if (how_toggle == OPT_TOGGLE && *s == '\0')
339a5f0fb15SPaul Saab 			how_toggle = OPT_NO_TOGGLE;
340a5f0fb15SPaul Saab 		break;
341a5f0fb15SPaul Saab 	}
342a5f0fb15SPaul Saab 
343a5f0fb15SPaul Saab #if HILITE_SEARCH
344a5f0fb15SPaul Saab 	if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
345a5f0fb15SPaul Saab 		repaint_hilite(0);
346a5f0fb15SPaul Saab #endif
347a5f0fb15SPaul Saab 
348a5f0fb15SPaul Saab 	/*
349a5f0fb15SPaul Saab 	 * Now actually toggle (change) the variable.
350a5f0fb15SPaul Saab 	 */
351a5f0fb15SPaul Saab 	if (how_toggle != OPT_NO_TOGGLE)
352a5f0fb15SPaul Saab 	{
353a5f0fb15SPaul Saab 		switch (o->otype & OTYPE)
354a5f0fb15SPaul Saab 		{
355a5f0fb15SPaul Saab 		case BOOL:
356a5f0fb15SPaul Saab 			/*
357a5f0fb15SPaul Saab 			 * Boolean.
358a5f0fb15SPaul Saab 			 */
359a5f0fb15SPaul Saab 			switch (how_toggle)
360a5f0fb15SPaul Saab 			{
361a5f0fb15SPaul Saab 			case OPT_TOGGLE:
362a5f0fb15SPaul Saab 				*(o->ovar) = ! *(o->ovar);
363a5f0fb15SPaul Saab 				break;
364a5f0fb15SPaul Saab 			case OPT_UNSET:
365a5f0fb15SPaul Saab 				*(o->ovar) = o->odefault;
366a5f0fb15SPaul Saab 				break;
367a5f0fb15SPaul Saab 			case OPT_SET:
368a5f0fb15SPaul Saab 				*(o->ovar) = ! o->odefault;
369a5f0fb15SPaul Saab 				break;
370a5f0fb15SPaul Saab 			}
371a5f0fb15SPaul Saab 			break;
372a5f0fb15SPaul Saab 		case TRIPLE:
373a5f0fb15SPaul Saab 			/*
374a5f0fb15SPaul Saab 			 * Triple:
375a5f0fb15SPaul Saab 			 *      If user gave the lower case letter, then switch
376a5f0fb15SPaul Saab 			 *      to 1 unless already 1, in which case make it 0.
377a5f0fb15SPaul Saab 			 *      If user gave the upper case letter, then switch
378a5f0fb15SPaul Saab 			 *      to 2 unless already 2, in which case make it 0.
379a5f0fb15SPaul Saab 			 */
380a5f0fb15SPaul Saab 			switch (how_toggle)
381a5f0fb15SPaul Saab 			{
382a5f0fb15SPaul Saab 			case OPT_TOGGLE:
38333096f16SXin LI 				*(o->ovar) = flip_triple(*(o->ovar), lower);
384a5f0fb15SPaul Saab 				break;
385a5f0fb15SPaul Saab 			case OPT_UNSET:
386a5f0fb15SPaul Saab 				*(o->ovar) = o->odefault;
387a5f0fb15SPaul Saab 				break;
388a5f0fb15SPaul Saab 			case OPT_SET:
38933096f16SXin LI 				*(o->ovar) = flip_triple(o->odefault, lower);
390a5f0fb15SPaul Saab 				break;
391a5f0fb15SPaul Saab 			}
392a5f0fb15SPaul Saab 			break;
393a5f0fb15SPaul Saab 		case STRING:
394a5f0fb15SPaul Saab 			/*
395a5f0fb15SPaul Saab 			 * String: don't do anything here.
396a5f0fb15SPaul Saab 			 *      The handling function will do everything.
397a5f0fb15SPaul Saab 			 */
398a5f0fb15SPaul Saab 			switch (how_toggle)
399a5f0fb15SPaul Saab 			{
400a5f0fb15SPaul Saab 			case OPT_SET:
401a5f0fb15SPaul Saab 			case OPT_UNSET:
402a5f0fb15SPaul Saab 				error("Cannot use \"-+\" or \"--\" for a string option",
403a5f0fb15SPaul Saab 					NULL_PARG);
404a5f0fb15SPaul Saab 				return;
405a5f0fb15SPaul Saab 			}
406a5f0fb15SPaul Saab 			break;
407a5f0fb15SPaul Saab 		case NUMBER:
408a5f0fb15SPaul Saab 			/*
409a5f0fb15SPaul Saab 			 * Number: set the variable to the given number.
410a5f0fb15SPaul Saab 			 */
411a5f0fb15SPaul Saab 			switch (how_toggle)
412a5f0fb15SPaul Saab 			{
413a5f0fb15SPaul Saab 			case OPT_TOGGLE:
414000ba3e8STim J. Robbins 				num = getnum(&s, NULL, &err);
415a5f0fb15SPaul Saab 				if (!err)
416a5f0fb15SPaul Saab 					*(o->ovar) = num;
417a5f0fb15SPaul Saab 				break;
418a5f0fb15SPaul Saab 			case OPT_UNSET:
419a5f0fb15SPaul Saab 				*(o->ovar) = o->odefault;
420a5f0fb15SPaul Saab 				break;
421a5f0fb15SPaul Saab 			case OPT_SET:
422a5f0fb15SPaul Saab 				error("Can't use \"-!\" for a numeric option",
423a5f0fb15SPaul Saab 					NULL_PARG);
424a5f0fb15SPaul Saab 				return;
425a5f0fb15SPaul Saab 			}
426a5f0fb15SPaul Saab 			break;
427a5f0fb15SPaul Saab 		}
428a5f0fb15SPaul Saab 	}
429a5f0fb15SPaul Saab 
430a5f0fb15SPaul Saab 	/*
431a5f0fb15SPaul Saab 	 * Call the handling function for any special action
432a5f0fb15SPaul Saab 	 * specific to this option.
433a5f0fb15SPaul Saab 	 */
434a5f0fb15SPaul Saab 	if (o->ofunc != NULL)
435a5f0fb15SPaul Saab 		(*o->ofunc)((how_toggle==OPT_NO_TOGGLE) ? QUERY : TOGGLE, s);
436a5f0fb15SPaul Saab 
437a5f0fb15SPaul Saab #if HILITE_SEARCH
438a5f0fb15SPaul Saab 	if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
439a5f0fb15SPaul Saab 		chg_hilite();
440a5f0fb15SPaul Saab #endif
441a5f0fb15SPaul Saab 
442a5f0fb15SPaul Saab 	if (!no_prompt)
443a5f0fb15SPaul Saab 	{
444a5f0fb15SPaul Saab 		/*
445a5f0fb15SPaul Saab 		 * Print a message describing the new setting.
446a5f0fb15SPaul Saab 		 */
447a5f0fb15SPaul Saab 		switch (o->otype & OTYPE)
448a5f0fb15SPaul Saab 		{
449a5f0fb15SPaul Saab 		case BOOL:
450a5f0fb15SPaul Saab 		case TRIPLE:
451a5f0fb15SPaul Saab 			/*
452a5f0fb15SPaul Saab 			 * Print the odesc message.
453a5f0fb15SPaul Saab 			 */
454a5f0fb15SPaul Saab 			error(o->odesc[*(o->ovar)], NULL_PARG);
455a5f0fb15SPaul Saab 			break;
456a5f0fb15SPaul Saab 		case NUMBER:
457a5f0fb15SPaul Saab 			/*
458a5f0fb15SPaul Saab 			 * The message is in odesc[1] and has a %d for
459a5f0fb15SPaul Saab 			 * the value of the variable.
460a5f0fb15SPaul Saab 			 */
461a5f0fb15SPaul Saab 			parg.p_int = *(o->ovar);
462a5f0fb15SPaul Saab 			error(o->odesc[1], &parg);
463a5f0fb15SPaul Saab 			break;
464a5f0fb15SPaul Saab 		case STRING:
465a5f0fb15SPaul Saab 			/*
466a5f0fb15SPaul Saab 			 * Message was already printed by the handling function.
467a5f0fb15SPaul Saab 			 */
468a5f0fb15SPaul Saab 			break;
469a5f0fb15SPaul Saab 		}
470a5f0fb15SPaul Saab 	}
471a5f0fb15SPaul Saab 
472a5f0fb15SPaul Saab 	if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT))
473a5f0fb15SPaul Saab 		screen_trashed = TRUE;
474a5f0fb15SPaul Saab }
475a5f0fb15SPaul Saab 
476a5f0fb15SPaul Saab /*
477a5f0fb15SPaul Saab  * "Toggle" a triple-valued option.
478a5f0fb15SPaul Saab  */
479*d713e089SXin LI static int flip_triple(int val, int lc)
480a5f0fb15SPaul Saab {
481a5f0fb15SPaul Saab 	if (lc)
482a5f0fb15SPaul Saab 		return ((val == OPT_ON) ? OPT_OFF : OPT_ON);
483a5f0fb15SPaul Saab 	else
484a5f0fb15SPaul Saab 		return ((val == OPT_ONPLUS) ? OPT_OFF : OPT_ONPLUS);
485a5f0fb15SPaul Saab }
486a5f0fb15SPaul Saab 
487a5f0fb15SPaul Saab /*
48833096f16SXin LI  * Determine if an option takes a parameter.
489a5f0fb15SPaul Saab  */
490*d713e089SXin LI public int opt_has_param(struct loption *o)
491a5f0fb15SPaul Saab {
492a5f0fb15SPaul Saab 	if (o == NULL)
49333096f16SXin LI 		return (0);
49433096f16SXin LI 	if (o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE))
49533096f16SXin LI 		return (0);
49633096f16SXin LI 	return (1);
497a5f0fb15SPaul Saab }
498a5f0fb15SPaul Saab 
499a5f0fb15SPaul Saab /*
500a5f0fb15SPaul Saab  * Return the prompt to be used for a given option letter.
501a5f0fb15SPaul Saab  * Only string and number valued options have prompts.
502a5f0fb15SPaul Saab  */
503*d713e089SXin LI public char * opt_prompt(struct loption *o)
504a5f0fb15SPaul Saab {
505a5f0fb15SPaul Saab 	if (o == NULL || (o->otype & (STRING|NUMBER)) == 0)
50633096f16SXin LI 		return ("?");
507a5f0fb15SPaul Saab 	return (o->odesc[0]);
508a5f0fb15SPaul Saab }
509a5f0fb15SPaul Saab 
510a5f0fb15SPaul Saab /*
5116f26c71dSXin LI  * If the specified option can be toggled, return NULL.
5126f26c71dSXin LI  * Otherwise return an appropriate error message.
5136f26c71dSXin LI  */
514*d713e089SXin LI public char * opt_toggle_disallowed(int c)
5156f26c71dSXin LI {
5166f26c71dSXin LI 	switch (c)
5176f26c71dSXin LI 	{
5186f26c71dSXin LI 	case 'o':
5196f26c71dSXin LI 		if (ch_getflags() & CH_CANSEEK)
5206f26c71dSXin LI 			return "Input is not a pipe";
5216f26c71dSXin LI 		break;
5226f26c71dSXin LI 	}
5236f26c71dSXin LI 	return NULL;
5246f26c71dSXin LI }
5256f26c71dSXin LI 
5266f26c71dSXin LI /*
527a5f0fb15SPaul Saab  * Return whether or not there is a string option pending;
528a5f0fb15SPaul Saab  * that is, if the previous option was a string-valued option letter
529a5f0fb15SPaul Saab  * (like -P) without a following string.
530a5f0fb15SPaul Saab  * In that case, the current option is taken to be the string for
531a5f0fb15SPaul Saab  * the previous option.
532a5f0fb15SPaul Saab  */
533*d713e089SXin LI public int isoptpending(void)
534a5f0fb15SPaul Saab {
535a5f0fb15SPaul Saab 	return (pendopt != NULL);
536a5f0fb15SPaul Saab }
537a5f0fb15SPaul Saab 
538a5f0fb15SPaul Saab /*
539a5f0fb15SPaul Saab  * Print error message about missing string.
540a5f0fb15SPaul Saab  */
541*d713e089SXin LI static void nostring(char *printopt)
542a5f0fb15SPaul Saab {
543a5f0fb15SPaul Saab 	PARG parg;
544a5f0fb15SPaul Saab 	parg.p_string = printopt;
545a5f0fb15SPaul Saab 	error("Value is required after %s", &parg);
546a5f0fb15SPaul Saab }
547a5f0fb15SPaul Saab 
548a5f0fb15SPaul Saab /*
549a5f0fb15SPaul Saab  * Print error message if a STRING type option is not followed by a string.
550a5f0fb15SPaul Saab  */
551*d713e089SXin LI public void nopendopt(void)
552a5f0fb15SPaul Saab {
55333096f16SXin LI 	nostring(opt_desc(pendopt));
554a5f0fb15SPaul Saab }
555a5f0fb15SPaul Saab 
556a5f0fb15SPaul Saab /*
557a5f0fb15SPaul Saab  * Scan to end of string or to an END_OPTION_STRING character.
558a5f0fb15SPaul Saab  * In the latter case, replace the char with a null char.
559a5f0fb15SPaul Saab  * Return a pointer to the remainder of the string, if any.
560a5f0fb15SPaul Saab  */
561*d713e089SXin LI static char * optstring(char *s, char **p_str, char *printopt, char *validchars)
562a5f0fb15SPaul Saab {
5631ea31627SRobert Watson 	char *p;
5641ea31627SRobert Watson 	char *out;
565a5f0fb15SPaul Saab 
566a5f0fb15SPaul Saab 	if (*s == '\0')
567a5f0fb15SPaul Saab 	{
568a5f0fb15SPaul Saab 		nostring(printopt);
5694cc5fc9aSXin LI 		return (NULL);
570a5f0fb15SPaul Saab 	}
5714cc5fc9aSXin LI 	/* Alloc could be more than needed, but not worth trimming. */
5724cc5fc9aSXin LI 	*p_str = (char *) ecalloc(strlen(s)+1, sizeof(char));
5734cc5fc9aSXin LI 	out = *p_str;
5744cc5fc9aSXin LI 
575a5f0fb15SPaul Saab 	for (p = s;  *p != '\0';  p++)
576000ba3e8STim J. Robbins 	{
5777bd2567cSXin LI 		if (opt_use_backslash && *p == '\\' && p[1] != '\0')
5784cc5fc9aSXin LI 		{
5794cc5fc9aSXin LI 			/* Take next char literally. */
5804cc5fc9aSXin LI 			++p;
5814cc5fc9aSXin LI 		} else
5824cc5fc9aSXin LI 		{
583c9346414SPaul Saab 			if (*p == END_OPTION_STRING ||
584c9346414SPaul Saab 			    (validchars != NULL && strchr(validchars, *p) == NULL))
5854cc5fc9aSXin LI 				/* End of option string. */
586c9346414SPaul Saab 				break;
587c9346414SPaul Saab 		}
5884cc5fc9aSXin LI 		*out++ = *p;
589000ba3e8STim J. Robbins 	}
5904cc5fc9aSXin LI 	*out = '\0';
591a5f0fb15SPaul Saab 	return (p);
592a5f0fb15SPaul Saab }
593a5f0fb15SPaul Saab 
594a5f0fb15SPaul Saab /*
5957f074f9cSXin LI  */
596*d713e089SXin LI static int num_error(char *printopt, int *errp, int overflow)
5977f074f9cSXin LI {
5987f074f9cSXin LI 	PARG parg;
5997f074f9cSXin LI 
6007f074f9cSXin LI 	if (errp != NULL)
6017f074f9cSXin LI 	{
6027f074f9cSXin LI 		*errp = TRUE;
6037f074f9cSXin LI 		return (-1);
6047f074f9cSXin LI 	}
6057f074f9cSXin LI 	if (printopt != NULL)
6067f074f9cSXin LI 	{
6077f074f9cSXin LI 		parg.p_string = printopt;
608*d713e089SXin LI 		error((overflow
609*d713e089SXin LI 		       ? "Number too large in '%s'"
610*d713e089SXin LI 		       : "Number is required after %s"),
611*d713e089SXin LI 		      &parg);
6127f074f9cSXin LI 	}
6137f074f9cSXin LI 	return (-1);
6147f074f9cSXin LI }
6157f074f9cSXin LI 
6167f074f9cSXin LI /*
617a5f0fb15SPaul Saab  * Translate a string into a number.
618a5f0fb15SPaul Saab  * Like atoi(), but takes a pointer to a char *, and updates
619a5f0fb15SPaul Saab  * the char * to point after the translated number.
620a5f0fb15SPaul Saab  */
621*d713e089SXin LI public int getnum(char **sp, char *printopt, int *errp)
622a5f0fb15SPaul Saab {
6231ea31627SRobert Watson 	char *s;
6241ea31627SRobert Watson 	int n;
6251ea31627SRobert Watson 	int neg;
626a5f0fb15SPaul Saab 
627a5f0fb15SPaul Saab 	s = skipsp(*sp);
628a5f0fb15SPaul Saab 	neg = FALSE;
629a5f0fb15SPaul Saab 	if (*s == '-')
630a5f0fb15SPaul Saab 	{
631a5f0fb15SPaul Saab 		neg = TRUE;
632a5f0fb15SPaul Saab 		s++;
633a5f0fb15SPaul Saab 	}
634a5f0fb15SPaul Saab 	if (*s < '0' || *s > '9')
635*d713e089SXin LI 		return (num_error(printopt, errp, FALSE));
636a5f0fb15SPaul Saab 
637*d713e089SXin LI 	n = lstrtoi(s, sp, 10);
638*d713e089SXin LI 	if (n < 0)
639*d713e089SXin LI 		return (num_error(printopt, errp, TRUE));
640a5f0fb15SPaul Saab 	if (errp != NULL)
641a5f0fb15SPaul Saab 		*errp = FALSE;
642a5f0fb15SPaul Saab 	if (neg)
643a5f0fb15SPaul Saab 		n = -n;
644a5f0fb15SPaul Saab 	return (n);
645a5f0fb15SPaul Saab }
6467f074f9cSXin LI 
6477f074f9cSXin LI /*
6487f074f9cSXin LI  * Translate a string into a fraction, represented by the part of a
6497f074f9cSXin LI  * number which would follow a decimal point.
6507f074f9cSXin LI  * The value of the fraction is returned as parts per NUM_FRAC_DENOM.
6517f074f9cSXin LI  * That is, if "n" is returned, the fraction intended is n/NUM_FRAC_DENOM.
6527f074f9cSXin LI  */
653*d713e089SXin LI public long getfraction(char **sp, char *printopt, int *errp)
6547f074f9cSXin LI {
6551ea31627SRobert Watson 	char *s;
6567f074f9cSXin LI 	long frac = 0;
6577f074f9cSXin LI 	int fraclen = 0;
6587f074f9cSXin LI 
6597f074f9cSXin LI 	s = skipsp(*sp);
6607f074f9cSXin LI 	if (*s < '0' || *s > '9')
661*d713e089SXin LI 		return (num_error(printopt, errp, FALSE));
6627f074f9cSXin LI 
6637f074f9cSXin LI 	for ( ;  *s >= '0' && *s <= '9';  s++)
6647f074f9cSXin LI 	{
665*d713e089SXin LI 		if (NUM_LOG_FRAC_DENOM <= fraclen)
666*d713e089SXin LI 			continue;
6677f074f9cSXin LI 		frac = (frac * 10) + (*s - '0');
6687f074f9cSXin LI 		fraclen++;
6697f074f9cSXin LI 	}
6707f074f9cSXin LI 	while (fraclen++ < NUM_LOG_FRAC_DENOM)
6717f074f9cSXin LI 		frac *= 10;
6727f074f9cSXin LI 	*sp = s;
6737f074f9cSXin LI 	if (errp != NULL)
6747f074f9cSXin LI 		*errp = FALSE;
6757f074f9cSXin LI 	return (frac);
6767f074f9cSXin LI }
6777f074f9cSXin LI 
6787f074f9cSXin LI 
6797f074f9cSXin LI /*
6807f074f9cSXin LI  * Get the value of the -e flag.
6817f074f9cSXin LI  */
682*d713e089SXin LI public int get_quit_at_eof(void)
6837f074f9cSXin LI {
6847f074f9cSXin LI 	if (!less_is_more)
6857f074f9cSXin LI 		return quit_at_eof;
6867f074f9cSXin LI 	/* When less_is_more is set, the -e flag semantics are different. */
687a15691bfSXin LI 	return quit_at_eof ? OPT_ONPLUS : OPT_ON;
6887f074f9cSXin LI }
689