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