option.c revision 221715
155682Smarkm/*
272445Sassar * Copyright (C) 1984-2011  Mark Nudelman
355682Smarkm *
455682Smarkm * You may distribute under the terms of either the GNU General Public
555682Smarkm * License or the Less License, as specified in the README file.
655682Smarkm *
755682Smarkm * For more information about less, or for information on how to
855682Smarkm * contact the author, see the README file.
955682Smarkm */
1055682Smarkm
1155682Smarkm
1255682Smarkm/*
1355682Smarkm * Process command line options.
1455682Smarkm *
1555682Smarkm * Each option is a single letter which controls a program variable.
1655682Smarkm * The options have defaults which may be changed via
1755682Smarkm * the command line option, toggled via the "-" command,
1855682Smarkm * or queried via the "_" command.
1955682Smarkm */
2055682Smarkm
2155682Smarkm#include "less.h"
2255682Smarkm#include "option.h"
2355682Smarkm
2455682Smarkmstatic struct loption *pendopt;
2555682Smarkmpublic int plusoption = FALSE;
2655682Smarkm
2755682Smarkmstatic char *optstring();
2855682Smarkmstatic int flip_triple();
2955682Smarkm
3055682Smarkmextern int screen_trashed;
3155682Smarkmextern int less_is_more;
3255682Smarkmextern int quit_at_eof;
3355682Smarkmextern char *every_first_cmd;
34178825Sdfr
3555682Smarkm/*
36102644Snectar * Return a printable description of an option.
37102644Snectar */
3855682Smarkm	static char *
3955682Smarkmopt_desc(o)
40178825Sdfr	struct loption *o;
4155682Smarkm{
42178825Sdfr	static char buf[OPTNAME_MAX + 10];
4355682Smarkm	if (o->oletter == OLETTER_NONE)
4455682Smarkm		SNPRINTF1(buf, sizeof(buf), "--%s", o->onames->oname);
4555682Smarkm	else
4655682Smarkm		SNPRINTF2(buf, sizeof(buf), "-%c (--%s)", o->oletter, o->onames->oname);
47178825Sdfr	return (buf);
4855682Smarkm}
49178825Sdfr
50178825Sdfr/*
5155682Smarkm * Return a string suitable for printing as the "name" of an option.
5255682Smarkm * For example, if the option letter is 'x', just return "-x".
5355682Smarkm */
5472445Sassar	public char *
5572445Sassarpropt(c)
5655682Smarkm	int c;
5755682Smarkm{
5855682Smarkm	static char buf[8];
5955682Smarkm
6055682Smarkm	sprintf(buf, "-%s", prchar(c));
6155682Smarkm	return (buf);
6255682Smarkm}
6355682Smarkm
6455682Smarkm/*
6555682Smarkm * Scan an argument (either from the command line or from the
6655682Smarkm * LESS environment variable) and process it.
6755682Smarkm */
6855682Smarkm	public void
6955682Smarkmscan_option(s)
7055682Smarkm	char *s;
7155682Smarkm{
7255682Smarkm	register struct loption *o;
7355682Smarkm	register int optc;
7455682Smarkm	char *optname;
7555682Smarkm	char *printopt;
76178825Sdfr	char *str;
7755682Smarkm	int set_default;
7855682Smarkm	int lc;
7955682Smarkm	int err;
8055682Smarkm	PARG parg;
8155682Smarkm
8255682Smarkm	if (s == NULL)
8355682Smarkm		return;
8455682Smarkm
8555682Smarkm	/*
8655682Smarkm	 * If we have a pending option which requires an argument,
8755682Smarkm	 * handle it now.
8855682Smarkm	 * This happens if the previous option was, for example, "-P"
8955682Smarkm	 * without a following string.  In that case, the current
9055682Smarkm	 * option is simply the argument for the previous option.
9172445Sassar	 */
9255682Smarkm	if (pendopt != NULL)
9355682Smarkm	{
9455682Smarkm		switch (pendopt->otype & OTYPE)
9555682Smarkm		{
9655682Smarkm		case STRING:
9755682Smarkm			(*pendopt->ofunc)(INIT, s);
9855682Smarkm			break;
9955682Smarkm		case NUMBER:
10055682Smarkm			printopt = opt_desc(pendopt);
10155682Smarkm			*(pendopt->ovar) = getnum(&s, printopt, (int*)NULL);
10255682Smarkm			break;
10372445Sassar		}
10472445Sassar		pendopt = NULL;
10572445Sassar		return;
10672445Sassar	}
10772445Sassar
10872445Sassar	set_default = FALSE;
10955682Smarkm	optname = NULL;
11055682Smarkm
111178825Sdfr	while (*s != '\0')
112178825Sdfr	{
113178825Sdfr		/*
114178825Sdfr		 * Check some special cases first.
115178825Sdfr		 */
116178825Sdfr		switch (optc = *s++)
117178825Sdfr		{
118178825Sdfr		case ' ':
119178825Sdfr		case '\t':
120178825Sdfr		case END_OPTION_STRING:
121178825Sdfr			continue;
122178825Sdfr		case '-':
123178825Sdfr			/*
124178825Sdfr			 * "--" indicates an option name instead of a letter.
12555682Smarkm			 */
12655682Smarkm			if (*s == '-')
12755682Smarkm			{
12855682Smarkm				optname = ++s;
12955682Smarkm				break;
13055682Smarkm			}
13155682Smarkm			/*
13255682Smarkm			 * "-+" means set these options back to their defaults.
13355682Smarkm			 * (They may have been set otherwise by previous
13472445Sassar			 * options.)
13572445Sassar			 */
13672445Sassar			set_default = (*s == '+');
13755682Smarkm			if (set_default)
13855682Smarkm				s++;
13955682Smarkm			continue;
14055682Smarkm		case '+':
14155682Smarkm			/*
14272445Sassar			 * An option prefixed by a "+" is ungotten, so
14355682Smarkm			 * that it is interpreted as less commands
144102644Snectar			 * 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 (*str == '+')
151				every_first_cmd = save(++str);
152			else
153				ungetsc(str);
154			continue;
155		case '0':  case '1':  case '2':  case '3':  case '4':
156		case '5':  case '6':  case '7':  case '8':  case '9':
157			/*
158			 * Special "more" compatibility form "-<number>"
159			 * instead of -z<number> to set the scrolling
160			 * window size.
161			 */
162			s--;
163			optc = 'z';
164			break;
165		case 'n':
166			if (less_is_more)
167				optc = 'z';
168			break;
169		}
170
171		/*
172		 * Not a special case.
173		 * Look up the option letter in the option table.
174		 */
175		err = 0;
176		if (optname == NULL)
177		{
178			printopt = propt(optc);
179			lc = ASCII_IS_LOWER(optc);
180			o = findopt(optc);
181		} else
182		{
183			printopt = optname;
184			lc = ASCII_IS_LOWER(optname[0]);
185			o = findopt_name(&optname, NULL, &err);
186			s = optname;
187			optname = NULL;
188			if (*s == '\0' || *s == ' ')
189			{
190				/*
191				 * The option name matches exactly.
192				 */
193				;
194			} else if (*s == '=')
195			{
196				/*
197				 * The option name is followed by "=value".
198				 */
199				if (o != NULL &&
200				    (o->otype & OTYPE) != STRING &&
201				    (o->otype & OTYPE) != NUMBER)
202				{
203					parg.p_string = printopt;
204					error("The %s option should not be followed by =",
205						&parg);
206					quit(QUIT_ERROR);
207				}
208				s++;
209			} else
210			{
211				/*
212				 * The specified name is longer than the
213				 * real option name.
214				 */
215				o = NULL;
216			}
217		}
218		if (o == NULL)
219		{
220			parg.p_string = printopt;
221			if (err == OPT_AMBIG)
222				error("%s is an ambiguous abbreviation (\"less --help\" for help)",
223					&parg);
224			else
225				error("There is no %s option (\"less --help\" for help)",
226					&parg);
227			quit(QUIT_ERROR);
228		}
229
230		str = NULL;
231		switch (o->otype & OTYPE)
232		{
233		case BOOL:
234			if (set_default)
235				*(o->ovar) = o->odefault;
236			else
237				*(o->ovar) = ! o->odefault;
238			break;
239		case TRIPLE:
240			if (set_default)
241				*(o->ovar) = o->odefault;
242			else
243				*(o->ovar) = flip_triple(o->odefault, lc);
244			break;
245		case STRING:
246			if (*s == '\0')
247			{
248				/*
249				 * Set pendopt and return.
250				 * We will get the string next time
251				 * scan_option is called.
252				 */
253				pendopt = o;
254				return;
255			}
256			/*
257			 * Don't do anything here.
258			 * All processing of STRING options is done by
259			 * the handling function.
260			 */
261			while (*s == ' ')
262				s++;
263			s = optstring(s, &str, printopt, o->odesc[1]);
264			break;
265		case NUMBER:
266			if (*s == '\0')
267			{
268				pendopt = o;
269				return;
270			}
271			*(o->ovar) = getnum(&s, printopt, (int*)NULL);
272			break;
273		}
274		/*
275		 * If the option has a handling function, call it.
276		 */
277		if (o->ofunc != NULL)
278			(*o->ofunc)(INIT, str);
279	}
280}
281
282/*
283 * Toggle command line flags from within the program.
284 * Used by the "-" and "_" commands.
285 * how_toggle may be:
286 *	OPT_NO_TOGGLE	just report the current setting, without changing it.
287 *	OPT_TOGGLE	invert the current setting
288 *	OPT_UNSET	set to the default value
289 *	OPT_SET		set to the inverse of the default value
290 */
291	public void
292toggle_option(o, lower, s, how_toggle)
293	struct loption *o;
294	int lower;
295	char *s;
296	int how_toggle;
297{
298	register int num;
299	int no_prompt;
300	int err;
301	PARG parg;
302
303	no_prompt = (how_toggle & OPT_NO_PROMPT);
304	how_toggle &= ~OPT_NO_PROMPT;
305
306	if (o == NULL)
307	{
308		error("No such option", NULL_PARG);
309		return;
310	}
311
312	if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE))
313	{
314		parg.p_string = opt_desc(o);
315		error("Cannot change the %s option", &parg);
316		return;
317	}
318
319	if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY))
320	{
321		parg.p_string = opt_desc(o);
322		error("Cannot query the %s option", &parg);
323		return;
324	}
325
326	/*
327	 * Check for something which appears to be a do_toggle
328	 * (because the "-" command was used), but really is not.
329	 * This could be a string option with no string, or
330	 * a number option with no number.
331	 */
332	switch (o->otype & OTYPE)
333	{
334	case STRING:
335	case NUMBER:
336		if (how_toggle == OPT_TOGGLE && *s == '\0')
337			how_toggle = OPT_NO_TOGGLE;
338		break;
339	}
340
341#if HILITE_SEARCH
342	if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
343		repaint_hilite(0);
344#endif
345
346	/*
347	 * Now actually toggle (change) the variable.
348	 */
349	if (how_toggle != OPT_NO_TOGGLE)
350	{
351		switch (o->otype & OTYPE)
352		{
353		case BOOL:
354			/*
355			 * Boolean.
356			 */
357			switch (how_toggle)
358			{
359			case OPT_TOGGLE:
360				*(o->ovar) = ! *(o->ovar);
361				break;
362			case OPT_UNSET:
363				*(o->ovar) = o->odefault;
364				break;
365			case OPT_SET:
366				*(o->ovar) = ! o->odefault;
367				break;
368			}
369			break;
370		case TRIPLE:
371			/*
372			 * Triple:
373			 *	If user gave the lower case letter, then switch
374			 *	to 1 unless already 1, in which case make it 0.
375			 *	If user gave the upper case letter, then switch
376			 *	to 2 unless already 2, in which case make it 0.
377			 */
378			switch (how_toggle)
379			{
380			case OPT_TOGGLE:
381				*(o->ovar) = flip_triple(*(o->ovar), lower);
382				break;
383			case OPT_UNSET:
384				*(o->ovar) = o->odefault;
385				break;
386			case OPT_SET:
387				*(o->ovar) = flip_triple(o->odefault, lower);
388				break;
389			}
390			break;
391		case STRING:
392			/*
393			 * String: don't do anything here.
394			 *	The handling function will do everything.
395			 */
396			switch (how_toggle)
397			{
398			case OPT_SET:
399			case OPT_UNSET:
400				error("Cannot use \"-+\" or \"--\" for a string option",
401					NULL_PARG);
402				return;
403			}
404			break;
405		case NUMBER:
406			/*
407			 * Number: set the variable to the given number.
408			 */
409			switch (how_toggle)
410			{
411			case OPT_TOGGLE:
412				num = getnum(&s, NULL, &err);
413				if (!err)
414					*(o->ovar) = num;
415				break;
416			case OPT_UNSET:
417				*(o->ovar) = o->odefault;
418				break;
419			case OPT_SET:
420				error("Can't use \"-!\" for a numeric option",
421					NULL_PARG);
422				return;
423			}
424			break;
425		}
426	}
427
428	/*
429	 * Call the handling function for any special action
430	 * specific to this option.
431	 */
432	if (o->ofunc != NULL)
433		(*o->ofunc)((how_toggle==OPT_NO_TOGGLE) ? QUERY : TOGGLE, s);
434
435#if HILITE_SEARCH
436	if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
437		chg_hilite();
438#endif
439
440	if (!no_prompt)
441	{
442		/*
443		 * Print a message describing the new setting.
444		 */
445		switch (o->otype & OTYPE)
446		{
447		case BOOL:
448		case TRIPLE:
449			/*
450			 * Print the odesc message.
451			 */
452			error(o->odesc[*(o->ovar)], NULL_PARG);
453			break;
454		case NUMBER:
455			/*
456			 * The message is in odesc[1] and has a %d for
457			 * the value of the variable.
458			 */
459			parg.p_int = *(o->ovar);
460			error(o->odesc[1], &parg);
461			break;
462		case STRING:
463			/*
464			 * Message was already printed by the handling function.
465			 */
466			break;
467		}
468	}
469
470	if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT))
471		screen_trashed = TRUE;
472}
473
474/*
475 * "Toggle" a triple-valued option.
476 */
477	static int
478flip_triple(val, lc)
479	int val;
480	int lc;
481{
482	if (lc)
483		return ((val == OPT_ON) ? OPT_OFF : OPT_ON);
484	else
485		return ((val == OPT_ONPLUS) ? OPT_OFF : OPT_ONPLUS);
486}
487
488/*
489 * Determine if an option takes a parameter.
490 */
491	public int
492opt_has_param(o)
493	struct loption *o;
494{
495	if (o == NULL)
496		return (0);
497	if (o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE))
498		return (0);
499	return (1);
500}
501
502/*
503 * Return the prompt to be used for a given option letter.
504 * Only string and number valued options have prompts.
505 */
506	public char *
507opt_prompt(o)
508	struct loption *o;
509{
510	if (o == NULL || (o->otype & (STRING|NUMBER)) == 0)
511		return ("?");
512	return (o->odesc[0]);
513}
514
515/*
516 * Return whether or not there is a string option pending;
517 * that is, if the previous option was a string-valued option letter
518 * (like -P) without a following string.
519 * In that case, the current option is taken to be the string for
520 * the previous option.
521 */
522	public int
523isoptpending()
524{
525	return (pendopt != NULL);
526}
527
528/*
529 * Print error message about missing string.
530 */
531	static void
532nostring(printopt)
533	char *printopt;
534{
535	PARG parg;
536	parg.p_string = printopt;
537	error("Value is required after %s", &parg);
538}
539
540/*
541 * Print error message if a STRING type option is not followed by a string.
542 */
543	public void
544nopendopt()
545{
546	nostring(opt_desc(pendopt));
547}
548
549/*
550 * Scan to end of string or to an END_OPTION_STRING character.
551 * In the latter case, replace the char with a null char.
552 * Return a pointer to the remainder of the string, if any.
553 */
554	static char *
555optstring(s, p_str, printopt, validchars)
556	char *s;
557	char **p_str;
558	char *printopt;
559	char *validchars;
560{
561	register char *p;
562
563	if (*s == '\0')
564	{
565		nostring(printopt);
566		quit(QUIT_ERROR);
567	}
568	*p_str = s;
569	for (p = s;  *p != '\0';  p++)
570	{
571		if (*p == END_OPTION_STRING ||
572		    (validchars != NULL && strchr(validchars, *p) == NULL))
573		{
574			switch (*p)
575			{
576			case END_OPTION_STRING:
577			case ' ':  case '\t':  case '-':
578				/* Replace the char with a null to terminate string. */
579				*p++ = '\0';
580				break;
581			default:
582				/* Cannot replace char; make a copy of the string. */
583				*p_str = (char *) ecalloc(p-s+1, sizeof(char));
584				strncpy(*p_str, s, p-s);
585				(*p_str)[p-s] = '\0';
586				break;
587			}
588			break;
589		}
590	}
591	return (p);
592}
593
594/*
595 */
596	static int
597num_error(printopt, errp)
598	char *printopt;
599	int *errp;
600{
601	PARG parg;
602
603	if (errp != NULL)
604	{
605		*errp = TRUE;
606		return (-1);
607	}
608	if (printopt != NULL)
609	{
610		parg.p_string = printopt;
611		error("Number is required after %s", &parg);
612	}
613	quit(QUIT_ERROR);
614	/* NOTREACHED */
615	return (-1);
616}
617
618/*
619 * Translate a string into a number.
620 * Like atoi(), but takes a pointer to a char *, and updates
621 * the char * to point after the translated number.
622 */
623	public int
624getnum(sp, printopt, errp)
625	char **sp;
626	char *printopt;
627	int *errp;
628{
629	register char *s;
630	register int n;
631	register int neg;
632
633	s = skipsp(*sp);
634	neg = FALSE;
635	if (*s == '-')
636	{
637		neg = TRUE;
638		s++;
639	}
640	if (*s < '0' || *s > '9')
641		return (num_error(printopt, errp));
642
643	n = 0;
644	while (*s >= '0' && *s <= '9')
645		n = 10 * n + *s++ - '0';
646	*sp = s;
647	if (errp != NULL)
648		*errp = FALSE;
649	if (neg)
650		n = -n;
651	return (n);
652}
653
654/*
655 * Translate a string into a fraction, represented by the part of a
656 * number which would follow a decimal point.
657 * The value of the fraction is returned as parts per NUM_FRAC_DENOM.
658 * That is, if "n" is returned, the fraction intended is n/NUM_FRAC_DENOM.
659 */
660	public long
661getfraction(sp, printopt, errp)
662	char **sp;
663	char *printopt;
664	int *errp;
665{
666	register char *s;
667	long frac = 0;
668	int fraclen = 0;
669
670	s = skipsp(*sp);
671	if (*s < '0' || *s > '9')
672		return (num_error(printopt, errp));
673
674	for ( ;  *s >= '0' && *s <= '9';  s++)
675	{
676		frac = (frac * 10) + (*s - '0');
677		fraclen++;
678	}
679	if (fraclen > NUM_LOG_FRAC_DENOM)
680		while (fraclen-- > NUM_LOG_FRAC_DENOM)
681			frac /= 10;
682	else
683		while (fraclen++ < NUM_LOG_FRAC_DENOM)
684			frac *= 10;
685	*sp = s;
686	if (errp != NULL)
687		*errp = FALSE;
688	return (frac);
689}
690
691
692/*
693 * Get the value of the -e flag.
694 */
695	public int
696get_quit_at_eof()
697{
698	if (!less_is_more)
699		return quit_at_eof;
700	/* When less_is_more is set, the -e flag semantics are different. */
701	return quit_at_eof ? OPT_ON : OPT_ONPLUS;
702}
703