xref: /freebsd/contrib/less/option.c (revision 33096f16e1815def0772f877cbb01e832bb5b37e)
1a5f0fb15SPaul Saab /*
2*33096f16SXin LI  * Copyright (C) 1984-2011  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  *
7a5f0fb15SPaul Saab  * For more information about less, or for information on how to
8a5f0fb15SPaul Saab  * contact the author, see the README file.
9a5f0fb15SPaul Saab  */
10a5f0fb15SPaul Saab 
11a5f0fb15SPaul Saab 
12a5f0fb15SPaul Saab /*
13a5f0fb15SPaul Saab  * Process command line options.
14a5f0fb15SPaul Saab  *
15a5f0fb15SPaul Saab  * Each option is a single letter which controls a program variable.
16a5f0fb15SPaul Saab  * The options have defaults which may be changed via
17a5f0fb15SPaul Saab  * the command line option, toggled via the "-" command,
18a5f0fb15SPaul Saab  * or queried via the "_" command.
19a5f0fb15SPaul Saab  */
20a5f0fb15SPaul Saab 
21a5f0fb15SPaul Saab #include "less.h"
22a5f0fb15SPaul Saab #include "option.h"
23a5f0fb15SPaul Saab 
24000ba3e8STim J. Robbins static struct loption *pendopt;
25a5f0fb15SPaul Saab public int plusoption = FALSE;
26a5f0fb15SPaul Saab 
27a5f0fb15SPaul Saab static char *optstring();
28a5f0fb15SPaul Saab static int flip_triple();
29a5f0fb15SPaul Saab 
30a5f0fb15SPaul Saab extern int screen_trashed;
317f074f9cSXin LI extern int less_is_more;
327f074f9cSXin LI extern int quit_at_eof;
33a5f0fb15SPaul Saab extern char *every_first_cmd;
34a5f0fb15SPaul Saab 
35a5f0fb15SPaul Saab /*
36*33096f16SXin LI  * Return a printable description of an option.
37*33096f16SXin LI  */
38*33096f16SXin LI 	static char *
39*33096f16SXin LI opt_desc(o)
40*33096f16SXin LI 	struct loption *o;
41*33096f16SXin LI {
42*33096f16SXin LI 	static char buf[OPTNAME_MAX + 10];
43*33096f16SXin LI 	if (o->oletter == OLETTER_NONE)
44*33096f16SXin LI 		SNPRINTF1(buf, sizeof(buf), "--%s", o->onames->oname);
45*33096f16SXin LI 	else
46*33096f16SXin LI 		SNPRINTF2(buf, sizeof(buf), "-%c (--%s)", o->oletter, o->onames->oname);
47*33096f16SXin LI 	return (buf);
48*33096f16SXin LI }
49*33096f16SXin LI 
50*33096f16SXin LI /*
51*33096f16SXin LI  * Return a string suitable for printing as the "name" of an option.
52*33096f16SXin LI  * For example, if the option letter is 'x', just return "-x".
53*33096f16SXin LI  */
54*33096f16SXin LI 	public char *
55*33096f16SXin LI propt(c)
56*33096f16SXin LI 	int c;
57*33096f16SXin LI {
58*33096f16SXin LI 	static char buf[8];
59*33096f16SXin LI 
60*33096f16SXin LI 	sprintf(buf, "-%s", prchar(c));
61*33096f16SXin LI 	return (buf);
62*33096f16SXin LI }
63*33096f16SXin LI 
64*33096f16SXin LI /*
65a5f0fb15SPaul Saab  * Scan an argument (either from the command line or from the
66a5f0fb15SPaul Saab  * LESS environment variable) and process it.
67a5f0fb15SPaul Saab  */
68a5f0fb15SPaul Saab 	public void
69a5f0fb15SPaul Saab scan_option(s)
70a5f0fb15SPaul Saab 	char *s;
71a5f0fb15SPaul Saab {
72000ba3e8STim J. Robbins 	register struct loption *o;
73a5f0fb15SPaul Saab 	register int optc;
74a5f0fb15SPaul Saab 	char *optname;
75a5f0fb15SPaul Saab 	char *printopt;
76a5f0fb15SPaul Saab 	char *str;
77a5f0fb15SPaul Saab 	int set_default;
78a5f0fb15SPaul Saab 	int lc;
79a5f0fb15SPaul Saab 	int err;
80a5f0fb15SPaul Saab 	PARG parg;
81a5f0fb15SPaul Saab 
82a5f0fb15SPaul Saab 	if (s == NULL)
83a5f0fb15SPaul Saab 		return;
84a5f0fb15SPaul Saab 
85a5f0fb15SPaul Saab 	/*
86a5f0fb15SPaul Saab 	 * If we have a pending option which requires an argument,
87a5f0fb15SPaul Saab 	 * handle it now.
88a5f0fb15SPaul Saab 	 * This happens if the previous option was, for example, "-P"
89a5f0fb15SPaul Saab 	 * without a following string.  In that case, the current
90a5f0fb15SPaul Saab 	 * option is simply the argument for the previous option.
91a5f0fb15SPaul Saab 	 */
92a5f0fb15SPaul Saab 	if (pendopt != NULL)
93a5f0fb15SPaul Saab 	{
94a5f0fb15SPaul Saab 		switch (pendopt->otype & OTYPE)
95a5f0fb15SPaul Saab 		{
96a5f0fb15SPaul Saab 		case STRING:
97a5f0fb15SPaul Saab 			(*pendopt->ofunc)(INIT, s);
98a5f0fb15SPaul Saab 			break;
99a5f0fb15SPaul Saab 		case NUMBER:
100*33096f16SXin LI 			printopt = opt_desc(pendopt);
101a5f0fb15SPaul Saab 			*(pendopt->ovar) = getnum(&s, printopt, (int*)NULL);
102a5f0fb15SPaul Saab 			break;
103a5f0fb15SPaul Saab 		}
104a5f0fb15SPaul Saab 		pendopt = NULL;
105a5f0fb15SPaul Saab 		return;
106a5f0fb15SPaul Saab 	}
107a5f0fb15SPaul Saab 
108a5f0fb15SPaul Saab 	set_default = FALSE;
109a5f0fb15SPaul Saab 	optname = NULL;
110a5f0fb15SPaul Saab 
111a5f0fb15SPaul Saab 	while (*s != '\0')
112a5f0fb15SPaul Saab 	{
113a5f0fb15SPaul Saab 		/*
114a5f0fb15SPaul Saab 		 * Check some special cases first.
115a5f0fb15SPaul Saab 		 */
116a5f0fb15SPaul Saab 		switch (optc = *s++)
117a5f0fb15SPaul Saab 		{
118a5f0fb15SPaul Saab 		case ' ':
119a5f0fb15SPaul Saab 		case '\t':
120a5f0fb15SPaul Saab 		case END_OPTION_STRING:
121a5f0fb15SPaul Saab 			continue;
122a5f0fb15SPaul Saab 		case '-':
123a5f0fb15SPaul Saab 			/*
124a5f0fb15SPaul Saab 			 * "--" indicates an option name instead of a letter.
125a5f0fb15SPaul Saab 			 */
126a5f0fb15SPaul Saab 			if (*s == '-')
127a5f0fb15SPaul Saab 			{
128a5f0fb15SPaul Saab 				optname = ++s;
129a5f0fb15SPaul Saab 				break;
130a5f0fb15SPaul Saab 			}
131a5f0fb15SPaul Saab 			/*
132a5f0fb15SPaul Saab 			 * "-+" means set these options back to their defaults.
133a5f0fb15SPaul Saab 			 * (They may have been set otherwise by previous
134a5f0fb15SPaul Saab 			 * options.)
135a5f0fb15SPaul Saab 			 */
136a5f0fb15SPaul Saab 			set_default = (*s == '+');
137a5f0fb15SPaul Saab 			if (set_default)
138a5f0fb15SPaul Saab 				s++;
139a5f0fb15SPaul Saab 			continue;
140a5f0fb15SPaul Saab 		case '+':
141a5f0fb15SPaul Saab 			/*
142a5f0fb15SPaul Saab 			 * An option prefixed by a "+" is ungotten, so
143a5f0fb15SPaul Saab 			 * that it is interpreted as less commands
144a5f0fb15SPaul Saab 			 * processed at the start of the first input file.
145a5f0fb15SPaul Saab 			 * "++" means process the commands at the start of
146a5f0fb15SPaul Saab 			 * EVERY input file.
147a5f0fb15SPaul Saab 			 */
148a5f0fb15SPaul Saab 			plusoption = TRUE;
149000ba3e8STim J. Robbins 			s = optstring(s, &str, propt('+'), NULL);
150c9346414SPaul Saab 			if (*str == '+')
151c9346414SPaul Saab 				every_first_cmd = save(++str);
152a5f0fb15SPaul Saab 			else
153c9346414SPaul Saab 				ungetsc(str);
154a5f0fb15SPaul Saab 			continue;
155a5f0fb15SPaul Saab 		case '0':  case '1':  case '2':  case '3':  case '4':
156a5f0fb15SPaul Saab 		case '5':  case '6':  case '7':  case '8':  case '9':
157a5f0fb15SPaul Saab 			/*
158a5f0fb15SPaul Saab 			 * Special "more" compatibility form "-<number>"
159a5f0fb15SPaul Saab 			 * instead of -z<number> to set the scrolling
160a5f0fb15SPaul Saab 			 * window size.
161a5f0fb15SPaul Saab 			 */
162a5f0fb15SPaul Saab 			s--;
163a5f0fb15SPaul Saab 			optc = 'z';
164a5f0fb15SPaul Saab 			break;
1657f074f9cSXin LI 		case 'n':
1667f074f9cSXin LI 			if (less_is_more)
1677f074f9cSXin LI 				optc = 'z';
1687f074f9cSXin LI 			break;
169a5f0fb15SPaul Saab 		}
170a5f0fb15SPaul Saab 
171a5f0fb15SPaul Saab 		/*
172a5f0fb15SPaul Saab 		 * Not a special case.
173a5f0fb15SPaul Saab 		 * Look up the option letter in the option table.
174a5f0fb15SPaul Saab 		 */
175a5f0fb15SPaul Saab 		err = 0;
176a5f0fb15SPaul Saab 		if (optname == NULL)
177a5f0fb15SPaul Saab 		{
178a5f0fb15SPaul Saab 			printopt = propt(optc);
1796dcb072bSXin LI 			lc = ASCII_IS_LOWER(optc);
180a5f0fb15SPaul Saab 			o = findopt(optc);
181a5f0fb15SPaul Saab 		} else
182a5f0fb15SPaul Saab 		{
183a5f0fb15SPaul Saab 			printopt = optname;
1846dcb072bSXin LI 			lc = ASCII_IS_LOWER(optname[0]);
185a5f0fb15SPaul Saab 			o = findopt_name(&optname, NULL, &err);
186a5f0fb15SPaul Saab 			s = optname;
187a5f0fb15SPaul Saab 			optname = NULL;
188a5f0fb15SPaul Saab 			if (*s == '\0' || *s == ' ')
189a5f0fb15SPaul Saab 			{
190a5f0fb15SPaul Saab 				/*
191a5f0fb15SPaul Saab 				 * The option name matches exactly.
192a5f0fb15SPaul Saab 				 */
193a5f0fb15SPaul Saab 				;
194a5f0fb15SPaul Saab 			} else if (*s == '=')
195a5f0fb15SPaul Saab 			{
196a5f0fb15SPaul Saab 				/*
197a5f0fb15SPaul Saab 				 * The option name is followed by "=value".
198a5f0fb15SPaul Saab 				 */
199a5f0fb15SPaul Saab 				if (o != NULL &&
200a5f0fb15SPaul Saab 				    (o->otype & OTYPE) != STRING &&
201a5f0fb15SPaul Saab 				    (o->otype & OTYPE) != NUMBER)
202a5f0fb15SPaul Saab 				{
203a5f0fb15SPaul Saab 					parg.p_string = printopt;
204a5f0fb15SPaul Saab 					error("The %s option should not be followed by =",
205a5f0fb15SPaul Saab 						&parg);
206a5f0fb15SPaul Saab 					quit(QUIT_ERROR);
207a5f0fb15SPaul Saab 				}
208a5f0fb15SPaul Saab 				s++;
209a5f0fb15SPaul Saab 			} else
210a5f0fb15SPaul Saab 			{
211a5f0fb15SPaul Saab 				/*
212a5f0fb15SPaul Saab 				 * The specified name is longer than the
213a5f0fb15SPaul Saab 				 * real option name.
214a5f0fb15SPaul Saab 				 */
215a5f0fb15SPaul Saab 				o = NULL;
216a5f0fb15SPaul Saab 			}
217a5f0fb15SPaul Saab 		}
218a5f0fb15SPaul Saab 		if (o == NULL)
219a5f0fb15SPaul Saab 		{
220a5f0fb15SPaul Saab 			parg.p_string = printopt;
221a5f0fb15SPaul Saab 			if (err == OPT_AMBIG)
222a5f0fb15SPaul Saab 				error("%s is an ambiguous abbreviation (\"less --help\" for help)",
223a5f0fb15SPaul Saab 					&parg);
224a5f0fb15SPaul Saab 			else
225a5f0fb15SPaul Saab 				error("There is no %s option (\"less --help\" for help)",
226a5f0fb15SPaul Saab 					&parg);
227a5f0fb15SPaul Saab 			quit(QUIT_ERROR);
228a5f0fb15SPaul Saab 		}
229a5f0fb15SPaul Saab 
230a5f0fb15SPaul Saab 		str = NULL;
231a5f0fb15SPaul Saab 		switch (o->otype & OTYPE)
232a5f0fb15SPaul Saab 		{
233a5f0fb15SPaul Saab 		case BOOL:
234a5f0fb15SPaul Saab 			if (set_default)
235a5f0fb15SPaul Saab 				*(o->ovar) = o->odefault;
236a5f0fb15SPaul Saab 			else
237a5f0fb15SPaul Saab 				*(o->ovar) = ! o->odefault;
238a5f0fb15SPaul Saab 			break;
239a5f0fb15SPaul Saab 		case TRIPLE:
240a5f0fb15SPaul Saab 			if (set_default)
241a5f0fb15SPaul Saab 				*(o->ovar) = o->odefault;
242a5f0fb15SPaul Saab 			else
243a5f0fb15SPaul Saab 				*(o->ovar) = flip_triple(o->odefault, lc);
244a5f0fb15SPaul Saab 			break;
245a5f0fb15SPaul Saab 		case STRING:
246a5f0fb15SPaul Saab 			if (*s == '\0')
247a5f0fb15SPaul Saab 			{
248a5f0fb15SPaul Saab 				/*
249a5f0fb15SPaul Saab 				 * Set pendopt and return.
250a5f0fb15SPaul Saab 				 * We will get the string next time
251a5f0fb15SPaul Saab 				 * scan_option is called.
252a5f0fb15SPaul Saab 				 */
253a5f0fb15SPaul Saab 				pendopt = o;
254a5f0fb15SPaul Saab 				return;
255a5f0fb15SPaul Saab 			}
256a5f0fb15SPaul Saab 			/*
257a5f0fb15SPaul Saab 			 * Don't do anything here.
258a5f0fb15SPaul Saab 			 * All processing of STRING options is done by
259a5f0fb15SPaul Saab 			 * the handling function.
260a5f0fb15SPaul Saab 			 */
261000ba3e8STim J. Robbins 			while (*s == ' ')
262000ba3e8STim J. Robbins 				s++;
263000ba3e8STim J. Robbins 			s = optstring(s, &str, printopt, o->odesc[1]);
264a5f0fb15SPaul Saab 			break;
265a5f0fb15SPaul Saab 		case NUMBER:
266a5f0fb15SPaul Saab 			if (*s == '\0')
267a5f0fb15SPaul Saab 			{
268a5f0fb15SPaul Saab 				pendopt = o;
269a5f0fb15SPaul Saab 				return;
270a5f0fb15SPaul Saab 			}
271a5f0fb15SPaul Saab 			*(o->ovar) = getnum(&s, printopt, (int*)NULL);
272a5f0fb15SPaul Saab 			break;
273a5f0fb15SPaul Saab 		}
274a5f0fb15SPaul Saab 		/*
275a5f0fb15SPaul Saab 		 * If the option has a handling function, call it.
276a5f0fb15SPaul Saab 		 */
277a5f0fb15SPaul Saab 		if (o->ofunc != NULL)
278a5f0fb15SPaul Saab 			(*o->ofunc)(INIT, str);
279a5f0fb15SPaul Saab 	}
280a5f0fb15SPaul Saab }
281a5f0fb15SPaul Saab 
282a5f0fb15SPaul Saab /*
283a5f0fb15SPaul Saab  * Toggle command line flags from within the program.
284a5f0fb15SPaul Saab  * Used by the "-" and "_" commands.
285a5f0fb15SPaul Saab  * how_toggle may be:
286a5f0fb15SPaul Saab  *	OPT_NO_TOGGLE	just report the current setting, without changing it.
287a5f0fb15SPaul Saab  *	OPT_TOGGLE	invert the current setting
288a5f0fb15SPaul Saab  *	OPT_UNSET	set to the default value
289a5f0fb15SPaul Saab  *	OPT_SET		set to the inverse of the default value
290a5f0fb15SPaul Saab  */
291a5f0fb15SPaul Saab 	public void
292*33096f16SXin LI toggle_option(o, lower, s, how_toggle)
293*33096f16SXin LI 	struct loption *o;
294*33096f16SXin LI 	int lower;
295a5f0fb15SPaul Saab 	char *s;
296a5f0fb15SPaul Saab 	int how_toggle;
297a5f0fb15SPaul Saab {
298a5f0fb15SPaul Saab 	register int num;
299a5f0fb15SPaul Saab 	int no_prompt;
300a5f0fb15SPaul Saab 	int err;
301a5f0fb15SPaul Saab 	PARG parg;
302a5f0fb15SPaul Saab 
303a5f0fb15SPaul Saab 	no_prompt = (how_toggle & OPT_NO_PROMPT);
304a5f0fb15SPaul Saab 	how_toggle &= ~OPT_NO_PROMPT;
305a5f0fb15SPaul Saab 
306a5f0fb15SPaul Saab 	if (o == NULL)
307a5f0fb15SPaul Saab 	{
308*33096f16SXin LI 		error("No such option", NULL_PARG);
309a5f0fb15SPaul Saab 		return;
310a5f0fb15SPaul Saab 	}
311a5f0fb15SPaul Saab 
312a5f0fb15SPaul Saab 	if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE))
313a5f0fb15SPaul Saab 	{
314*33096f16SXin LI 		parg.p_string = opt_desc(o);
315a5f0fb15SPaul Saab 		error("Cannot change the %s option", &parg);
316a5f0fb15SPaul Saab 		return;
317a5f0fb15SPaul Saab 	}
318a5f0fb15SPaul Saab 
319a5f0fb15SPaul Saab 	if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY))
320a5f0fb15SPaul Saab 	{
321*33096f16SXin LI 		parg.p_string = opt_desc(o);
322a5f0fb15SPaul Saab 		error("Cannot query the %s option", &parg);
323a5f0fb15SPaul Saab 		return;
324a5f0fb15SPaul Saab 	}
325a5f0fb15SPaul Saab 
326a5f0fb15SPaul Saab 	/*
327a5f0fb15SPaul Saab 	 * Check for something which appears to be a do_toggle
328a5f0fb15SPaul Saab 	 * (because the "-" command was used), but really is not.
329a5f0fb15SPaul Saab 	 * This could be a string option with no string, or
330a5f0fb15SPaul Saab 	 * a number option with no number.
331a5f0fb15SPaul Saab 	 */
332a5f0fb15SPaul Saab 	switch (o->otype & OTYPE)
333a5f0fb15SPaul Saab 	{
334a5f0fb15SPaul Saab 	case STRING:
335a5f0fb15SPaul Saab 	case NUMBER:
336a5f0fb15SPaul Saab 		if (how_toggle == OPT_TOGGLE && *s == '\0')
337a5f0fb15SPaul Saab 			how_toggle = OPT_NO_TOGGLE;
338a5f0fb15SPaul Saab 		break;
339a5f0fb15SPaul Saab 	}
340a5f0fb15SPaul Saab 
341a5f0fb15SPaul Saab #if HILITE_SEARCH
342a5f0fb15SPaul Saab 	if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
343a5f0fb15SPaul Saab 		repaint_hilite(0);
344a5f0fb15SPaul Saab #endif
345a5f0fb15SPaul Saab 
346a5f0fb15SPaul Saab 	/*
347a5f0fb15SPaul Saab 	 * Now actually toggle (change) the variable.
348a5f0fb15SPaul Saab 	 */
349a5f0fb15SPaul Saab 	if (how_toggle != OPT_NO_TOGGLE)
350a5f0fb15SPaul Saab 	{
351a5f0fb15SPaul Saab 		switch (o->otype & OTYPE)
352a5f0fb15SPaul Saab 		{
353a5f0fb15SPaul Saab 		case BOOL:
354a5f0fb15SPaul Saab 			/*
355a5f0fb15SPaul Saab 			 * Boolean.
356a5f0fb15SPaul Saab 			 */
357a5f0fb15SPaul Saab 			switch (how_toggle)
358a5f0fb15SPaul Saab 			{
359a5f0fb15SPaul Saab 			case OPT_TOGGLE:
360a5f0fb15SPaul Saab 				*(o->ovar) = ! *(o->ovar);
361a5f0fb15SPaul Saab 				break;
362a5f0fb15SPaul Saab 			case OPT_UNSET:
363a5f0fb15SPaul Saab 				*(o->ovar) = o->odefault;
364a5f0fb15SPaul Saab 				break;
365a5f0fb15SPaul Saab 			case OPT_SET:
366a5f0fb15SPaul Saab 				*(o->ovar) = ! o->odefault;
367a5f0fb15SPaul Saab 				break;
368a5f0fb15SPaul Saab 			}
369a5f0fb15SPaul Saab 			break;
370a5f0fb15SPaul Saab 		case TRIPLE:
371a5f0fb15SPaul Saab 			/*
372a5f0fb15SPaul Saab 			 * Triple:
373a5f0fb15SPaul Saab 			 *	If user gave the lower case letter, then switch
374a5f0fb15SPaul Saab 			 *	to 1 unless already 1, in which case make it 0.
375a5f0fb15SPaul Saab 			 *	If user gave the upper case letter, then switch
376a5f0fb15SPaul Saab 			 *	to 2 unless already 2, in which case make it 0.
377a5f0fb15SPaul Saab 			 */
378a5f0fb15SPaul Saab 			switch (how_toggle)
379a5f0fb15SPaul Saab 			{
380a5f0fb15SPaul Saab 			case OPT_TOGGLE:
381*33096f16SXin LI 				*(o->ovar) = flip_triple(*(o->ovar), lower);
382a5f0fb15SPaul Saab 				break;
383a5f0fb15SPaul Saab 			case OPT_UNSET:
384a5f0fb15SPaul Saab 				*(o->ovar) = o->odefault;
385a5f0fb15SPaul Saab 				break;
386a5f0fb15SPaul Saab 			case OPT_SET:
387*33096f16SXin LI 				*(o->ovar) = flip_triple(o->odefault, lower);
388a5f0fb15SPaul Saab 				break;
389a5f0fb15SPaul Saab 			}
390a5f0fb15SPaul Saab 			break;
391a5f0fb15SPaul Saab 		case STRING:
392a5f0fb15SPaul Saab 			/*
393a5f0fb15SPaul Saab 			 * String: don't do anything here.
394a5f0fb15SPaul Saab 			 *	The handling function will do everything.
395a5f0fb15SPaul Saab 			 */
396a5f0fb15SPaul Saab 			switch (how_toggle)
397a5f0fb15SPaul Saab 			{
398a5f0fb15SPaul Saab 			case OPT_SET:
399a5f0fb15SPaul Saab 			case OPT_UNSET:
400a5f0fb15SPaul Saab 				error("Cannot use \"-+\" or \"--\" for a string option",
401a5f0fb15SPaul Saab 					NULL_PARG);
402a5f0fb15SPaul Saab 				return;
403a5f0fb15SPaul Saab 			}
404a5f0fb15SPaul Saab 			break;
405a5f0fb15SPaul Saab 		case NUMBER:
406a5f0fb15SPaul Saab 			/*
407a5f0fb15SPaul Saab 			 * Number: set the variable to the given number.
408a5f0fb15SPaul Saab 			 */
409a5f0fb15SPaul Saab 			switch (how_toggle)
410a5f0fb15SPaul Saab 			{
411a5f0fb15SPaul Saab 			case OPT_TOGGLE:
412000ba3e8STim J. Robbins 				num = getnum(&s, NULL, &err);
413a5f0fb15SPaul Saab 				if (!err)
414a5f0fb15SPaul Saab 					*(o->ovar) = num;
415a5f0fb15SPaul Saab 				break;
416a5f0fb15SPaul Saab 			case OPT_UNSET:
417a5f0fb15SPaul Saab 				*(o->ovar) = o->odefault;
418a5f0fb15SPaul Saab 				break;
419a5f0fb15SPaul Saab 			case OPT_SET:
420a5f0fb15SPaul Saab 				error("Can't use \"-!\" for a numeric option",
421a5f0fb15SPaul Saab 					NULL_PARG);
422a5f0fb15SPaul Saab 				return;
423a5f0fb15SPaul Saab 			}
424a5f0fb15SPaul Saab 			break;
425a5f0fb15SPaul Saab 		}
426a5f0fb15SPaul Saab 	}
427a5f0fb15SPaul Saab 
428a5f0fb15SPaul Saab 	/*
429a5f0fb15SPaul Saab 	 * Call the handling function for any special action
430a5f0fb15SPaul Saab 	 * specific to this option.
431a5f0fb15SPaul Saab 	 */
432a5f0fb15SPaul Saab 	if (o->ofunc != NULL)
433a5f0fb15SPaul Saab 		(*o->ofunc)((how_toggle==OPT_NO_TOGGLE) ? QUERY : TOGGLE, s);
434a5f0fb15SPaul Saab 
435a5f0fb15SPaul Saab #if HILITE_SEARCH
436a5f0fb15SPaul Saab 	if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
437a5f0fb15SPaul Saab 		chg_hilite();
438a5f0fb15SPaul Saab #endif
439a5f0fb15SPaul Saab 
440a5f0fb15SPaul Saab 	if (!no_prompt)
441a5f0fb15SPaul Saab 	{
442a5f0fb15SPaul Saab 		/*
443a5f0fb15SPaul Saab 		 * Print a message describing the new setting.
444a5f0fb15SPaul Saab 		 */
445a5f0fb15SPaul Saab 		switch (o->otype & OTYPE)
446a5f0fb15SPaul Saab 		{
447a5f0fb15SPaul Saab 		case BOOL:
448a5f0fb15SPaul Saab 		case TRIPLE:
449a5f0fb15SPaul Saab 			/*
450a5f0fb15SPaul Saab 			 * Print the odesc message.
451a5f0fb15SPaul Saab 			 */
452a5f0fb15SPaul Saab 			error(o->odesc[*(o->ovar)], NULL_PARG);
453a5f0fb15SPaul Saab 			break;
454a5f0fb15SPaul Saab 		case NUMBER:
455a5f0fb15SPaul Saab 			/*
456a5f0fb15SPaul Saab 			 * The message is in odesc[1] and has a %d for
457a5f0fb15SPaul Saab 			 * the value of the variable.
458a5f0fb15SPaul Saab 			 */
459a5f0fb15SPaul Saab 			parg.p_int = *(o->ovar);
460a5f0fb15SPaul Saab 			error(o->odesc[1], &parg);
461a5f0fb15SPaul Saab 			break;
462a5f0fb15SPaul Saab 		case STRING:
463a5f0fb15SPaul Saab 			/*
464a5f0fb15SPaul Saab 			 * Message was already printed by the handling function.
465a5f0fb15SPaul Saab 			 */
466a5f0fb15SPaul Saab 			break;
467a5f0fb15SPaul Saab 		}
468a5f0fb15SPaul Saab 	}
469a5f0fb15SPaul Saab 
470a5f0fb15SPaul Saab 	if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT))
471a5f0fb15SPaul Saab 		screen_trashed = TRUE;
472a5f0fb15SPaul Saab }
473a5f0fb15SPaul Saab 
474a5f0fb15SPaul Saab /*
475a5f0fb15SPaul Saab  * "Toggle" a triple-valued option.
476a5f0fb15SPaul Saab  */
477a5f0fb15SPaul Saab 	static int
478a5f0fb15SPaul Saab flip_triple(val, lc)
479a5f0fb15SPaul Saab 	int val;
480a5f0fb15SPaul Saab 	int lc;
481a5f0fb15SPaul Saab {
482a5f0fb15SPaul Saab 	if (lc)
483a5f0fb15SPaul Saab 		return ((val == OPT_ON) ? OPT_OFF : OPT_ON);
484a5f0fb15SPaul Saab 	else
485a5f0fb15SPaul Saab 		return ((val == OPT_ONPLUS) ? OPT_OFF : OPT_ONPLUS);
486a5f0fb15SPaul Saab }
487a5f0fb15SPaul Saab 
488a5f0fb15SPaul Saab /*
489*33096f16SXin LI  * Determine if an option takes a parameter.
490a5f0fb15SPaul Saab  */
491a5f0fb15SPaul Saab 	public int
492*33096f16SXin LI opt_has_param(o)
493*33096f16SXin LI 	struct loption *o;
494a5f0fb15SPaul Saab {
495a5f0fb15SPaul Saab 	if (o == NULL)
496*33096f16SXin LI 		return (0);
497*33096f16SXin LI 	if (o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE))
498*33096f16SXin LI 		return (0);
499*33096f16SXin LI 	return (1);
500a5f0fb15SPaul Saab }
501a5f0fb15SPaul Saab 
502a5f0fb15SPaul Saab /*
503a5f0fb15SPaul Saab  * Return the prompt to be used for a given option letter.
504a5f0fb15SPaul Saab  * Only string and number valued options have prompts.
505a5f0fb15SPaul Saab  */
506a5f0fb15SPaul Saab 	public char *
507*33096f16SXin LI opt_prompt(o)
508*33096f16SXin LI 	struct loption *o;
509a5f0fb15SPaul Saab {
510a5f0fb15SPaul Saab 	if (o == NULL || (o->otype & (STRING|NUMBER)) == 0)
511*33096f16SXin LI 		return ("?");
512a5f0fb15SPaul Saab 	return (o->odesc[0]);
513a5f0fb15SPaul Saab }
514a5f0fb15SPaul Saab 
515a5f0fb15SPaul Saab /*
516a5f0fb15SPaul Saab  * Return whether or not there is a string option pending;
517a5f0fb15SPaul Saab  * that is, if the previous option was a string-valued option letter
518a5f0fb15SPaul Saab  * (like -P) without a following string.
519a5f0fb15SPaul Saab  * In that case, the current option is taken to be the string for
520a5f0fb15SPaul Saab  * the previous option.
521a5f0fb15SPaul Saab  */
522a5f0fb15SPaul Saab 	public int
523a5f0fb15SPaul Saab isoptpending()
524a5f0fb15SPaul Saab {
525a5f0fb15SPaul Saab 	return (pendopt != NULL);
526a5f0fb15SPaul Saab }
527a5f0fb15SPaul Saab 
528a5f0fb15SPaul Saab /*
529a5f0fb15SPaul Saab  * Print error message about missing string.
530a5f0fb15SPaul Saab  */
531a5f0fb15SPaul Saab 	static void
532a5f0fb15SPaul Saab nostring(printopt)
533a5f0fb15SPaul Saab 	char *printopt;
534a5f0fb15SPaul Saab {
535a5f0fb15SPaul Saab 	PARG parg;
536a5f0fb15SPaul Saab 	parg.p_string = printopt;
537a5f0fb15SPaul Saab 	error("Value is required after %s", &parg);
538a5f0fb15SPaul Saab }
539a5f0fb15SPaul Saab 
540a5f0fb15SPaul Saab /*
541a5f0fb15SPaul Saab  * Print error message if a STRING type option is not followed by a string.
542a5f0fb15SPaul Saab  */
543a5f0fb15SPaul Saab 	public void
544a5f0fb15SPaul Saab nopendopt()
545a5f0fb15SPaul Saab {
546*33096f16SXin LI 	nostring(opt_desc(pendopt));
547a5f0fb15SPaul Saab }
548a5f0fb15SPaul Saab 
549a5f0fb15SPaul Saab /*
550a5f0fb15SPaul Saab  * Scan to end of string or to an END_OPTION_STRING character.
551a5f0fb15SPaul Saab  * In the latter case, replace the char with a null char.
552a5f0fb15SPaul Saab  * Return a pointer to the remainder of the string, if any.
553a5f0fb15SPaul Saab  */
554a5f0fb15SPaul Saab 	static char *
555000ba3e8STim J. Robbins optstring(s, p_str, printopt, validchars)
556a5f0fb15SPaul Saab 	char *s;
557000ba3e8STim J. Robbins 	char **p_str;
558a5f0fb15SPaul Saab 	char *printopt;
559c9346414SPaul Saab 	char *validchars;
560a5f0fb15SPaul Saab {
561a5f0fb15SPaul Saab 	register char *p;
562a5f0fb15SPaul Saab 
563a5f0fb15SPaul Saab 	if (*s == '\0')
564a5f0fb15SPaul Saab 	{
565a5f0fb15SPaul Saab 		nostring(printopt);
566a5f0fb15SPaul Saab 		quit(QUIT_ERROR);
567a5f0fb15SPaul Saab 	}
568000ba3e8STim J. Robbins 	*p_str = s;
569a5f0fb15SPaul Saab 	for (p = s;  *p != '\0';  p++)
570000ba3e8STim J. Robbins 	{
571c9346414SPaul Saab 		if (*p == END_OPTION_STRING ||
572c9346414SPaul Saab 		    (validchars != NULL && strchr(validchars, *p) == NULL))
573a5f0fb15SPaul Saab 		{
574c9346414SPaul Saab 			switch (*p)
575c9346414SPaul Saab 			{
576c9346414SPaul Saab 			case END_OPTION_STRING:
577c9346414SPaul Saab 			case ' ':  case '\t':  case '-':
578000ba3e8STim J. Robbins 				/* Replace the char with a null to terminate string. */
579000ba3e8STim J. Robbins 				*p++ = '\0';
580c9346414SPaul Saab 				break;
581c9346414SPaul Saab 			default:
582000ba3e8STim J. Robbins 				/* Cannot replace char; make a copy of the string. */
583000ba3e8STim J. Robbins 				*p_str = (char *) ecalloc(p-s+1, sizeof(char));
584000ba3e8STim J. Robbins 				strncpy(*p_str, s, p-s);
585000ba3e8STim J. Robbins 				(*p_str)[p-s] = '\0';
586c9346414SPaul Saab 				break;
587c9346414SPaul Saab 			}
588000ba3e8STim J. Robbins 			break;
589000ba3e8STim J. Robbins 		}
590a5f0fb15SPaul Saab 	}
591a5f0fb15SPaul Saab 	return (p);
592a5f0fb15SPaul Saab }
593a5f0fb15SPaul Saab 
594a5f0fb15SPaul Saab /*
5957f074f9cSXin LI  */
5967f074f9cSXin LI 	static int
5977f074f9cSXin LI num_error(printopt, errp)
5987f074f9cSXin LI 	char *printopt;
5997f074f9cSXin LI 	int *errp;
6007f074f9cSXin LI {
6017f074f9cSXin LI 	PARG parg;
6027f074f9cSXin LI 
6037f074f9cSXin LI 	if (errp != NULL)
6047f074f9cSXin LI 	{
6057f074f9cSXin LI 		*errp = TRUE;
6067f074f9cSXin LI 		return (-1);
6077f074f9cSXin LI 	}
6087f074f9cSXin LI 	if (printopt != NULL)
6097f074f9cSXin LI 	{
6107f074f9cSXin LI 		parg.p_string = printopt;
6117f074f9cSXin LI 		error("Number is required after %s", &parg);
6127f074f9cSXin LI 	}
6137f074f9cSXin LI 	quit(QUIT_ERROR);
6147f074f9cSXin LI 	/* NOTREACHED */
6157f074f9cSXin LI 	return (-1);
6167f074f9cSXin LI }
6177f074f9cSXin LI 
6187f074f9cSXin LI /*
619a5f0fb15SPaul Saab  * Translate a string into a number.
620a5f0fb15SPaul Saab  * Like atoi(), but takes a pointer to a char *, and updates
621a5f0fb15SPaul Saab  * the char * to point after the translated number.
622a5f0fb15SPaul Saab  */
623a5f0fb15SPaul Saab 	public int
624a5f0fb15SPaul Saab getnum(sp, printopt, errp)
625a5f0fb15SPaul Saab 	char **sp;
626a5f0fb15SPaul Saab 	char *printopt;
627a5f0fb15SPaul Saab 	int *errp;
628a5f0fb15SPaul Saab {
629a5f0fb15SPaul Saab 	register char *s;
630a5f0fb15SPaul Saab 	register int n;
631a5f0fb15SPaul Saab 	register int neg;
632a5f0fb15SPaul Saab 
633a5f0fb15SPaul Saab 	s = skipsp(*sp);
634a5f0fb15SPaul Saab 	neg = FALSE;
635a5f0fb15SPaul Saab 	if (*s == '-')
636a5f0fb15SPaul Saab 	{
637a5f0fb15SPaul Saab 		neg = TRUE;
638a5f0fb15SPaul Saab 		s++;
639a5f0fb15SPaul Saab 	}
640a5f0fb15SPaul Saab 	if (*s < '0' || *s > '9')
6417f074f9cSXin LI 		return (num_error(printopt, errp));
642a5f0fb15SPaul Saab 
643a5f0fb15SPaul Saab 	n = 0;
644a5f0fb15SPaul Saab 	while (*s >= '0' && *s <= '9')
645a5f0fb15SPaul Saab 		n = 10 * n + *s++ - '0';
646a5f0fb15SPaul Saab 	*sp = s;
647a5f0fb15SPaul Saab 	if (errp != NULL)
648a5f0fb15SPaul Saab 		*errp = FALSE;
649a5f0fb15SPaul Saab 	if (neg)
650a5f0fb15SPaul Saab 		n = -n;
651a5f0fb15SPaul Saab 	return (n);
652a5f0fb15SPaul Saab }
6537f074f9cSXin LI 
6547f074f9cSXin LI /*
6557f074f9cSXin LI  * Translate a string into a fraction, represented by the part of a
6567f074f9cSXin LI  * number which would follow a decimal point.
6577f074f9cSXin LI  * The value of the fraction is returned as parts per NUM_FRAC_DENOM.
6587f074f9cSXin LI  * That is, if "n" is returned, the fraction intended is n/NUM_FRAC_DENOM.
6597f074f9cSXin LI  */
6607f074f9cSXin LI 	public long
6617f074f9cSXin LI getfraction(sp, printopt, errp)
6627f074f9cSXin LI 	char **sp;
6637f074f9cSXin LI 	char *printopt;
6647f074f9cSXin LI 	int *errp;
6657f074f9cSXin LI {
6667f074f9cSXin LI 	register char *s;
6677f074f9cSXin LI 	long frac = 0;
6687f074f9cSXin LI 	int fraclen = 0;
6697f074f9cSXin LI 
6707f074f9cSXin LI 	s = skipsp(*sp);
6717f074f9cSXin LI 	if (*s < '0' || *s > '9')
6727f074f9cSXin LI 		return (num_error(printopt, errp));
6737f074f9cSXin LI 
6747f074f9cSXin LI 	for ( ;  *s >= '0' && *s <= '9';  s++)
6757f074f9cSXin LI 	{
6767f074f9cSXin LI 		frac = (frac * 10) + (*s - '0');
6777f074f9cSXin LI 		fraclen++;
6787f074f9cSXin LI 	}
6797f074f9cSXin LI 	if (fraclen > NUM_LOG_FRAC_DENOM)
6807f074f9cSXin LI 		while (fraclen-- > NUM_LOG_FRAC_DENOM)
6817f074f9cSXin LI 			frac /= 10;
6827f074f9cSXin LI 	else
6837f074f9cSXin LI 		while (fraclen++ < NUM_LOG_FRAC_DENOM)
6847f074f9cSXin LI 			frac *= 10;
6857f074f9cSXin LI 	*sp = s;
6867f074f9cSXin LI 	if (errp != NULL)
6877f074f9cSXin LI 		*errp = FALSE;
6887f074f9cSXin LI 	return (frac);
6897f074f9cSXin LI }
6907f074f9cSXin LI 
6917f074f9cSXin LI 
6927f074f9cSXin LI /*
6937f074f9cSXin LI  * Get the value of the -e flag.
6947f074f9cSXin LI  */
6957f074f9cSXin LI 	public int
6967f074f9cSXin LI get_quit_at_eof()
6977f074f9cSXin LI {
6987f074f9cSXin LI 	if (!less_is_more)
6997f074f9cSXin LI 		return quit_at_eof;
7007f074f9cSXin LI 	/* When less_is_more is set, the -e flag semantics are different. */
7017f074f9cSXin LI 	return quit_at_eof ? OPT_ON : OPT_ONPLUS;
7027f074f9cSXin LI }
703