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