option.c revision 294286
155682Smarkm/*
278527Sassar * Copyright (C) 1984-2015  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, see the README file.
855682Smarkm */
955682Smarkm
1055682Smarkm
1155682Smarkm/*
1255682Smarkm * Process command line options.
1355682Smarkm *
1455682Smarkm * Each option is a single letter which controls a program variable.
1555682Smarkm * The options have defaults which may be changed via
1655682Smarkm * the command line option, toggled via the "-" command,
1755682Smarkm * or queried via the "_" command.
1855682Smarkm */
1955682Smarkm
2055682Smarkm#include "less.h"
2155682Smarkm#include "option.h"
2255682Smarkm
2355682Smarkmstatic struct loption *pendopt;
2455682Smarkmpublic int plusoption = FALSE;
2555682Smarkm
2655682Smarkmstatic char *optstring();
2755682Smarkmstatic int flip_triple();
2855682Smarkm
2955682Smarkmextern int screen_trashed;
3055682Smarkmextern int less_is_more;
3155682Smarkmextern int quit_at_eof;
3255682Smarkmextern char *every_first_cmd;
3355682Smarkmextern int opt_use_backslash;
3455682Smarkm
3555682Smarkm/*
36178825Sdfr * Return a printable description of an option.
3755682Smarkm */
3855682Smarkm	static char *
3955682Smarkmopt_desc(o)
4055682Smarkm	struct loption *o;
4155682Smarkm{
4255682Smarkm	static char buf[OPTNAME_MAX + 10];
4355682Smarkm	if (o->oletter == OLETTER_NONE)
4478527Sassar		SNPRINTF1(buf, sizeof(buf), "--%s", o->onames->oname);
4578527Sassar	else
4655682Smarkm		SNPRINTF2(buf, sizeof(buf), "-%c (--%s)", o->oletter, o->onames->oname);
4778527Sassar	return (buf);
4857416Smarkm}
4955682Smarkm
5055682Smarkm/*
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 */
5455682Smarkm	public char *
5555682Smarkmpropt(c)
5655682Smarkm	int c;
57178825Sdfr{
5855682Smarkm	static char buf[8];
5955682Smarkm
6055682Smarkm	sprintf(buf, "-%s", prchar(c));
6155682Smarkm	return (buf);
6255682Smarkm}
6355682Smarkm
6455682Smarkm/*
65178825Sdfr * Scan an argument (either from the command line or from the
66178825Sdfr * LESS environment variable) and process it.
67178825Sdfr */
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;
7655682Smarkm	char *str;
7755682Smarkm	int set_default;
7878527Sassar	int lc;
7978527Sassar	int err;
8055682Smarkm	PARG parg;
8178527Sassar
8255682Smarkm	if (s == NULL)
8378527Sassar		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"
8957416Smarkm	 * without a following string.  In that case, the current
9057416Smarkm	 * option is simply the argument for the previous option.
9157422Smarkm	 */
9257422Smarkm	if (pendopt != NULL)
9357422Smarkm	{
9457422Smarkm		switch (pendopt->otype & OTYPE)
9557422Smarkm		{
9657422Smarkm		case STRING:
9757422Smarkm			(*pendopt->ofunc)(INIT, s);
9857422Smarkm			break;
9957422Smarkm		case NUMBER:
10057422Smarkm			printopt = opt_desc(pendopt);
10157422Smarkm			*(pendopt->ovar) = getnum(&s, printopt, (int*)NULL);
10257422Smarkm			break;
10357422Smarkm		}
10457422Smarkm		pendopt = NULL;
10557422Smarkm		return;
10657422Smarkm	}
10757422Smarkm
10857422Smarkm	set_default = FALSE;
10957422Smarkm	optname = NULL;
11057422Smarkm
11157422Smarkm	while (*s != '\0')
11257422Smarkm	{
11357422Smarkm		/*
11457422Smarkm		 * Check some special cases first.
11557422Smarkm		 */
11657416Smarkm		switch (optc = *s++)
11757416Smarkm		{
11857416Smarkm		case ' ':
11957416Smarkm		case '\t':
120178825Sdfr		case END_OPTION_STRING:
12157416Smarkm			continue;
12257416Smarkm		case '-':
12357416Smarkm			/*
12457416Smarkm			 * "--" indicates an option name instead of a letter.
12557416Smarkm			 */
12657416Smarkm			if (*s == '-')
12757416Smarkm			{
12857416Smarkm				optname = ++s;
12957416Smarkm				break;
130178825Sdfr			}
131178825Sdfr			/*
132178825Sdfr			 * "-+" means set these options back to their defaults.
133178825Sdfr			 * (They may have been set otherwise by previous
13457416Smarkm			 * options.)
13557416Smarkm			 */
13657416Smarkm			set_default = (*s == '+');
13757416Smarkm			if (set_default)
13857416Smarkm				s++;
13957422Smarkm			continue;
14057422Smarkm		case '+':
14157422Smarkm			/*
14257416Smarkm			 * An option prefixed by a "+" is ungotten, so
14357416Smarkm			 * that it is interpreted as less commands
14472445Sassar			 * processed at the start of the first input file.
14557422Smarkm			 * "++" means process the commands at the start of
14657422Smarkm			 * EVERY input file.
14757422Smarkm			 */
14857422Smarkm			plusoption = TRUE;
14957416Smarkm			s = optstring(s, &str, propt('+'), NULL);
15057416Smarkm			if (s == NULL)
15157422Smarkm				return;
15257422Smarkm			if (*str == '+')
15357422Smarkm				every_first_cmd = save(str+1);
15457422Smarkm			else
15557416Smarkm			{
15657416Smarkm				ungetcc(CHAR_END_COMMAND);
15757416Smarkm				ungetsc(str);
15890926Snectar			}
15957422Smarkm			free(str);
16057416Smarkm			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