xref: /minix3/external/bsd/less/dist/option.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1*84d9c625SLionel Sambuc /*	$NetBSD: option.c,v 1.4 2013/09/04 19:44:21 tron Exp $	*/
2f7cf2976SLionel Sambuc 
3f7cf2976SLionel Sambuc /*
4*84d9c625SLionel Sambuc  * Copyright (C) 1984-2012  Mark Nudelman
5f7cf2976SLionel Sambuc  *
6f7cf2976SLionel Sambuc  * You may distribute under the terms of either the GNU General Public
7f7cf2976SLionel Sambuc  * License or the Less License, as specified in the README file.
8f7cf2976SLionel Sambuc  *
9*84d9c625SLionel Sambuc  * For more information, see the README file.
10f7cf2976SLionel Sambuc  */
11f7cf2976SLionel Sambuc 
12f7cf2976SLionel Sambuc 
13f7cf2976SLionel Sambuc /*
14f7cf2976SLionel Sambuc  * Process command line options.
15f7cf2976SLionel Sambuc  *
16f7cf2976SLionel Sambuc  * Each option is a single letter which controls a program variable.
17f7cf2976SLionel Sambuc  * The options have defaults which may be changed via
18f7cf2976SLionel Sambuc  * the command line option, toggled via the "-" command,
19f7cf2976SLionel Sambuc  * or queried via the "_" command.
20f7cf2976SLionel Sambuc  */
21f7cf2976SLionel Sambuc 
22f7cf2976SLionel Sambuc #include "less.h"
23f7cf2976SLionel Sambuc #include "option.h"
24f7cf2976SLionel Sambuc 
25f7cf2976SLionel Sambuc static struct loption *pendopt;
26f7cf2976SLionel Sambuc public int plusoption = FALSE;
27f7cf2976SLionel Sambuc 
28f7cf2976SLionel Sambuc static char *optstring __P((char *, char **, char *, char *));
29f7cf2976SLionel Sambuc static int flip_triple __P((int, int));
30f7cf2976SLionel Sambuc static void nostring __P((char *));
31f7cf2976SLionel Sambuc 
32f7cf2976SLionel Sambuc extern int screen_trashed;
33f7cf2976SLionel Sambuc extern int less_is_more;
34f7cf2976SLionel Sambuc extern int quit_at_eof;
35f7cf2976SLionel Sambuc extern char *every_first_cmd;
36*84d9c625SLionel Sambuc extern int opt_use_backslash;
37f7cf2976SLionel Sambuc 
38f7cf2976SLionel Sambuc /*
39f7cf2976SLionel Sambuc  * Return a printable description of an option.
40f7cf2976SLionel Sambuc  */
41f7cf2976SLionel Sambuc 	static char *
opt_desc(o)42f7cf2976SLionel Sambuc opt_desc(o)
43f7cf2976SLionel Sambuc 	struct loption *o;
44f7cf2976SLionel Sambuc {
45f7cf2976SLionel Sambuc 	static char buf[OPTNAME_MAX + 10];
46f7cf2976SLionel Sambuc 	if (o->oletter == OLETTER_NONE)
47f7cf2976SLionel Sambuc 		SNPRINTF1(buf, sizeof(buf), "--%s", o->onames->oname);
48f7cf2976SLionel Sambuc 	else
49f7cf2976SLionel Sambuc 		SNPRINTF2(buf, sizeof(buf), "-%c (--%s)", o->oletter, o->onames->oname);
50f7cf2976SLionel Sambuc 	return (buf);
51f7cf2976SLionel Sambuc }
52f7cf2976SLionel Sambuc 
53f7cf2976SLionel Sambuc /*
54f7cf2976SLionel Sambuc  * Return a string suitable for printing as the "name" of an option.
55f7cf2976SLionel Sambuc  * For example, if the option letter is 'x', just return "-x".
56f7cf2976SLionel Sambuc  */
57f7cf2976SLionel Sambuc 	public char *
propt(c)58f7cf2976SLionel Sambuc propt(c)
59f7cf2976SLionel Sambuc 	int c;
60f7cf2976SLionel Sambuc {
61f7cf2976SLionel Sambuc 	static char buf[8];
62f7cf2976SLionel Sambuc 
63f7cf2976SLionel Sambuc 	sprintf(buf, "-%s", prchar(c));
64f7cf2976SLionel Sambuc 	return (buf);
65f7cf2976SLionel Sambuc }
66f7cf2976SLionel Sambuc 
67f7cf2976SLionel Sambuc /*
68f7cf2976SLionel Sambuc  * Scan an argument (either from the command line or from the
69f7cf2976SLionel Sambuc  * LESS environment variable) and process it.
70f7cf2976SLionel Sambuc  */
71f7cf2976SLionel Sambuc 	public void
scan_option(s)72f7cf2976SLionel Sambuc scan_option(s)
73f7cf2976SLionel Sambuc 	char *s;
74f7cf2976SLionel Sambuc {
75f7cf2976SLionel Sambuc 	register struct loption *o;
76f7cf2976SLionel Sambuc 	register int optc;
77f7cf2976SLionel Sambuc 	char *optname;
78f7cf2976SLionel Sambuc 	char *printopt;
79f7cf2976SLionel Sambuc 	char *str;
80f7cf2976SLionel Sambuc 	int set_default;
81f7cf2976SLionel Sambuc 	int lc;
82f7cf2976SLionel Sambuc 	int err;
83f7cf2976SLionel Sambuc 	PARG parg;
84f7cf2976SLionel Sambuc 
85f7cf2976SLionel Sambuc 	if (s == NULL)
86f7cf2976SLionel Sambuc 		return;
87f7cf2976SLionel Sambuc 
88f7cf2976SLionel Sambuc 	/*
89f7cf2976SLionel Sambuc 	 * If we have a pending option which requires an argument,
90f7cf2976SLionel Sambuc 	 * handle it now.
91f7cf2976SLionel Sambuc 	 * This happens if the previous option was, for example, "-P"
92f7cf2976SLionel Sambuc 	 * without a following string.  In that case, the current
93f7cf2976SLionel Sambuc 	 * option is simply the argument for the previous option.
94f7cf2976SLionel Sambuc 	 */
95f7cf2976SLionel Sambuc 	if (pendopt != NULL)
96f7cf2976SLionel Sambuc 	{
97f7cf2976SLionel Sambuc 		switch (pendopt->otype & OTYPE)
98f7cf2976SLionel Sambuc 		{
99f7cf2976SLionel Sambuc 		case STRING:
100f7cf2976SLionel Sambuc 			(*pendopt->ofunc)(INIT, s);
101f7cf2976SLionel Sambuc 			break;
102f7cf2976SLionel Sambuc 		case NUMBER:
103f7cf2976SLionel Sambuc 			printopt = opt_desc(pendopt);
104f7cf2976SLionel Sambuc 			*(pendopt->ovar) = getnum(&s, printopt, (int*)NULL);
105f7cf2976SLionel Sambuc 			break;
106f7cf2976SLionel Sambuc 		}
107f7cf2976SLionel Sambuc 		pendopt = NULL;
108f7cf2976SLionel Sambuc 		return;
109f7cf2976SLionel Sambuc 	}
110f7cf2976SLionel Sambuc 
111f7cf2976SLionel Sambuc 	set_default = FALSE;
112f7cf2976SLionel Sambuc 	optname = NULL;
113f7cf2976SLionel Sambuc 
114f7cf2976SLionel Sambuc 	while (*s != '\0')
115f7cf2976SLionel Sambuc 	{
116f7cf2976SLionel Sambuc 		/*
117f7cf2976SLionel Sambuc 		 * Check some special cases first.
118f7cf2976SLionel Sambuc 		 */
119f7cf2976SLionel Sambuc 		switch (optc = *s++)
120f7cf2976SLionel Sambuc 		{
121f7cf2976SLionel Sambuc 		case ' ':
122f7cf2976SLionel Sambuc 		case '\t':
123f7cf2976SLionel Sambuc 		case END_OPTION_STRING:
124f7cf2976SLionel Sambuc 			continue;
125f7cf2976SLionel Sambuc 		case '-':
126f7cf2976SLionel Sambuc 			/*
127f7cf2976SLionel Sambuc 			 * "--" indicates an option name instead of a letter.
128f7cf2976SLionel Sambuc 			 */
129f7cf2976SLionel Sambuc 			if (*s == '-')
130f7cf2976SLionel Sambuc 			{
131f7cf2976SLionel Sambuc 				optname = ++s;
132f7cf2976SLionel Sambuc 				break;
133f7cf2976SLionel Sambuc 			}
134f7cf2976SLionel Sambuc 			/*
135f7cf2976SLionel Sambuc 			 * "-+" means set these options back to their defaults.
136f7cf2976SLionel Sambuc 			 * (They may have been set otherwise by previous
137f7cf2976SLionel Sambuc 			 * options.)
138f7cf2976SLionel Sambuc 			 */
139f7cf2976SLionel Sambuc 			set_default = (*s == '+');
140f7cf2976SLionel Sambuc 			if (set_default)
141f7cf2976SLionel Sambuc 				s++;
142f7cf2976SLionel Sambuc 			continue;
143f7cf2976SLionel Sambuc 		case '+':
144f7cf2976SLionel Sambuc 			/*
145f7cf2976SLionel Sambuc 			 * An option prefixed by a "+" is ungotten, so
146f7cf2976SLionel Sambuc 			 * that it is interpreted as less commands
147f7cf2976SLionel Sambuc 			 * processed at the start of the first input file.
148f7cf2976SLionel Sambuc 			 * "++" means process the commands at the start of
149f7cf2976SLionel Sambuc 			 * EVERY input file.
150f7cf2976SLionel Sambuc 			 */
151f7cf2976SLionel Sambuc 			plusoption = TRUE;
152f7cf2976SLionel Sambuc 			s = optstring(s, &str, propt('+'), NULL);
153*84d9c625SLionel Sambuc 			if (s == NULL)
154*84d9c625SLionel Sambuc 				return;
155f7cf2976SLionel Sambuc 			if (*str == '+')
156*84d9c625SLionel Sambuc 				every_first_cmd = save(str+1);
157f7cf2976SLionel Sambuc 			else
158f7cf2976SLionel Sambuc 				ungetsc(str);
159*84d9c625SLionel Sambuc 			free(str);
160f7cf2976SLionel Sambuc 			continue;
161f7cf2976SLionel Sambuc 		case '0':  case '1':  case '2':  case '3':  case '4':
162f7cf2976SLionel Sambuc 		case '5':  case '6':  case '7':  case '8':  case '9':
163f7cf2976SLionel Sambuc 			/*
164f7cf2976SLionel Sambuc 			 * Special "more" compatibility form "-<number>"
165f7cf2976SLionel Sambuc 			 * instead of -z<number> to set the scrolling
166f7cf2976SLionel Sambuc 			 * window size.
167f7cf2976SLionel Sambuc 			 */
168f7cf2976SLionel Sambuc 			s--;
169f7cf2976SLionel Sambuc 			optc = 'z';
170f7cf2976SLionel Sambuc 			break;
171f7cf2976SLionel Sambuc 		case 'n':
172f7cf2976SLionel Sambuc 			if (less_is_more)
173f7cf2976SLionel Sambuc 				optc = 'z';
174f7cf2976SLionel Sambuc 			break;
175f7cf2976SLionel Sambuc 		}
176f7cf2976SLionel Sambuc 
177f7cf2976SLionel Sambuc 		/*
178f7cf2976SLionel Sambuc 		 * Not a special case.
179f7cf2976SLionel Sambuc 		 * Look up the option letter in the option table.
180f7cf2976SLionel Sambuc 		 */
181f7cf2976SLionel Sambuc 		err = 0;
182f7cf2976SLionel Sambuc 		if (optname == NULL)
183f7cf2976SLionel Sambuc 		{
184f7cf2976SLionel Sambuc 			printopt = propt(optc);
185f7cf2976SLionel Sambuc 			lc = ASCII_IS_LOWER(optc);
186f7cf2976SLionel Sambuc 			o = findopt(optc);
187f7cf2976SLionel Sambuc 		} else
188f7cf2976SLionel Sambuc 		{
189f7cf2976SLionel Sambuc 			printopt = optname;
190f7cf2976SLionel Sambuc 			lc = ASCII_IS_LOWER(optname[0]);
191f7cf2976SLionel Sambuc 			o = findopt_name(&optname, NULL, &err);
192f7cf2976SLionel Sambuc 			s = optname;
193f7cf2976SLionel Sambuc 			optname = NULL;
194f7cf2976SLionel Sambuc 			if (*s == '\0' || *s == ' ')
195f7cf2976SLionel Sambuc 			{
196f7cf2976SLionel Sambuc 				/*
197f7cf2976SLionel Sambuc 				 * The option name matches exactly.
198f7cf2976SLionel Sambuc 				 */
199f7cf2976SLionel Sambuc 				;
200f7cf2976SLionel Sambuc 			} else if (*s == '=')
201f7cf2976SLionel Sambuc 			{
202f7cf2976SLionel Sambuc 				/*
203f7cf2976SLionel Sambuc 				 * The option name is followed by "=value".
204f7cf2976SLionel Sambuc 				 */
205f7cf2976SLionel Sambuc 				if (o != NULL &&
206f7cf2976SLionel Sambuc 				    (o->otype & OTYPE) != STRING &&
207f7cf2976SLionel Sambuc 				    (o->otype & OTYPE) != NUMBER)
208f7cf2976SLionel Sambuc 				{
209f7cf2976SLionel Sambuc 					parg.p_string = printopt;
210f7cf2976SLionel Sambuc 					error("The %s option should not be followed by =",
211f7cf2976SLionel Sambuc 						&parg);
212*84d9c625SLionel Sambuc 					return;
213f7cf2976SLionel Sambuc 				}
214f7cf2976SLionel Sambuc 				s++;
215f7cf2976SLionel Sambuc 			} else
216f7cf2976SLionel Sambuc 			{
217f7cf2976SLionel Sambuc 				/*
218f7cf2976SLionel Sambuc 				 * The specified name is longer than the
219f7cf2976SLionel Sambuc 				 * real option name.
220f7cf2976SLionel Sambuc 				 */
221f7cf2976SLionel Sambuc 				o = NULL;
222f7cf2976SLionel Sambuc 			}
223f7cf2976SLionel Sambuc 		}
224f7cf2976SLionel Sambuc 		if (o == NULL)
225f7cf2976SLionel Sambuc 		{
226f7cf2976SLionel Sambuc 			parg.p_string = printopt;
227f7cf2976SLionel Sambuc 			if (err == OPT_AMBIG)
228f7cf2976SLionel Sambuc 				error("%s is an ambiguous abbreviation (\"less --help\" for help)",
229f7cf2976SLionel Sambuc 					&parg);
230f7cf2976SLionel Sambuc 			else
231f7cf2976SLionel Sambuc 				error("There is no %s option (\"less --help\" for help)",
232f7cf2976SLionel Sambuc 					&parg);
233*84d9c625SLionel Sambuc 			return;
234f7cf2976SLionel Sambuc 		}
235f7cf2976SLionel Sambuc 
236f7cf2976SLionel Sambuc 		str = NULL;
237f7cf2976SLionel Sambuc 		switch (o->otype & OTYPE)
238f7cf2976SLionel Sambuc 		{
239f7cf2976SLionel Sambuc 		case BOOL:
240f7cf2976SLionel Sambuc 			if (set_default)
241f7cf2976SLionel Sambuc 				*(o->ovar) = o->odefault;
242f7cf2976SLionel Sambuc 			else
243f7cf2976SLionel Sambuc 				*(o->ovar) = ! o->odefault;
244f7cf2976SLionel Sambuc 			break;
245f7cf2976SLionel Sambuc 		case TRIPLE:
246f7cf2976SLionel Sambuc 			if (set_default)
247f7cf2976SLionel Sambuc 				*(o->ovar) = o->odefault;
248f7cf2976SLionel Sambuc 			else
249f7cf2976SLionel Sambuc 				*(o->ovar) = flip_triple(o->odefault, lc);
250f7cf2976SLionel Sambuc 			break;
251f7cf2976SLionel Sambuc 		case STRING:
252f7cf2976SLionel Sambuc 			if (*s == '\0')
253f7cf2976SLionel Sambuc 			{
254f7cf2976SLionel Sambuc 				/*
255f7cf2976SLionel Sambuc 				 * Set pendopt and return.
256f7cf2976SLionel Sambuc 				 * We will get the string next time
257f7cf2976SLionel Sambuc 				 * scan_option is called.
258f7cf2976SLionel Sambuc 				 */
259f7cf2976SLionel Sambuc 				pendopt = o;
260f7cf2976SLionel Sambuc 				return;
261f7cf2976SLionel Sambuc 			}
262f7cf2976SLionel Sambuc 			/*
263f7cf2976SLionel Sambuc 			 * Don't do anything here.
264f7cf2976SLionel Sambuc 			 * All processing of STRING options is done by
265f7cf2976SLionel Sambuc 			 * the handling function.
266f7cf2976SLionel Sambuc 			 */
267f7cf2976SLionel Sambuc 			while (*s == ' ')
268f7cf2976SLionel Sambuc 				s++;
269f7cf2976SLionel Sambuc 			s = optstring(s, &str, printopt, o->odesc[1]);
270*84d9c625SLionel Sambuc 			if (s == NULL)
271*84d9c625SLionel Sambuc 				return;
272f7cf2976SLionel Sambuc 			break;
273f7cf2976SLionel Sambuc 		case NUMBER:
274f7cf2976SLionel Sambuc 			if (*s == '\0')
275f7cf2976SLionel Sambuc 			{
276f7cf2976SLionel Sambuc 				pendopt = o;
277f7cf2976SLionel Sambuc 				return;
278f7cf2976SLionel Sambuc 			}
279f7cf2976SLionel Sambuc 			*(o->ovar) = getnum(&s, printopt, (int*)NULL);
280f7cf2976SLionel Sambuc 			break;
281f7cf2976SLionel Sambuc 		}
282f7cf2976SLionel Sambuc 		/*
283f7cf2976SLionel Sambuc 		 * If the option has a handling function, call it.
284f7cf2976SLionel Sambuc 		 */
285f7cf2976SLionel Sambuc 		if (o->ofunc != NULL)
286f7cf2976SLionel Sambuc 			(*o->ofunc)(INIT, str);
287*84d9c625SLionel Sambuc 		if (str != NULL)
288*84d9c625SLionel Sambuc 			free(str);
289f7cf2976SLionel Sambuc 	}
290f7cf2976SLionel Sambuc }
291f7cf2976SLionel Sambuc 
292f7cf2976SLionel Sambuc /*
293f7cf2976SLionel Sambuc  * Toggle command line flags from within the program.
294f7cf2976SLionel Sambuc  * Used by the "-" and "_" commands.
295f7cf2976SLionel Sambuc  * how_toggle may be:
296f7cf2976SLionel Sambuc  *	OPT_NO_TOGGLE	just report the current setting, without changing it.
297f7cf2976SLionel Sambuc  *	OPT_TOGGLE	invert the current setting
298f7cf2976SLionel Sambuc  *	OPT_UNSET	set to the default value
299f7cf2976SLionel Sambuc  *	OPT_SET		set to the inverse of the default value
300f7cf2976SLionel Sambuc  */
301f7cf2976SLionel Sambuc 	public void
toggle_option(o,lower,s,how_toggle)302f7cf2976SLionel Sambuc toggle_option(o, lower, s, how_toggle)
303f7cf2976SLionel Sambuc 	struct loption *o;
304f7cf2976SLionel Sambuc 	int lower;
305f7cf2976SLionel Sambuc 	char *s;
306f7cf2976SLionel Sambuc 	int how_toggle;
307f7cf2976SLionel Sambuc {
308f7cf2976SLionel Sambuc 	register int num;
309f7cf2976SLionel Sambuc 	int no_prompt;
310f7cf2976SLionel Sambuc 	int err;
311f7cf2976SLionel Sambuc 	PARG parg;
312f7cf2976SLionel Sambuc 
313f7cf2976SLionel Sambuc 	no_prompt = (how_toggle & OPT_NO_PROMPT);
314f7cf2976SLionel Sambuc 	how_toggle &= ~OPT_NO_PROMPT;
315f7cf2976SLionel Sambuc 
316f7cf2976SLionel Sambuc 	if (o == NULL)
317f7cf2976SLionel Sambuc 	{
318f7cf2976SLionel Sambuc 		error("No such option", NULL_PARG);
319f7cf2976SLionel Sambuc 		return;
320f7cf2976SLionel Sambuc 	}
321f7cf2976SLionel Sambuc 
322f7cf2976SLionel Sambuc 	if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE))
323f7cf2976SLionel Sambuc 	{
324f7cf2976SLionel Sambuc 		parg.p_string = opt_desc(o);
325f7cf2976SLionel Sambuc 		error("Cannot change the %s option", &parg);
326f7cf2976SLionel Sambuc 		return;
327f7cf2976SLionel Sambuc 	}
328f7cf2976SLionel Sambuc 
329f7cf2976SLionel Sambuc 	if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY))
330f7cf2976SLionel Sambuc 	{
331f7cf2976SLionel Sambuc 		parg.p_string = opt_desc(o);
332f7cf2976SLionel Sambuc 		error("Cannot query the %s option", &parg);
333f7cf2976SLionel Sambuc 		return;
334f7cf2976SLionel Sambuc 	}
335f7cf2976SLionel Sambuc 
336f7cf2976SLionel Sambuc 	/*
337f7cf2976SLionel Sambuc 	 * Check for something which appears to be a do_toggle
338f7cf2976SLionel Sambuc 	 * (because the "-" command was used), but really is not.
339f7cf2976SLionel Sambuc 	 * This could be a string option with no string, or
340f7cf2976SLionel Sambuc 	 * a number option with no number.
341f7cf2976SLionel Sambuc 	 */
342f7cf2976SLionel Sambuc 	switch (o->otype & OTYPE)
343f7cf2976SLionel Sambuc 	{
344f7cf2976SLionel Sambuc 	case STRING:
345f7cf2976SLionel Sambuc 	case NUMBER:
346f7cf2976SLionel Sambuc 		if (how_toggle == OPT_TOGGLE && *s == '\0')
347f7cf2976SLionel Sambuc 			how_toggle = OPT_NO_TOGGLE;
348f7cf2976SLionel Sambuc 		break;
349f7cf2976SLionel Sambuc 	}
350f7cf2976SLionel Sambuc 
351f7cf2976SLionel Sambuc #if HILITE_SEARCH
352f7cf2976SLionel Sambuc 	if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
353f7cf2976SLionel Sambuc 		repaint_hilite(0);
354f7cf2976SLionel Sambuc #endif
355f7cf2976SLionel Sambuc 
356f7cf2976SLionel Sambuc 	/*
357f7cf2976SLionel Sambuc 	 * Now actually toggle (change) the variable.
358f7cf2976SLionel Sambuc 	 */
359f7cf2976SLionel Sambuc 	if (how_toggle != OPT_NO_TOGGLE)
360f7cf2976SLionel Sambuc 	{
361f7cf2976SLionel Sambuc 		switch (o->otype & OTYPE)
362f7cf2976SLionel Sambuc 		{
363f7cf2976SLionel Sambuc 		case BOOL:
364f7cf2976SLionel Sambuc 			/*
365f7cf2976SLionel Sambuc 			 * Boolean.
366f7cf2976SLionel Sambuc 			 */
367f7cf2976SLionel Sambuc 			switch (how_toggle)
368f7cf2976SLionel Sambuc 			{
369f7cf2976SLionel Sambuc 			case OPT_TOGGLE:
370f7cf2976SLionel Sambuc 				*(o->ovar) = ! *(o->ovar);
371f7cf2976SLionel Sambuc 				break;
372f7cf2976SLionel Sambuc 			case OPT_UNSET:
373f7cf2976SLionel Sambuc 				*(o->ovar) = o->odefault;
374f7cf2976SLionel Sambuc 				break;
375f7cf2976SLionel Sambuc 			case OPT_SET:
376f7cf2976SLionel Sambuc 				*(o->ovar) = ! o->odefault;
377f7cf2976SLionel Sambuc 				break;
378f7cf2976SLionel Sambuc 			}
379f7cf2976SLionel Sambuc 			break;
380f7cf2976SLionel Sambuc 		case TRIPLE:
381f7cf2976SLionel Sambuc 			/*
382f7cf2976SLionel Sambuc 			 * Triple:
383f7cf2976SLionel Sambuc 			 *	If user gave the lower case letter, then switch
384f7cf2976SLionel Sambuc 			 *	to 1 unless already 1, in which case make it 0.
385f7cf2976SLionel Sambuc 			 *	If user gave the upper case letter, then switch
386f7cf2976SLionel Sambuc 			 *	to 2 unless already 2, in which case make it 0.
387f7cf2976SLionel Sambuc 			 */
388f7cf2976SLionel Sambuc 			switch (how_toggle)
389f7cf2976SLionel Sambuc 			{
390f7cf2976SLionel Sambuc 			case OPT_TOGGLE:
391f7cf2976SLionel Sambuc 				*(o->ovar) = flip_triple(*(o->ovar), lower);
392f7cf2976SLionel Sambuc 				break;
393f7cf2976SLionel Sambuc 			case OPT_UNSET:
394f7cf2976SLionel Sambuc 				*(o->ovar) = o->odefault;
395f7cf2976SLionel Sambuc 				break;
396f7cf2976SLionel Sambuc 			case OPT_SET:
397f7cf2976SLionel Sambuc 				*(o->ovar) = flip_triple(o->odefault, lower);
398f7cf2976SLionel Sambuc 				break;
399f7cf2976SLionel Sambuc 			}
400f7cf2976SLionel Sambuc 			break;
401f7cf2976SLionel Sambuc 		case STRING:
402f7cf2976SLionel Sambuc 			/*
403f7cf2976SLionel Sambuc 			 * String: don't do anything here.
404f7cf2976SLionel Sambuc 			 *	The handling function will do everything.
405f7cf2976SLionel Sambuc 			 */
406f7cf2976SLionel Sambuc 			switch (how_toggle)
407f7cf2976SLionel Sambuc 			{
408f7cf2976SLionel Sambuc 			case OPT_SET:
409f7cf2976SLionel Sambuc 			case OPT_UNSET:
410f7cf2976SLionel Sambuc 				error("Cannot use \"-+\" or \"--\" for a string option",
411f7cf2976SLionel Sambuc 					NULL_PARG);
412f7cf2976SLionel Sambuc 				return;
413f7cf2976SLionel Sambuc 			}
414f7cf2976SLionel Sambuc 			break;
415f7cf2976SLionel Sambuc 		case NUMBER:
416f7cf2976SLionel Sambuc 			/*
417f7cf2976SLionel Sambuc 			 * Number: set the variable to the given number.
418f7cf2976SLionel Sambuc 			 */
419f7cf2976SLionel Sambuc 			switch (how_toggle)
420f7cf2976SLionel Sambuc 			{
421f7cf2976SLionel Sambuc 			case OPT_TOGGLE:
422f7cf2976SLionel Sambuc 				num = getnum(&s, NULL, &err);
423f7cf2976SLionel Sambuc 				if (!err)
424f7cf2976SLionel Sambuc 					*(o->ovar) = num;
425f7cf2976SLionel Sambuc 				break;
426f7cf2976SLionel Sambuc 			case OPT_UNSET:
427f7cf2976SLionel Sambuc 				*(o->ovar) = o->odefault;
428f7cf2976SLionel Sambuc 				break;
429f7cf2976SLionel Sambuc 			case OPT_SET:
430f7cf2976SLionel Sambuc 				error("Can't use \"-!\" for a numeric option",
431f7cf2976SLionel Sambuc 					NULL_PARG);
432f7cf2976SLionel Sambuc 				return;
433f7cf2976SLionel Sambuc 			}
434f7cf2976SLionel Sambuc 			break;
435f7cf2976SLionel Sambuc 		}
436f7cf2976SLionel Sambuc 	}
437f7cf2976SLionel Sambuc 
438f7cf2976SLionel Sambuc 	/*
439f7cf2976SLionel Sambuc 	 * Call the handling function for any special action
440f7cf2976SLionel Sambuc 	 * specific to this option.
441f7cf2976SLionel Sambuc 	 */
442f7cf2976SLionel Sambuc 	if (o->ofunc != NULL)
443f7cf2976SLionel Sambuc 		(*o->ofunc)((how_toggle==OPT_NO_TOGGLE) ? QUERY : TOGGLE, s);
444f7cf2976SLionel Sambuc 
445f7cf2976SLionel Sambuc #if HILITE_SEARCH
446f7cf2976SLionel Sambuc 	if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
447f7cf2976SLionel Sambuc 		chg_hilite();
448f7cf2976SLionel Sambuc #endif
449f7cf2976SLionel Sambuc 
450f7cf2976SLionel Sambuc 	if (!no_prompt)
451f7cf2976SLionel Sambuc 	{
452f7cf2976SLionel Sambuc 		/*
453f7cf2976SLionel Sambuc 		 * Print a message describing the new setting.
454f7cf2976SLionel Sambuc 		 */
455f7cf2976SLionel Sambuc 		switch (o->otype & OTYPE)
456f7cf2976SLionel Sambuc 		{
457f7cf2976SLionel Sambuc 		case BOOL:
458f7cf2976SLionel Sambuc 		case TRIPLE:
459f7cf2976SLionel Sambuc 			if (*(o->ovar) < 0)
460f7cf2976SLionel Sambuc 				error("Negative option is invalid", NULL_PARG);
461f7cf2976SLionel Sambuc 			/*
462f7cf2976SLionel Sambuc 			 * Print the odesc message.
463f7cf2976SLionel Sambuc 			 */
464f7cf2976SLionel Sambuc 			error(o->odesc[*(o->ovar)], NULL_PARG);
465f7cf2976SLionel Sambuc 			break;
466f7cf2976SLionel Sambuc 		case NUMBER:
467f7cf2976SLionel Sambuc 			/*
468f7cf2976SLionel Sambuc 			 * The message is in odesc[1] and has a %d for
469f7cf2976SLionel Sambuc 			 * the value of the variable.
470f7cf2976SLionel Sambuc 			 */
471f7cf2976SLionel Sambuc 			parg.p_int = *(o->ovar);
472f7cf2976SLionel Sambuc 			error(o->odesc[1], &parg);
473f7cf2976SLionel Sambuc 			break;
474f7cf2976SLionel Sambuc 		case STRING:
475f7cf2976SLionel Sambuc 			/*
476f7cf2976SLionel Sambuc 			 * Message was already printed by the handling function.
477f7cf2976SLionel Sambuc 			 */
478f7cf2976SLionel Sambuc 			break;
479f7cf2976SLionel Sambuc 		}
480f7cf2976SLionel Sambuc 	}
481f7cf2976SLionel Sambuc 
482f7cf2976SLionel Sambuc 	if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT))
483f7cf2976SLionel Sambuc 		screen_trashed = TRUE;
484f7cf2976SLionel Sambuc }
485f7cf2976SLionel Sambuc 
486f7cf2976SLionel Sambuc /*
487f7cf2976SLionel Sambuc  * "Toggle" a triple-valued option.
488f7cf2976SLionel Sambuc  */
489f7cf2976SLionel Sambuc 	static int
flip_triple(val,lc)490f7cf2976SLionel Sambuc flip_triple(val, lc)
491f7cf2976SLionel Sambuc 	int val;
492f7cf2976SLionel Sambuc 	int lc;
493f7cf2976SLionel Sambuc {
494f7cf2976SLionel Sambuc 	if (lc)
495f7cf2976SLionel Sambuc 		return ((val == OPT_ON) ? OPT_OFF : OPT_ON);
496f7cf2976SLionel Sambuc 	else
497f7cf2976SLionel Sambuc 		return ((val == OPT_ONPLUS) ? OPT_OFF : OPT_ONPLUS);
498f7cf2976SLionel Sambuc }
499f7cf2976SLionel Sambuc 
500f7cf2976SLionel Sambuc /*
501f7cf2976SLionel Sambuc  * Determine if an option takes a parameter.
502f7cf2976SLionel Sambuc  */
503f7cf2976SLionel Sambuc 	public int
opt_has_param(o)504f7cf2976SLionel Sambuc opt_has_param(o)
505f7cf2976SLionel Sambuc 	struct loption *o;
506f7cf2976SLionel Sambuc {
507f7cf2976SLionel Sambuc 	if (o == NULL)
508f7cf2976SLionel Sambuc 		return (0);
509f7cf2976SLionel Sambuc 	if (o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE))
510f7cf2976SLionel Sambuc 		return (0);
511f7cf2976SLionel Sambuc 	return (1);
512f7cf2976SLionel Sambuc }
513f7cf2976SLionel Sambuc 
514f7cf2976SLionel Sambuc /*
515f7cf2976SLionel Sambuc  * Return the prompt to be used for a given option letter.
516f7cf2976SLionel Sambuc  * Only string and number valued options have prompts.
517f7cf2976SLionel Sambuc  */
518f7cf2976SLionel Sambuc 	public char *
opt_prompt(o)519f7cf2976SLionel Sambuc opt_prompt(o)
520f7cf2976SLionel Sambuc 	struct loption *o;
521f7cf2976SLionel Sambuc {
522f7cf2976SLionel Sambuc 	if (o == NULL || (o->otype & (STRING|NUMBER)) == 0)
523f7cf2976SLionel Sambuc 		return ("?");
524f7cf2976SLionel Sambuc 	return (o->odesc[0]);
525f7cf2976SLionel Sambuc }
526f7cf2976SLionel Sambuc 
527f7cf2976SLionel Sambuc /*
528f7cf2976SLionel Sambuc  * Return whether or not there is a string option pending;
529f7cf2976SLionel Sambuc  * that is, if the previous option was a string-valued option letter
530f7cf2976SLionel Sambuc  * (like -P) without a following string.
531f7cf2976SLionel Sambuc  * In that case, the current option is taken to be the string for
532f7cf2976SLionel Sambuc  * the previous option.
533f7cf2976SLionel Sambuc  */
534f7cf2976SLionel Sambuc 	public int
isoptpending()535f7cf2976SLionel Sambuc isoptpending()
536f7cf2976SLionel Sambuc {
537f7cf2976SLionel Sambuc 	return (pendopt != NULL);
538f7cf2976SLionel Sambuc }
539f7cf2976SLionel Sambuc 
540f7cf2976SLionel Sambuc /*
541f7cf2976SLionel Sambuc  * Print error message about missing string.
542f7cf2976SLionel Sambuc  */
543f7cf2976SLionel Sambuc 	static void
nostring(printopt)544f7cf2976SLionel Sambuc nostring(printopt)
545f7cf2976SLionel Sambuc 	char *printopt;
546f7cf2976SLionel Sambuc {
547f7cf2976SLionel Sambuc 	PARG parg;
548f7cf2976SLionel Sambuc 	parg.p_string = printopt;
549f7cf2976SLionel Sambuc 	error("Value is required after %s", &parg);
550f7cf2976SLionel Sambuc }
551f7cf2976SLionel Sambuc 
552f7cf2976SLionel Sambuc /*
553f7cf2976SLionel Sambuc  * Print error message if a STRING type option is not followed by a string.
554f7cf2976SLionel Sambuc  */
555f7cf2976SLionel Sambuc 	public void
nopendopt()556f7cf2976SLionel Sambuc nopendopt()
557f7cf2976SLionel Sambuc {
558f7cf2976SLionel Sambuc 	nostring(opt_desc(pendopt));
559f7cf2976SLionel Sambuc }
560f7cf2976SLionel Sambuc 
561f7cf2976SLionel Sambuc /*
562f7cf2976SLionel Sambuc  * Scan to end of string or to an END_OPTION_STRING character.
563f7cf2976SLionel Sambuc  * In the latter case, replace the char with a null char.
564f7cf2976SLionel Sambuc  * Return a pointer to the remainder of the string, if any.
565f7cf2976SLionel Sambuc  */
566f7cf2976SLionel Sambuc 	static char *
optstring(s,p_str,printopt,validchars)567f7cf2976SLionel Sambuc optstring(s, p_str, printopt, validchars)
568f7cf2976SLionel Sambuc 	char *s;
569f7cf2976SLionel Sambuc 	char **p_str;
570f7cf2976SLionel Sambuc 	char *printopt;
571f7cf2976SLionel Sambuc 	char *validchars;
572f7cf2976SLionel Sambuc {
573f7cf2976SLionel Sambuc 	register char *p;
574*84d9c625SLionel Sambuc 	register char *out;
575f7cf2976SLionel Sambuc 
576f7cf2976SLionel Sambuc 	if (*s == '\0')
577f7cf2976SLionel Sambuc 	{
578f7cf2976SLionel Sambuc 		nostring(printopt);
579*84d9c625SLionel Sambuc 		return (NULL);
580f7cf2976SLionel Sambuc 	}
581*84d9c625SLionel Sambuc 	/* Alloc could be more than needed, but not worth trimming. */
582*84d9c625SLionel Sambuc 	*p_str = (char *) ecalloc(strlen(s)+1, sizeof(char));
583*84d9c625SLionel Sambuc 	out = *p_str;
584*84d9c625SLionel Sambuc 
585f7cf2976SLionel Sambuc 	for (p = s;  *p != '\0';  p++)
586f7cf2976SLionel Sambuc 	{
587*84d9c625SLionel Sambuc 		if (opt_use_backslash && *p == '\\' && p[1] != '\0')
588*84d9c625SLionel Sambuc 		{
589*84d9c625SLionel Sambuc 			/* Take next char literally. */
590*84d9c625SLionel Sambuc 			++p;
591*84d9c625SLionel Sambuc 		} else
592*84d9c625SLionel Sambuc 		{
593f7cf2976SLionel Sambuc 			if (*p == END_OPTION_STRING ||
594f7cf2976SLionel Sambuc 			    (validchars != NULL && strchr(validchars, *p) == NULL))
595*84d9c625SLionel Sambuc 				/* End of option string. */
596f7cf2976SLionel Sambuc 				break;
597f7cf2976SLionel Sambuc 		}
598*84d9c625SLionel Sambuc 		*out++ = *p;
599f7cf2976SLionel Sambuc 	}
600*84d9c625SLionel Sambuc 	*out = '\0';
601f7cf2976SLionel Sambuc 	return (p);
602f7cf2976SLionel Sambuc }
603f7cf2976SLionel Sambuc 
604f7cf2976SLionel Sambuc /*
605f7cf2976SLionel Sambuc  */
606f7cf2976SLionel Sambuc 	static int
num_error(printopt,errp)607f7cf2976SLionel Sambuc num_error(printopt, errp)
608f7cf2976SLionel Sambuc 	char *printopt;
609f7cf2976SLionel Sambuc 	int *errp;
610f7cf2976SLionel Sambuc {
611f7cf2976SLionel Sambuc 	PARG parg;
612f7cf2976SLionel Sambuc 
613f7cf2976SLionel Sambuc 	if (errp != NULL)
614f7cf2976SLionel Sambuc 	{
615f7cf2976SLionel Sambuc 		*errp = TRUE;
616f7cf2976SLionel Sambuc 		return (-1);
617f7cf2976SLionel Sambuc 	}
618f7cf2976SLionel Sambuc 	if (printopt != NULL)
619f7cf2976SLionel Sambuc 	{
620f7cf2976SLionel Sambuc 		parg.p_string = printopt;
621f7cf2976SLionel Sambuc 		error("Number is required after %s", &parg);
622f7cf2976SLionel Sambuc 	}
623f7cf2976SLionel Sambuc 	return (-1);
624f7cf2976SLionel Sambuc }
625f7cf2976SLionel Sambuc 
626f7cf2976SLionel Sambuc /*
627f7cf2976SLionel Sambuc  * Translate a string into a number.
628f7cf2976SLionel Sambuc  * Like atoi(), but takes a pointer to a char *, and updates
629f7cf2976SLionel Sambuc  * the char * to point after the translated number.
630f7cf2976SLionel Sambuc  */
631f7cf2976SLionel Sambuc 	public int
getnum(sp,printopt,errp)632f7cf2976SLionel Sambuc getnum(sp, printopt, errp)
633f7cf2976SLionel Sambuc 	char **sp;
634f7cf2976SLionel Sambuc 	char *printopt;
635f7cf2976SLionel Sambuc 	int *errp;
636f7cf2976SLionel Sambuc {
637f7cf2976SLionel Sambuc 	register char *s;
638f7cf2976SLionel Sambuc 	register int n;
639f7cf2976SLionel Sambuc 	register int neg;
640f7cf2976SLionel Sambuc 
641f7cf2976SLionel Sambuc 	s = skipsp(*sp);
642f7cf2976SLionel Sambuc 	neg = FALSE;
643f7cf2976SLionel Sambuc 	if (*s == '-')
644f7cf2976SLionel Sambuc 	{
645f7cf2976SLionel Sambuc 		neg = TRUE;
646f7cf2976SLionel Sambuc 		s++;
647f7cf2976SLionel Sambuc 	}
648f7cf2976SLionel Sambuc 	if (*s < '0' || *s > '9')
649f7cf2976SLionel Sambuc 		return (num_error(printopt, errp));
650f7cf2976SLionel Sambuc 
651f7cf2976SLionel Sambuc 	n = 0;
652f7cf2976SLionel Sambuc 	while (*s >= '0' && *s <= '9')
653f7cf2976SLionel Sambuc 		n = 10 * n + *s++ - '0';
654f7cf2976SLionel Sambuc 	*sp = s;
655f7cf2976SLionel Sambuc 	if (errp != NULL)
656f7cf2976SLionel Sambuc 		*errp = FALSE;
657f7cf2976SLionel Sambuc 	if (neg)
658f7cf2976SLionel Sambuc 		n = -n;
659f7cf2976SLionel Sambuc 	return (n);
660f7cf2976SLionel Sambuc }
661f7cf2976SLionel Sambuc 
662f7cf2976SLionel Sambuc /*
663f7cf2976SLionel Sambuc  * Translate a string into a fraction, represented by the part of a
664f7cf2976SLionel Sambuc  * number which would follow a decimal point.
665f7cf2976SLionel Sambuc  * The value of the fraction is returned as parts per NUM_FRAC_DENOM.
666f7cf2976SLionel Sambuc  * That is, if "n" is returned, the fraction intended is n/NUM_FRAC_DENOM.
667f7cf2976SLionel Sambuc  */
668f7cf2976SLionel Sambuc 	public long
getfraction(sp,printopt,errp)669f7cf2976SLionel Sambuc getfraction(sp, printopt, errp)
670f7cf2976SLionel Sambuc 	char **sp;
671f7cf2976SLionel Sambuc 	char *printopt;
672f7cf2976SLionel Sambuc 	int *errp;
673f7cf2976SLionel Sambuc {
674f7cf2976SLionel Sambuc 	register char *s;
675f7cf2976SLionel Sambuc 	long frac = 0;
676f7cf2976SLionel Sambuc 	int fraclen = 0;
677f7cf2976SLionel Sambuc 
678f7cf2976SLionel Sambuc 	s = skipsp(*sp);
679f7cf2976SLionel Sambuc 	if (*s < '0' || *s > '9')
680f7cf2976SLionel Sambuc 		return (num_error(printopt, errp));
681f7cf2976SLionel Sambuc 
682f7cf2976SLionel Sambuc 	for ( ;  *s >= '0' && *s <= '9';  s++)
683f7cf2976SLionel Sambuc 	{
684f7cf2976SLionel Sambuc 		frac = (frac * 10) + (*s - '0');
685f7cf2976SLionel Sambuc 		fraclen++;
686f7cf2976SLionel Sambuc 	}
687f7cf2976SLionel Sambuc 	if (fraclen > NUM_LOG_FRAC_DENOM)
688f7cf2976SLionel Sambuc 		while (fraclen-- > NUM_LOG_FRAC_DENOM)
689f7cf2976SLionel Sambuc 			frac /= 10;
690f7cf2976SLionel Sambuc 	else
691f7cf2976SLionel Sambuc 		while (fraclen++ < NUM_LOG_FRAC_DENOM)
692f7cf2976SLionel Sambuc 			frac *= 10;
693f7cf2976SLionel Sambuc 	*sp = s;
694f7cf2976SLionel Sambuc 	if (errp != NULL)
695f7cf2976SLionel Sambuc 		*errp = FALSE;
696f7cf2976SLionel Sambuc 	return (frac);
697f7cf2976SLionel Sambuc }
698f7cf2976SLionel Sambuc 
699f7cf2976SLionel Sambuc 
700f7cf2976SLionel Sambuc /*
701f7cf2976SLionel Sambuc  * Get the value of the -e flag.
702f7cf2976SLionel Sambuc  */
703f7cf2976SLionel Sambuc 	public int
get_quit_at_eof()704f7cf2976SLionel Sambuc get_quit_at_eof()
705f7cf2976SLionel Sambuc {
706f7cf2976SLionel Sambuc 	if (!less_is_more)
707f7cf2976SLionel Sambuc 		return quit_at_eof;
708f7cf2976SLionel Sambuc 	/* When less_is_more is set, the -e flag semantics are different. */
709f7cf2976SLionel Sambuc 	return quit_at_eof ? OPT_ON : OPT_ONPLUS;
710f7cf2976SLionel Sambuc }
711