160786Sps/*
2240121Sdelphij * Copyright (C) 1984-2012  Mark Nudelman
360786Sps *
460786Sps * You may distribute under the terms of either the GNU General Public
560786Sps * License or the Less License, as specified in the README file.
660786Sps *
7240121Sdelphij * For more information, see the README file.
860786Sps */
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;
33251154Sdelphijextern 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{
72128345Stjr	register struct loption *o;
7360786Sps	register 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);
150251154Sdelphij			if (s == NULL)
151251154Sdelphij				return;
15289019Sps			if (*str == '+')
153251154Sdelphij				every_first_cmd = save(str+1);
15460786Sps			else
15589019Sps				ungetsc(str);
156251154Sdelphij			free(str);
15760786Sps			continue;
15860786Sps		case '0':  case '1':  case '2':  case '3':  case '4':
15960786Sps		case '5':  case '6':  case '7':  case '8':  case '9':
16060786Sps			/*
16160786Sps			 * Special "more" compatibility form "-<number>"
16260786Sps			 * instead of -z<number> to set the scrolling
16360786Sps			 * window size.
16460786Sps			 */
16560786Sps			s--;
16660786Sps			optc = 'z';
16760786Sps			break;
168170256Sdelphij		case 'n':
169170256Sdelphij			if (less_is_more)
170170256Sdelphij				optc = 'z';
171170256Sdelphij			break;
17260786Sps		}
17360786Sps
17460786Sps		/*
17560786Sps		 * Not a special case.
17660786Sps		 * Look up the option letter in the option table.
17760786Sps		 */
17860786Sps		err = 0;
17960786Sps		if (optname == NULL)
18060786Sps		{
18160786Sps			printopt = propt(optc);
182161475Sdelphij			lc = ASCII_IS_LOWER(optc);
18360786Sps			o = findopt(optc);
18460786Sps		} else
18560786Sps		{
18660786Sps			printopt = optname;
187161475Sdelphij			lc = ASCII_IS_LOWER(optname[0]);
18860786Sps			o = findopt_name(&optname, NULL, &err);
18960786Sps			s = optname;
19060786Sps			optname = NULL;
19160786Sps			if (*s == '\0' || *s == ' ')
19260786Sps			{
19360786Sps				/*
19460786Sps				 * The option name matches exactly.
19560786Sps				 */
19660786Sps				;
19760786Sps			} else if (*s == '=')
19860786Sps			{
19960786Sps				/*
20060786Sps				 * The option name is followed by "=value".
20160786Sps				 */
20260786Sps				if (o != NULL &&
20360786Sps				    (o->otype & OTYPE) != STRING &&
20460786Sps				    (o->otype & OTYPE) != NUMBER)
20560786Sps				{
20660786Sps					parg.p_string = printopt;
20760786Sps					error("The %s option should not be followed by =",
20860786Sps						&parg);
209251154Sdelphij					return;
21060786Sps				}
21160786Sps				s++;
21260786Sps			} else
21360786Sps			{
21460786Sps				/*
21560786Sps				 * The specified name is longer than the
21660786Sps				 * real option name.
21760786Sps				 */
21860786Sps				o = NULL;
21960786Sps			}
22060786Sps		}
22160786Sps		if (o == NULL)
22260786Sps		{
22360786Sps			parg.p_string = printopt;
22460786Sps			if (err == OPT_AMBIG)
22560786Sps				error("%s is an ambiguous abbreviation (\"less --help\" for help)",
22660786Sps					&parg);
22760786Sps			else
22860786Sps				error("There is no %s option (\"less --help\" for help)",
22960786Sps					&parg);
230251154Sdelphij			return;
23160786Sps		}
23260786Sps
23360786Sps		str = NULL;
23460786Sps		switch (o->otype & OTYPE)
23560786Sps		{
23660786Sps		case BOOL:
23760786Sps			if (set_default)
23860786Sps				*(o->ovar) = o->odefault;
23960786Sps			else
24060786Sps				*(o->ovar) = ! o->odefault;
24160786Sps			break;
24260786Sps		case TRIPLE:
24360786Sps			if (set_default)
24460786Sps				*(o->ovar) = o->odefault;
24560786Sps			else
24660786Sps				*(o->ovar) = flip_triple(o->odefault, lc);
24760786Sps			break;
24860786Sps		case STRING:
24960786Sps			if (*s == '\0')
25060786Sps			{
25160786Sps				/*
25260786Sps				 * Set pendopt and return.
25360786Sps				 * We will get the string next time
25460786Sps				 * scan_option is called.
25560786Sps				 */
25660786Sps				pendopt = o;
25760786Sps				return;
25860786Sps			}
25960786Sps			/*
26060786Sps			 * Don't do anything here.
26160786Sps			 * All processing of STRING options is done by
26260786Sps			 * the handling function.
26360786Sps			 */
264128345Stjr			while (*s == ' ')
265128345Stjr				s++;
266128345Stjr			s = optstring(s, &str, printopt, o->odesc[1]);
267251154Sdelphij			if (s == NULL)
268251154Sdelphij				return;
26960786Sps			break;
27060786Sps		case NUMBER:
27160786Sps			if (*s == '\0')
27260786Sps			{
27360786Sps				pendopt = o;
27460786Sps				return;
27560786Sps			}
27660786Sps			*(o->ovar) = getnum(&s, printopt, (int*)NULL);
27760786Sps			break;
27860786Sps		}
27960786Sps		/*
28060786Sps		 * If the option has a handling function, call it.
28160786Sps		 */
28260786Sps		if (o->ofunc != NULL)
28360786Sps			(*o->ofunc)(INIT, str);
284251154Sdelphij		if (str != NULL)
285251154Sdelphij			free(str);
28660786Sps	}
28760786Sps}
28860786Sps
28960786Sps/*
29060786Sps * Toggle command line flags from within the program.
29160786Sps * Used by the "-" and "_" commands.
29260786Sps * how_toggle may be:
29360786Sps *	OPT_NO_TOGGLE	just report the current setting, without changing it.
29460786Sps *	OPT_TOGGLE	invert the current setting
29560786Sps *	OPT_UNSET	set to the default value
29660786Sps *	OPT_SET		set to the inverse of the default value
29760786Sps */
29860786Sps	public void
299221715Sdelphijtoggle_option(o, lower, s, how_toggle)
300221715Sdelphij	struct loption *o;
301221715Sdelphij	int lower;
30260786Sps	char *s;
30360786Sps	int how_toggle;
30460786Sps{
30560786Sps	register int num;
30660786Sps	int no_prompt;
30760786Sps	int err;
30860786Sps	PARG parg;
30960786Sps
31060786Sps	no_prompt = (how_toggle & OPT_NO_PROMPT);
31160786Sps	how_toggle &= ~OPT_NO_PROMPT;
31260786Sps
31360786Sps	if (o == NULL)
31460786Sps	{
315221715Sdelphij		error("No such option", NULL_PARG);
31660786Sps		return;
31760786Sps	}
31860786Sps
31960786Sps	if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE))
32060786Sps	{
321221715Sdelphij		parg.p_string = opt_desc(o);
32260786Sps		error("Cannot change the %s option", &parg);
32360786Sps		return;
324221715Sdelphij	}
32560786Sps
32660786Sps	if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY))
32760786Sps	{
328221715Sdelphij		parg.p_string = opt_desc(o);
32960786Sps		error("Cannot query the %s option", &parg);
33060786Sps		return;
33160786Sps	}
33260786Sps
33360786Sps	/*
33460786Sps	 * Check for something which appears to be a do_toggle
33560786Sps	 * (because the "-" command was used), but really is not.
33660786Sps	 * This could be a string option with no string, or
33760786Sps	 * a number option with no number.
33860786Sps	 */
33960786Sps	switch (o->otype & OTYPE)
34060786Sps	{
34160786Sps	case STRING:
34260786Sps	case NUMBER:
34360786Sps		if (how_toggle == OPT_TOGGLE && *s == '\0')
34460786Sps			how_toggle = OPT_NO_TOGGLE;
34560786Sps		break;
34660786Sps	}
34760786Sps
34860786Sps#if HILITE_SEARCH
34960786Sps	if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
35060786Sps		repaint_hilite(0);
35160786Sps#endif
35260786Sps
35360786Sps	/*
35460786Sps	 * Now actually toggle (change) the variable.
35560786Sps	 */
35660786Sps	if (how_toggle != OPT_NO_TOGGLE)
35760786Sps	{
35860786Sps		switch (o->otype & OTYPE)
35960786Sps		{
36060786Sps		case BOOL:
36160786Sps			/*
36260786Sps			 * Boolean.
36360786Sps			 */
36460786Sps			switch (how_toggle)
36560786Sps			{
36660786Sps			case OPT_TOGGLE:
36760786Sps				*(o->ovar) = ! *(o->ovar);
36860786Sps				break;
36960786Sps			case OPT_UNSET:
37060786Sps				*(o->ovar) = o->odefault;
37160786Sps				break;
37260786Sps			case OPT_SET:
37360786Sps				*(o->ovar) = ! o->odefault;
37460786Sps				break;
37560786Sps			}
37660786Sps			break;
37760786Sps		case TRIPLE:
37860786Sps			/*
37960786Sps			 * Triple:
38060786Sps			 *	If user gave the lower case letter, then switch
38160786Sps			 *	to 1 unless already 1, in which case make it 0.
38260786Sps			 *	If user gave the upper case letter, then switch
38360786Sps			 *	to 2 unless already 2, in which case make it 0.
38460786Sps			 */
38560786Sps			switch (how_toggle)
38660786Sps			{
38760786Sps			case OPT_TOGGLE:
388221715Sdelphij				*(o->ovar) = flip_triple(*(o->ovar), lower);
38960786Sps				break;
39060786Sps			case OPT_UNSET:
39160786Sps				*(o->ovar) = o->odefault;
39260786Sps				break;
39360786Sps			case OPT_SET:
394221715Sdelphij				*(o->ovar) = flip_triple(o->odefault, lower);
39560786Sps				break;
39660786Sps			}
39760786Sps			break;
39860786Sps		case STRING:
39960786Sps			/*
40060786Sps			 * String: don't do anything here.
40160786Sps			 *	The handling function will do everything.
40260786Sps			 */
40360786Sps			switch (how_toggle)
40460786Sps			{
40560786Sps			case OPT_SET:
40660786Sps			case OPT_UNSET:
40760786Sps				error("Cannot use \"-+\" or \"--\" for a string option",
40860786Sps					NULL_PARG);
40960786Sps				return;
41060786Sps			}
41160786Sps			break;
41260786Sps		case NUMBER:
41360786Sps			/*
41460786Sps			 * Number: set the variable to the given number.
41560786Sps			 */
41660786Sps			switch (how_toggle)
41760786Sps			{
41860786Sps			case OPT_TOGGLE:
419128345Stjr				num = getnum(&s, NULL, &err);
42060786Sps				if (!err)
42160786Sps					*(o->ovar) = num;
42260786Sps				break;
42360786Sps			case OPT_UNSET:
42460786Sps				*(o->ovar) = o->odefault;
42560786Sps				break;
42660786Sps			case OPT_SET:
42760786Sps				error("Can't use \"-!\" for a numeric option",
42860786Sps					NULL_PARG);
42960786Sps				return;
43060786Sps			}
43160786Sps			break;
43260786Sps		}
43360786Sps	}
43460786Sps
43560786Sps	/*
43660786Sps	 * Call the handling function for any special action
43760786Sps	 * specific to this option.
43860786Sps	 */
43960786Sps	if (o->ofunc != NULL)
44060786Sps		(*o->ofunc)((how_toggle==OPT_NO_TOGGLE) ? QUERY : TOGGLE, s);
44160786Sps
44260786Sps#if HILITE_SEARCH
44360786Sps	if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
44460786Sps		chg_hilite();
44560786Sps#endif
44660786Sps
44760786Sps	if (!no_prompt)
44860786Sps	{
44960786Sps		/*
45060786Sps		 * Print a message describing the new setting.
45160786Sps		 */
45260786Sps		switch (o->otype & OTYPE)
45360786Sps		{
45460786Sps		case BOOL:
45560786Sps		case TRIPLE:
45660786Sps			/*
45760786Sps			 * Print the odesc message.
45860786Sps			 */
45960786Sps			error(o->odesc[*(o->ovar)], NULL_PARG);
46060786Sps			break;
46160786Sps		case NUMBER:
46260786Sps			/*
46360786Sps			 * The message is in odesc[1] and has a %d for
46460786Sps			 * the value of the variable.
46560786Sps			 */
46660786Sps			parg.p_int = *(o->ovar);
46760786Sps			error(o->odesc[1], &parg);
46860786Sps			break;
46960786Sps		case STRING:
47060786Sps			/*
47160786Sps			 * Message was already printed by the handling function.
47260786Sps			 */
47360786Sps			break;
47460786Sps		}
47560786Sps	}
47660786Sps
47760786Sps	if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT))
47860786Sps		screen_trashed = TRUE;
47960786Sps}
48060786Sps
48160786Sps/*
48260786Sps * "Toggle" a triple-valued option.
48360786Sps */
48460786Sps	static int
48560786Spsflip_triple(val, lc)
48660786Sps	int val;
48760786Sps	int lc;
48860786Sps{
48960786Sps	if (lc)
49060786Sps		return ((val == OPT_ON) ? OPT_OFF : OPT_ON);
49160786Sps	else
49260786Sps		return ((val == OPT_ONPLUS) ? OPT_OFF : OPT_ONPLUS);
49360786Sps}
49460786Sps
49560786Sps/*
496221715Sdelphij * Determine if an option takes a parameter.
49760786Sps */
49860786Sps	public int
499221715Sdelphijopt_has_param(o)
500221715Sdelphij	struct loption *o;
50160786Sps{
50260786Sps	if (o == NULL)
503221715Sdelphij		return (0);
504221715Sdelphij	if (o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE))
505221715Sdelphij		return (0);
506221715Sdelphij	return (1);
50760786Sps}
50860786Sps
50960786Sps/*
51060786Sps * Return the prompt to be used for a given option letter.
51160786Sps * Only string and number valued options have prompts.
51260786Sps */
51360786Sps	public char *
514221715Sdelphijopt_prompt(o)
515221715Sdelphij	struct loption *o;
51660786Sps{
51760786Sps	if (o == NULL || (o->otype & (STRING|NUMBER)) == 0)
518221715Sdelphij		return ("?");
51960786Sps	return (o->odesc[0]);
52060786Sps}
52160786Sps
52260786Sps/*
52360786Sps * Return whether or not there is a string option pending;
52460786Sps * that is, if the previous option was a string-valued option letter
52560786Sps * (like -P) without a following string.
52660786Sps * In that case, the current option is taken to be the string for
52760786Sps * the previous option.
52860786Sps */
52960786Sps	public int
53060786Spsisoptpending()
53160786Sps{
53260786Sps	return (pendopt != NULL);
53360786Sps}
53460786Sps
53560786Sps/*
53660786Sps * Print error message about missing string.
53760786Sps */
53860786Sps	static void
53960786Spsnostring(printopt)
54060786Sps	char *printopt;
54160786Sps{
54260786Sps	PARG parg;
54360786Sps	parg.p_string = printopt;
54460786Sps	error("Value is required after %s", &parg);
54560786Sps}
54660786Sps
54760786Sps/*
54860786Sps * Print error message if a STRING type option is not followed by a string.
54960786Sps */
55060786Sps	public void
55160786Spsnopendopt()
55260786Sps{
553221715Sdelphij	nostring(opt_desc(pendopt));
55460786Sps}
55560786Sps
55660786Sps/*
55760786Sps * Scan to end of string or to an END_OPTION_STRING character.
55860786Sps * In the latter case, replace the char with a null char.
55960786Sps * Return a pointer to the remainder of the string, if any.
56060786Sps */
56160786Sps	static char *
562128345Stjroptstring(s, p_str, printopt, validchars)
56360786Sps	char *s;
564128345Stjr	char **p_str;
56560786Sps	char *printopt;
56689019Sps	char *validchars;
56760786Sps{
56860786Sps	register char *p;
569251154Sdelphij	register char *out;
57060786Sps
57160786Sps	if (*s == '\0')
57260786Sps	{
57360786Sps		nostring(printopt);
574251154Sdelphij		return (NULL);
57560786Sps	}
576251154Sdelphij	/* Alloc could be more than needed, but not worth trimming. */
577251154Sdelphij	*p_str = (char *) ecalloc(strlen(s)+1, sizeof(char));
578251154Sdelphij	out = *p_str;
579251154Sdelphij
58060786Sps	for (p = s;  *p != '\0';  p++)
581128345Stjr	{
582251154Sdelphij		if (opt_use_backslash && *p == '\\' && p[1] != '\0')
58360786Sps		{
584251154Sdelphij			/* Take next char literally. */
585251154Sdelphij			++p;
586251154Sdelphij		} else
587251154Sdelphij		{
588251154Sdelphij			if (*p == END_OPTION_STRING ||
589251154Sdelphij			    (validchars != NULL && strchr(validchars, *p) == NULL))
590251154Sdelphij				/* End of option string. */
59189019Sps				break;
59260786Sps		}
593251154Sdelphij		*out++ = *p;
594128345Stjr	}
595251154Sdelphij	*out = '\0';
59660786Sps	return (p);
59760786Sps}
59860786Sps
59960786Sps/*
600170256Sdelphij */
601170256Sdelphij	static int
602170256Sdelphijnum_error(printopt, errp)
603170256Sdelphij	char *printopt;
604170256Sdelphij	int *errp;
605170256Sdelphij{
606170256Sdelphij	PARG parg;
607170256Sdelphij
608170256Sdelphij	if (errp != NULL)
609170256Sdelphij	{
610170256Sdelphij		*errp = TRUE;
611170256Sdelphij		return (-1);
612170256Sdelphij	}
613170256Sdelphij	if (printopt != NULL)
614170256Sdelphij	{
615170256Sdelphij		parg.p_string = printopt;
616170256Sdelphij		error("Number is required after %s", &parg);
617170256Sdelphij	}
618170256Sdelphij	return (-1);
619170256Sdelphij}
620170256Sdelphij
621170256Sdelphij/*
62260786Sps * Translate a string into a number.
62360786Sps * Like atoi(), but takes a pointer to a char *, and updates
62460786Sps * the char * to point after the translated number.
62560786Sps */
62660786Sps	public int
62760786Spsgetnum(sp, printopt, errp)
62860786Sps	char **sp;
62960786Sps	char *printopt;
63060786Sps	int *errp;
63160786Sps{
63260786Sps	register char *s;
63360786Sps	register int n;
63460786Sps	register int neg;
63560786Sps
63660786Sps	s = skipsp(*sp);
63760786Sps	neg = FALSE;
63860786Sps	if (*s == '-')
63960786Sps	{
64060786Sps		neg = TRUE;
64160786Sps		s++;
64260786Sps	}
64360786Sps	if (*s < '0' || *s > '9')
644170256Sdelphij		return (num_error(printopt, errp));
64560786Sps
64660786Sps	n = 0;
64760786Sps	while (*s >= '0' && *s <= '9')
64860786Sps		n = 10 * n + *s++ - '0';
64960786Sps	*sp = s;
65060786Sps	if (errp != NULL)
65160786Sps		*errp = FALSE;
65260786Sps	if (neg)
65360786Sps		n = -n;
65460786Sps	return (n);
65560786Sps}
656170256Sdelphij
657170256Sdelphij/*
658170256Sdelphij * Translate a string into a fraction, represented by the part of a
659170256Sdelphij * number which would follow a decimal point.
660170256Sdelphij * The value of the fraction is returned as parts per NUM_FRAC_DENOM.
661170256Sdelphij * That is, if "n" is returned, the fraction intended is n/NUM_FRAC_DENOM.
662170256Sdelphij */
663170256Sdelphij	public long
664170256Sdelphijgetfraction(sp, printopt, errp)
665170256Sdelphij	char **sp;
666170256Sdelphij	char *printopt;
667170256Sdelphij	int *errp;
668170256Sdelphij{
669170256Sdelphij	register char *s;
670170256Sdelphij	long frac = 0;
671170256Sdelphij	int fraclen = 0;
672170256Sdelphij
673170256Sdelphij	s = skipsp(*sp);
674170256Sdelphij	if (*s < '0' || *s > '9')
675170256Sdelphij		return (num_error(printopt, errp));
676170256Sdelphij
677170256Sdelphij	for ( ;  *s >= '0' && *s <= '9';  s++)
678170256Sdelphij	{
679170256Sdelphij		frac = (frac * 10) + (*s - '0');
680170256Sdelphij		fraclen++;
681170256Sdelphij	}
682170256Sdelphij	if (fraclen > NUM_LOG_FRAC_DENOM)
683170256Sdelphij		while (fraclen-- > NUM_LOG_FRAC_DENOM)
684170256Sdelphij			frac /= 10;
685170256Sdelphij	else
686170256Sdelphij		while (fraclen++ < NUM_LOG_FRAC_DENOM)
687170256Sdelphij			frac *= 10;
688170256Sdelphij	*sp = s;
689170256Sdelphij	if (errp != NULL)
690170256Sdelphij		*errp = FALSE;
691170256Sdelphij	return (frac);
692170256Sdelphij}
693170256Sdelphij
694170256Sdelphij
695170256Sdelphij/*
696170256Sdelphij * Get the value of the -e flag.
697170256Sdelphij */
698170256Sdelphij	public int
699170256Sdelphijget_quit_at_eof()
700170256Sdelphij{
701170256Sdelphij	if (!less_is_more)
702170256Sdelphij		return quit_at_eof;
703170256Sdelphij	/* When less_is_more is set, the -e flag semantics are different. */
704170256Sdelphij	return quit_at_eof ? OPT_ON : OPT_ONPLUS;
705170256Sdelphij}
706