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