1238730Sdelphij/*
2330571Sdelphij * Copyright (C) 1984-2017  Mark Nudelman
3238730Sdelphij *
4238730Sdelphij * You may distribute under the terms of either the GNU General Public
5238730Sdelphij * License or the Less License, as specified in the README file.
6238730Sdelphij *
7238730Sdelphij * For more information, see the README file.
8238730Sdelphij */
960786Sps
1060786Sps
1160786Sps/*
1260786Sps * Process command line options.
1360786Sps *
1460786Sps * Each option is a single letter which controls a program variable.
1560786Sps * The options have defaults which may be changed via
1660786Sps * the command line option, toggled via the "-" command,
1760786Sps * or queried via the "_" command.
1860786Sps */
1960786Sps
2060786Sps#include "less.h"
2160786Sps#include "option.h"
2260786Sps
23128345Stjrstatic struct loption *pendopt;
2460786Spspublic int plusoption = FALSE;
2560786Sps
2660786Spsstatic char *optstring();
2760786Spsstatic int flip_triple();
2860786Sps
2960786Spsextern int screen_trashed;
30170256Sdelphijextern int less_is_more;
31170256Sdelphijextern int quit_at_eof;
3260786Spsextern char *every_first_cmd;
33250592Sdelphijextern int opt_use_backslash;
3460786Sps
35221715Sdelphij/*
36221715Sdelphij * Return a printable description of an option.
37221715Sdelphij */
38221715Sdelphij	static char *
39221715Sdelphijopt_desc(o)
40221715Sdelphij	struct loption *o;
41221715Sdelphij{
42221715Sdelphij	static char buf[OPTNAME_MAX + 10];
43221715Sdelphij	if (o->oletter == OLETTER_NONE)
44221715Sdelphij		SNPRINTF1(buf, sizeof(buf), "--%s", o->onames->oname);
45221715Sdelphij	else
46221715Sdelphij		SNPRINTF2(buf, sizeof(buf), "-%c (--%s)", o->oletter, o->onames->oname);
47221715Sdelphij	return (buf);
48221715Sdelphij}
49221715Sdelphij
50221715Sdelphij/*
51221715Sdelphij * Return a string suitable for printing as the "name" of an option.
52221715Sdelphij * For example, if the option letter is 'x', just return "-x".
53221715Sdelphij */
54221715Sdelphij	public char *
55221715Sdelphijpropt(c)
56221715Sdelphij	int c;
57221715Sdelphij{
58221715Sdelphij	static char buf[8];
59221715Sdelphij
60221715Sdelphij	sprintf(buf, "-%s", prchar(c));
61221715Sdelphij	return (buf);
62221715Sdelphij}
63221715Sdelphij
6460786Sps/*
6560786Sps * Scan an argument (either from the command line or from the
6660786Sps * LESS environment variable) and process it.
6760786Sps */
6860786Sps	public void
6960786Spsscan_option(s)
7060786Sps	char *s;
7160786Sps{
72330571Sdelphij	struct loption *o;
73330571Sdelphij	int optc;
7460786Sps	char *optname;
7560786Sps	char *printopt;
7660786Sps	char *str;
7760786Sps	int set_default;
7860786Sps	int lc;
7960786Sps	int err;
8060786Sps	PARG parg;
8160786Sps
8260786Sps	if (s == NULL)
8360786Sps		return;
8460786Sps
8560786Sps	/*
8660786Sps	 * If we have a pending option which requires an argument,
8760786Sps	 * handle it now.
8860786Sps	 * This happens if the previous option was, for example, "-P"
8960786Sps	 * without a following string.  In that case, the current
9060786Sps	 * option is simply the argument for the previous option.
9160786Sps	 */
9260786Sps	if (pendopt != NULL)
9360786Sps	{
9460786Sps		switch (pendopt->otype & OTYPE)
9560786Sps		{
9660786Sps		case STRING:
9760786Sps			(*pendopt->ofunc)(INIT, s);
9860786Sps			break;
9960786Sps		case NUMBER:
100221715Sdelphij			printopt = opt_desc(pendopt);
10160786Sps			*(pendopt->ovar) = getnum(&s, printopt, (int*)NULL);
10260786Sps			break;
10360786Sps		}
10460786Sps		pendopt = NULL;
10560786Sps		return;
10660786Sps	}
10760786Sps
10860786Sps	set_default = FALSE;
10960786Sps	optname = NULL;
11060786Sps
11160786Sps	while (*s != '\0')
11260786Sps	{
11360786Sps		/*
11460786Sps		 * Check some special cases first.
11560786Sps		 */
11660786Sps		switch (optc = *s++)
11760786Sps		{
11860786Sps		case ' ':
11960786Sps		case '\t':
12060786Sps		case END_OPTION_STRING:
12160786Sps			continue;
12260786Sps		case '-':
12360786Sps			/*
12460786Sps			 * "--" indicates an option name instead of a letter.
12560786Sps			 */
12660786Sps			if (*s == '-')
12760786Sps			{
12860786Sps				optname = ++s;
12960786Sps				break;
13060786Sps			}
13160786Sps			/*
13260786Sps			 * "-+" means set these options back to their defaults.
13360786Sps			 * (They may have been set otherwise by previous
13460786Sps			 * options.)
13560786Sps			 */
13660786Sps			set_default = (*s == '+');
13760786Sps			if (set_default)
13860786Sps				s++;
13960786Sps			continue;
14060786Sps		case '+':
14160786Sps			/*
14260786Sps			 * An option prefixed by a "+" is ungotten, so
14360786Sps			 * that it is interpreted as less commands
14460786Sps			 * processed at the start of the first input file.
14560786Sps			 * "++" means process the commands at the start of
14660786Sps			 * EVERY input file.
14760786Sps			 */
14860786Sps			plusoption = TRUE;
149128345Stjr			s = optstring(s, &str, propt('+'), NULL);
150242584Sdelphij			if (s == NULL)
151242584Sdelphij				return;
15289019Sps			if (*str == '+')
153243829Sdelphij				every_first_cmd = save(str+1);
15460786Sps			else
155294286Sdelphij			{
156294286Sdelphij				ungetcc(CHAR_END_COMMAND);
15789019Sps				ungetsc(str);
158294286Sdelphij			}
159242584Sdelphij			free(str);
16060786Sps			continue;
16160786Sps		case '0':  case '1':  case '2':  case '3':  case '4':
16260786Sps		case '5':  case '6':  case '7':  case '8':  case '9':
16360786Sps			/*
16460786Sps			 * Special "more" compatibility form "-<number>"
16560786Sps			 * instead of -z<number> to set the scrolling
16660786Sps			 * window size.
16760786Sps			 */
16860786Sps			s--;
16960786Sps			optc = 'z';
17060786Sps			break;
171170256Sdelphij		case 'n':
172170256Sdelphij			if (less_is_more)
173170256Sdelphij				optc = 'z';
174170256Sdelphij			break;
17560786Sps		}
17660786Sps
17760786Sps		/*
17860786Sps		 * Not a special case.
17960786Sps		 * Look up the option letter in the option table.
18060786Sps		 */
18160786Sps		err = 0;
18260786Sps		if (optname == NULL)
18360786Sps		{
18460786Sps			printopt = propt(optc);
185161475Sdelphij			lc = ASCII_IS_LOWER(optc);
18660786Sps			o = findopt(optc);
18760786Sps		} else
18860786Sps		{
18960786Sps			printopt = optname;
190161475Sdelphij			lc = ASCII_IS_LOWER(optname[0]);
19160786Sps			o = findopt_name(&optname, NULL, &err);
19260786Sps			s = optname;
19360786Sps			optname = NULL;
19460786Sps			if (*s == '\0' || *s == ' ')
19560786Sps			{
19660786Sps				/*
19760786Sps				 * The option name matches exactly.
19860786Sps				 */
19960786Sps				;
20060786Sps			} else if (*s == '=')
20160786Sps			{
20260786Sps				/*
20360786Sps				 * The option name is followed by "=value".
20460786Sps				 */
20560786Sps				if (o != NULL &&
20660786Sps				    (o->otype & OTYPE) != STRING &&
20760786Sps				    (o->otype & OTYPE) != NUMBER)
20860786Sps				{
20960786Sps					parg.p_string = printopt;
21060786Sps					error("The %s option should not be followed by =",
21160786Sps						&parg);
212242584Sdelphij					return;
21360786Sps				}
21460786Sps				s++;
21560786Sps			} else
21660786Sps			{
21760786Sps				/*
21860786Sps				 * The specified name is longer than the
21960786Sps				 * real option name.
22060786Sps				 */
22160786Sps				o = NULL;
22260786Sps			}
22360786Sps		}
22460786Sps		if (o == NULL)
22560786Sps		{
22660786Sps			parg.p_string = printopt;
22760786Sps			if (err == OPT_AMBIG)
22860786Sps				error("%s is an ambiguous abbreviation (\"less --help\" for help)",
22960786Sps					&parg);
23060786Sps			else
23160786Sps				error("There is no %s option (\"less --help\" for help)",
23260786Sps					&parg);
233242584Sdelphij			return;
23460786Sps		}
23560786Sps
23660786Sps		str = NULL;
23760786Sps		switch (o->otype & OTYPE)
23860786Sps		{
23960786Sps		case BOOL:
24060786Sps			if (set_default)
24160786Sps				*(o->ovar) = o->odefault;
24260786Sps			else
24360786Sps				*(o->ovar) = ! o->odefault;
24460786Sps			break;
24560786Sps		case TRIPLE:
24660786Sps			if (set_default)
24760786Sps				*(o->ovar) = o->odefault;
24860786Sps			else
24960786Sps				*(o->ovar) = flip_triple(o->odefault, lc);
25060786Sps			break;
25160786Sps		case STRING:
25260786Sps			if (*s == '\0')
25360786Sps			{
25460786Sps				/*
25560786Sps				 * Set pendopt and return.
25660786Sps				 * We will get the string next time
25760786Sps				 * scan_option is called.
25860786Sps				 */
25960786Sps				pendopt = o;
26060786Sps				return;
26160786Sps			}
26260786Sps			/*
26360786Sps			 * Don't do anything here.
26460786Sps			 * All processing of STRING options is done by
26560786Sps			 * the handling function.
26660786Sps			 */
267128345Stjr			while (*s == ' ')
268128345Stjr				s++;
269128345Stjr			s = optstring(s, &str, printopt, o->odesc[1]);
270242584Sdelphij			if (s == NULL)
271242584Sdelphij				return;
27260786Sps			break;
27360786Sps		case NUMBER:
27460786Sps			if (*s == '\0')
27560786Sps			{
27660786Sps				pendopt = o;
27760786Sps				return;
27860786Sps			}
27960786Sps			*(o->ovar) = getnum(&s, printopt, (int*)NULL);
28060786Sps			break;
28160786Sps		}
28260786Sps		/*
28360786Sps		 * If the option has a handling function, call it.
28460786Sps		 */
28560786Sps		if (o->ofunc != NULL)
28660786Sps			(*o->ofunc)(INIT, str);
287242584Sdelphij		if (str != NULL)
288242584Sdelphij			free(str);
28960786Sps	}
29060786Sps}
29160786Sps
29260786Sps/*
29360786Sps * Toggle command line flags from within the program.
29460786Sps * Used by the "-" and "_" commands.
29560786Sps * how_toggle may be:
29660786Sps *	OPT_NO_TOGGLE	just report the current setting, without changing it.
29760786Sps *	OPT_TOGGLE	invert the current setting
29860786Sps *	OPT_UNSET	set to the default value
29960786Sps *	OPT_SET		set to the inverse of the default value
30060786Sps */
30160786Sps	public void
302221715Sdelphijtoggle_option(o, lower, s, how_toggle)
303221715Sdelphij	struct loption *o;
304221715Sdelphij	int lower;
30560786Sps	char *s;
30660786Sps	int how_toggle;
30760786Sps{
308330571Sdelphij	int num;
30960786Sps	int no_prompt;
31060786Sps	int err;
31160786Sps	PARG parg;
31260786Sps
31360786Sps	no_prompt = (how_toggle & OPT_NO_PROMPT);
31460786Sps	how_toggle &= ~OPT_NO_PROMPT;
31560786Sps
31660786Sps	if (o == NULL)
31760786Sps	{
318221715Sdelphij		error("No such option", NULL_PARG);
31960786Sps		return;
32060786Sps	}
32160786Sps
32260786Sps	if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE))
32360786Sps	{
324221715Sdelphij		parg.p_string = opt_desc(o);
32560786Sps		error("Cannot change the %s option", &parg);
32660786Sps		return;
327221715Sdelphij	}
32860786Sps
32960786Sps	if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY))
33060786Sps	{
331221715Sdelphij		parg.p_string = opt_desc(o);
33260786Sps		error("Cannot query the %s option", &parg);
33360786Sps		return;
33460786Sps	}
33560786Sps
33660786Sps	/*
33760786Sps	 * Check for something which appears to be a do_toggle
33860786Sps	 * (because the "-" command was used), but really is not.
33960786Sps	 * This could be a string option with no string, or
34060786Sps	 * a number option with no number.
34160786Sps	 */
34260786Sps	switch (o->otype & OTYPE)
34360786Sps	{
34460786Sps	case STRING:
34560786Sps	case NUMBER:
34660786Sps		if (how_toggle == OPT_TOGGLE && *s == '\0')
34760786Sps			how_toggle = OPT_NO_TOGGLE;
34860786Sps		break;
34960786Sps	}
35060786Sps
35160786Sps#if HILITE_SEARCH
35260786Sps	if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
35360786Sps		repaint_hilite(0);
35460786Sps#endif
35560786Sps
35660786Sps	/*
35760786Sps	 * Now actually toggle (change) the variable.
35860786Sps	 */
35960786Sps	if (how_toggle != OPT_NO_TOGGLE)
36060786Sps	{
36160786Sps		switch (o->otype & OTYPE)
36260786Sps		{
36360786Sps		case BOOL:
36460786Sps			/*
36560786Sps			 * Boolean.
36660786Sps			 */
36760786Sps			switch (how_toggle)
36860786Sps			{
36960786Sps			case OPT_TOGGLE:
37060786Sps				*(o->ovar) = ! *(o->ovar);
37160786Sps				break;
37260786Sps			case OPT_UNSET:
37360786Sps				*(o->ovar) = o->odefault;
37460786Sps				break;
37560786Sps			case OPT_SET:
37660786Sps				*(o->ovar) = ! o->odefault;
37760786Sps				break;
37860786Sps			}
37960786Sps			break;
38060786Sps		case TRIPLE:
38160786Sps			/*
38260786Sps			 * Triple:
38360786Sps			 *	If user gave the lower case letter, then switch
38460786Sps			 *	to 1 unless already 1, in which case make it 0.
38560786Sps			 *	If user gave the upper case letter, then switch
38660786Sps			 *	to 2 unless already 2, in which case make it 0.
38760786Sps			 */
38860786Sps			switch (how_toggle)
38960786Sps			{
39060786Sps			case OPT_TOGGLE:
391221715Sdelphij				*(o->ovar) = flip_triple(*(o->ovar), lower);
39260786Sps				break;
39360786Sps			case OPT_UNSET:
39460786Sps				*(o->ovar) = o->odefault;
39560786Sps				break;
39660786Sps			case OPT_SET:
397221715Sdelphij				*(o->ovar) = flip_triple(o->odefault, lower);
39860786Sps				break;
39960786Sps			}
40060786Sps			break;
40160786Sps		case STRING:
40260786Sps			/*
40360786Sps			 * String: don't do anything here.
40460786Sps			 *	The handling function will do everything.
40560786Sps			 */
40660786Sps			switch (how_toggle)
40760786Sps			{
40860786Sps			case OPT_SET:
40960786Sps			case OPT_UNSET:
41060786Sps				error("Cannot use \"-+\" or \"--\" for a string option",
41160786Sps					NULL_PARG);
41260786Sps				return;
41360786Sps			}
41460786Sps			break;
41560786Sps		case NUMBER:
41660786Sps			/*
41760786Sps			 * Number: set the variable to the given number.
41860786Sps			 */
41960786Sps			switch (how_toggle)
42060786Sps			{
42160786Sps			case OPT_TOGGLE:
422128345Stjr				num = getnum(&s, NULL, &err);
42360786Sps				if (!err)
42460786Sps					*(o->ovar) = num;
42560786Sps				break;
42660786Sps			case OPT_UNSET:
42760786Sps				*(o->ovar) = o->odefault;
42860786Sps				break;
42960786Sps			case OPT_SET:
43060786Sps				error("Can't use \"-!\" for a numeric option",
43160786Sps					NULL_PARG);
43260786Sps				return;
43360786Sps			}
43460786Sps			break;
43560786Sps		}
43660786Sps	}
43760786Sps
43860786Sps	/*
43960786Sps	 * Call the handling function for any special action
44060786Sps	 * specific to this option.
44160786Sps	 */
44260786Sps	if (o->ofunc != NULL)
44360786Sps		(*o->ofunc)((how_toggle==OPT_NO_TOGGLE) ? QUERY : TOGGLE, s);
44460786Sps
44560786Sps#if HILITE_SEARCH
44660786Sps	if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
44760786Sps		chg_hilite();
44860786Sps#endif
44960786Sps
45060786Sps	if (!no_prompt)
45160786Sps	{
45260786Sps		/*
45360786Sps		 * Print a message describing the new setting.
45460786Sps		 */
45560786Sps		switch (o->otype & OTYPE)
45660786Sps		{
45760786Sps		case BOOL:
45860786Sps		case TRIPLE:
45960786Sps			/*
46060786Sps			 * Print the odesc message.
46160786Sps			 */
46260786Sps			error(o->odesc[*(o->ovar)], NULL_PARG);
46360786Sps			break;
46460786Sps		case NUMBER:
46560786Sps			/*
46660786Sps			 * The message is in odesc[1] and has a %d for
46760786Sps			 * the value of the variable.
46860786Sps			 */
46960786Sps			parg.p_int = *(o->ovar);
47060786Sps			error(o->odesc[1], &parg);
47160786Sps			break;
47260786Sps		case STRING:
47360786Sps			/*
47460786Sps			 * Message was already printed by the handling function.
47560786Sps			 */
47660786Sps			break;
47760786Sps		}
47860786Sps	}
47960786Sps
48060786Sps	if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT))
48160786Sps		screen_trashed = TRUE;
48260786Sps}
48360786Sps
48460786Sps/*
48560786Sps * "Toggle" a triple-valued option.
48660786Sps */
48760786Sps	static int
48860786Spsflip_triple(val, lc)
48960786Sps	int val;
49060786Sps	int lc;
49160786Sps{
49260786Sps	if (lc)
49360786Sps		return ((val == OPT_ON) ? OPT_OFF : OPT_ON);
49460786Sps	else
49560786Sps		return ((val == OPT_ONPLUS) ? OPT_OFF : OPT_ONPLUS);
49660786Sps}
49760786Sps
49860786Sps/*
499221715Sdelphij * Determine if an option takes a parameter.
50060786Sps */
50160786Sps	public int
502221715Sdelphijopt_has_param(o)
503221715Sdelphij	struct loption *o;
50460786Sps{
50560786Sps	if (o == NULL)
506221715Sdelphij		return (0);
507221715Sdelphij	if (o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE))
508221715Sdelphij		return (0);
509221715Sdelphij	return (1);
51060786Sps}
51160786Sps
51260786Sps/*
51360786Sps * Return the prompt to be used for a given option letter.
51460786Sps * Only string and number valued options have prompts.
51560786Sps */
51660786Sps	public char *
517221715Sdelphijopt_prompt(o)
518221715Sdelphij	struct loption *o;
51960786Sps{
52060786Sps	if (o == NULL || (o->otype & (STRING|NUMBER)) == 0)
521221715Sdelphij		return ("?");
52260786Sps	return (o->odesc[0]);
52360786Sps}
52460786Sps
52560786Sps/*
52660786Sps * Return whether or not there is a string option pending;
52760786Sps * that is, if the previous option was a string-valued option letter
52860786Sps * (like -P) without a following string.
52960786Sps * In that case, the current option is taken to be the string for
53060786Sps * the previous option.
53160786Sps */
53260786Sps	public int
53360786Spsisoptpending()
53460786Sps{
53560786Sps	return (pendopt != NULL);
53660786Sps}
53760786Sps
53860786Sps/*
53960786Sps * Print error message about missing string.
54060786Sps */
54160786Sps	static void
54260786Spsnostring(printopt)
54360786Sps	char *printopt;
54460786Sps{
54560786Sps	PARG parg;
54660786Sps	parg.p_string = printopt;
54760786Sps	error("Value is required after %s", &parg);
54860786Sps}
54960786Sps
55060786Sps/*
55160786Sps * Print error message if a STRING type option is not followed by a string.
55260786Sps */
55360786Sps	public void
55460786Spsnopendopt()
55560786Sps{
556221715Sdelphij	nostring(opt_desc(pendopt));
55760786Sps}
55860786Sps
55960786Sps/*
56060786Sps * Scan to end of string or to an END_OPTION_STRING character.
56160786Sps * In the latter case, replace the char with a null char.
56260786Sps * Return a pointer to the remainder of the string, if any.
56360786Sps */
56460786Sps	static char *
565128345Stjroptstring(s, p_str, printopt, validchars)
56660786Sps	char *s;
567128345Stjr	char **p_str;
56860786Sps	char *printopt;
56989019Sps	char *validchars;
57060786Sps{
571330571Sdelphij	char *p;
572330571Sdelphij	char *out;
57360786Sps
57460786Sps	if (*s == '\0')
57560786Sps	{
57660786Sps		nostring(printopt);
577242584Sdelphij		return (NULL);
57860786Sps	}
579242584Sdelphij	/* Alloc could be more than needed, but not worth trimming. */
580242584Sdelphij	*p_str = (char *) ecalloc(strlen(s)+1, sizeof(char));
581242584Sdelphij	out = *p_str;
582242584Sdelphij
58360786Sps	for (p = s;  *p != '\0';  p++)
584128345Stjr	{
585250592Sdelphij		if (opt_use_backslash && *p == '\\' && p[1] != '\0')
58660786Sps		{
587242584Sdelphij			/* Take next char literally. */
588242584Sdelphij			++p;
589242584Sdelphij		} else
590242584Sdelphij		{
591242584Sdelphij			if (*p == END_OPTION_STRING ||
592242584Sdelphij			    (validchars != NULL && strchr(validchars, *p) == NULL))
593242584Sdelphij				/* End of option string. */
59489019Sps				break;
59560786Sps		}
596242584Sdelphij		*out++ = *p;
597128345Stjr	}
598242584Sdelphij	*out = '\0';
59960786Sps	return (p);
60060786Sps}
60160786Sps
60260786Sps/*
603170256Sdelphij */
604170256Sdelphij	static int
605170256Sdelphijnum_error(printopt, errp)
606170256Sdelphij	char *printopt;
607170256Sdelphij	int *errp;
608170256Sdelphij{
609170256Sdelphij	PARG parg;
610170256Sdelphij
611170256Sdelphij	if (errp != NULL)
612170256Sdelphij	{
613170256Sdelphij		*errp = TRUE;
614170256Sdelphij		return (-1);
615170256Sdelphij	}
616170256Sdelphij	if (printopt != NULL)
617170256Sdelphij	{
618170256Sdelphij		parg.p_string = printopt;
619170256Sdelphij		error("Number is required after %s", &parg);
620170256Sdelphij	}
621170256Sdelphij	return (-1);
622170256Sdelphij}
623170256Sdelphij
624170256Sdelphij/*
62560786Sps * Translate a string into a number.
62660786Sps * Like atoi(), but takes a pointer to a char *, and updates
62760786Sps * the char * to point after the translated number.
62860786Sps */
62960786Sps	public int
63060786Spsgetnum(sp, printopt, errp)
63160786Sps	char **sp;
63260786Sps	char *printopt;
63360786Sps	int *errp;
63460786Sps{
635330571Sdelphij	char *s;
636330571Sdelphij	int n;
637330571Sdelphij	int neg;
63860786Sps
63960786Sps	s = skipsp(*sp);
64060786Sps	neg = FALSE;
64160786Sps	if (*s == '-')
64260786Sps	{
64360786Sps		neg = TRUE;
64460786Sps		s++;
64560786Sps	}
64660786Sps	if (*s < '0' || *s > '9')
647170256Sdelphij		return (num_error(printopt, errp));
64860786Sps
64960786Sps	n = 0;
65060786Sps	while (*s >= '0' && *s <= '9')
65160786Sps		n = 10 * n + *s++ - '0';
65260786Sps	*sp = s;
65360786Sps	if (errp != NULL)
65460786Sps		*errp = FALSE;
65560786Sps	if (neg)
65660786Sps		n = -n;
65760786Sps	return (n);
65860786Sps}
659170256Sdelphij
660170256Sdelphij/*
661170256Sdelphij * Translate a string into a fraction, represented by the part of a
662170256Sdelphij * number which would follow a decimal point.
663170256Sdelphij * The value of the fraction is returned as parts per NUM_FRAC_DENOM.
664170256Sdelphij * That is, if "n" is returned, the fraction intended is n/NUM_FRAC_DENOM.
665170256Sdelphij */
666170256Sdelphij	public long
667170256Sdelphijgetfraction(sp, printopt, errp)
668170256Sdelphij	char **sp;
669170256Sdelphij	char *printopt;
670170256Sdelphij	int *errp;
671170256Sdelphij{
672330571Sdelphij	char *s;
673170256Sdelphij	long frac = 0;
674170256Sdelphij	int fraclen = 0;
675170256Sdelphij
676170256Sdelphij	s = skipsp(*sp);
677170256Sdelphij	if (*s < '0' || *s > '9')
678170256Sdelphij		return (num_error(printopt, errp));
679170256Sdelphij
680170256Sdelphij	for ( ;  *s >= '0' && *s <= '9';  s++)
681170256Sdelphij	{
682170256Sdelphij		frac = (frac * 10) + (*s - '0');
683170256Sdelphij		fraclen++;
684170256Sdelphij	}
685170256Sdelphij	if (fraclen > NUM_LOG_FRAC_DENOM)
686170256Sdelphij		while (fraclen-- > NUM_LOG_FRAC_DENOM)
687170256Sdelphij			frac /= 10;
688170256Sdelphij	else
689170256Sdelphij		while (fraclen++ < NUM_LOG_FRAC_DENOM)
690170256Sdelphij			frac *= 10;
691170256Sdelphij	*sp = s;
692170256Sdelphij	if (errp != NULL)
693170256Sdelphij		*errp = FALSE;
694170256Sdelphij	return (frac);
695170256Sdelphij}
696170256Sdelphij
697170256Sdelphij
698170256Sdelphij/*
699170256Sdelphij * Get the value of the -e flag.
700170256Sdelphij */
701170256Sdelphij	public int
702170256Sdelphijget_quit_at_eof()
703170256Sdelphij{
704170256Sdelphij	if (!less_is_more)
705170256Sdelphij		return quit_at_eof;
706170256Sdelphij	/* When less_is_more is set, the -e flag semantics are different. */
707294286Sdelphij	return quit_at_eof ? OPT_ONPLUS : OPT_ON;
708170256Sdelphij}
709