option.c revision 238730
1168404Spjd/*
2168404Spjd * Copyright (C) 1984-2012  Mark Nudelman
3168404Spjd *
4168404Spjd * You may distribute under the terms of either the GNU General Public
5168404Spjd * License or the Less License, as specified in the README file.
6168404Spjd *
7168404Spjd * For more information, see the README file.
8168404Spjd */
9168404Spjd
10168404Spjd
11168404Spjd/*
12168404Spjd * Process command line options.
13168404Spjd *
14168404Spjd * Each option is a single letter which controls a program variable.
15168404Spjd * The options have defaults which may be changed via
16168404Spjd * the command line option, toggled via the "-" command,
17168404Spjd * or queried via the "_" command.
18168404Spjd */
19168404Spjd
20168404Spjd#include "less.h"
21168404Spjd#include "option.h"
22168404Spjd
23219089Spjdstatic struct loption *pendopt;
24227497Smmpublic int plusoption = FALSE;
25236155Smm
26236145Smmstatic char *optstring();
27236155Smmstatic int flip_triple();
28254758Sdelphij
29168404Spjdextern int screen_trashed;
30168404Spjdextern int less_is_more;
31168404Spjdextern int quit_at_eof;
32168404Spjdextern char *every_first_cmd;
33168404Spjd
34168404Spjd/*
35168404Spjd * Return a printable description of an option.
36168404Spjd */
37168404Spjd	static char *
38168404Spjdopt_desc(o)
39168404Spjd	struct loption *o;
40168404Spjd{
41168404Spjd	static char buf[OPTNAME_MAX + 10];
42168404Spjd	if (o->oletter == OLETTER_NONE)
43168404Spjd		SNPRINTF1(buf, sizeof(buf), "--%s", o->onames->oname);
44168404Spjd	else
45168404Spjd		SNPRINTF2(buf, sizeof(buf), "-%c (--%s)", o->oletter, o->onames->oname);
46168404Spjd	return (buf);
47185029Spjd}
48185029Spjd
49168404Spjd/*
50236155Smm * Return a string suitable for printing as the "name" of an option.
51168404Spjd * For example, if the option letter is 'x', just return "-x".
52168404Spjd */
53168404Spjd	public char *
54168404Spjdpropt(c)
55168404Spjd	int c;
56168404Spjd{
57185029Spjd	static char buf[8];
58236884Smm
59168404Spjd	sprintf(buf, "-%s", prchar(c));
60219089Spjd	return (buf);
61219089Spjd}
62168404Spjd
63168404Spjd/*
64168404Spjd * Scan an argument (either from the command line or from the
65168404Spjd * LESS environment variable) and process it.
66168404Spjd */
67224171Sgibbs	public void
68168404Spjdscan_option(s)
69168404Spjd	char *s;
70168404Spjd{
71168404Spjd	register struct loption *o;
72168404Spjd	register int optc;
73168404Spjd	char *optname;
74168404Spjd	char *printopt;
75168404Spjd	char *str;
76236155Smm	int set_default;
77168404Spjd	int lc;
78228103Smm	int err;
79228103Smm	PARG parg;
80168404Spjd
81168404Spjd	if (s == NULL)
82168404Spjd		return;
83219089Spjd
84168404Spjd	/*
85168404Spjd	 * If we have a pending option which requires an argument,
86168404Spjd	 * handle it now.
87168404Spjd	 * This happens if the previous option was, for example, "-P"
88168404Spjd	 * without a following string.  In that case, the current
89168404Spjd	 * option is simply the argument for the previous option.
90168404Spjd	 */
91168404Spjd	if (pendopt != NULL)
92168404Spjd	{
93168404Spjd		switch (pendopt->otype & OTYPE)
94168404Spjd		{
95168404Spjd		case STRING:
96168404Spjd			(*pendopt->ofunc)(INIT, s);
97168404Spjd			break;
98168404Spjd		case NUMBER:
99168404Spjd			printopt = opt_desc(pendopt);
100168404Spjd			*(pendopt->ovar) = getnum(&s, printopt, (int*)NULL);
101185029Spjd			break;
102185029Spjd		}
103168404Spjd		pendopt = NULL;
104168404Spjd		return;
105168404Spjd	}
106168404Spjd
107168404Spjd	set_default = FALSE;
108168404Spjd	optname = NULL;
109168404Spjd
110168404Spjd	while (*s != '\0')
111168404Spjd	{
112168404Spjd		/*
113168404Spjd		 * Check some special cases first.
114185029Spjd		 */
115168404Spjd		switch (optc = *s++)
116168404Spjd		{
117168404Spjd		case ' ':
118168404Spjd		case '\t':
119168404Spjd		case END_OPTION_STRING:
120168404Spjd			continue;
121168404Spjd		case '-':
122168404Spjd			/*
123168404Spjd			 * "--" indicates an option name instead of a letter.
124168404Spjd			 */
125168404Spjd			if (*s == '-')
126168404Spjd			{
127224171Sgibbs				optname = ++s;
128168404Spjd				break;
129168404Spjd			}
130168404Spjd			/*
131168404Spjd			 * "-+" means set these options back to their defaults.
132168404Spjd			 * (They may have been set otherwise by previous
133168404Spjd			 * options.)
134168404Spjd			 */
135168404Spjd			set_default = (*s == '+');
136168404Spjd			if (set_default)
137219089Spjd				s++;
138228103Smm			continue;
139236155Smm		case '+':
140236155Smm			/*
141168404Spjd			 * An option prefixed by a "+" is ungotten, so
142168404Spjd			 * that it is interpreted as less commands
143168404Spjd			 * processed at the start of the first input file.
144168404Spjd			 * "++" means process the commands at the start of
145168404Spjd			 * EVERY input file.
146168404Spjd			 */
147168404Spjd			plusoption = TRUE;
148168404Spjd			s = optstring(s, &str, propt('+'), NULL);
149168404Spjd			if (*str == '+')
150168404Spjd				every_first_cmd = save(++str);
151168404Spjd			else
152168404Spjd				ungetsc(str);
153168404Spjd			continue;
154168404Spjd		case '0':  case '1':  case '2':  case '3':  case '4':
155168404Spjd		case '5':  case '6':  case '7':  case '8':  case '9':
156168404Spjd			/*
157168404Spjd			 * Special "more" compatibility form "-<number>"
158168404Spjd			 * instead of -z<number> to set the scrolling
159168404Spjd			 * window size.
160168404Spjd			 */
161168404Spjd			s--;
162168404Spjd			optc = 'z';
163168404Spjd			break;
164168404Spjd		case 'n':
165168404Spjd			if (less_is_more)
166224171Sgibbs				optc = 'z';
167224171Sgibbs			break;
168168404Spjd		}
169168404Spjd
170168404Spjd		/*
171168404Spjd		 * Not a special case.
172168404Spjd		 * Look up the option letter in the option table.
173168404Spjd		 */
174168404Spjd		err = 0;
175236155Smm		if (optname == NULL)
176168404Spjd		{
177168404Spjd			printopt = propt(optc);
178168404Spjd			lc = ASCII_IS_LOWER(optc);
179168404Spjd			o = findopt(optc);
180219089Spjd		} else
181168404Spjd		{
182168404Spjd			printopt = optname;
183168404Spjd			lc = ASCII_IS_LOWER(optname[0]);
184168404Spjd			o = findopt_name(&optname, NULL, &err);
185168404Spjd			s = optname;
186168404Spjd			optname = NULL;
187228103Smm			if (*s == '\0' || *s == ' ')
188168404Spjd			{
189168404Spjd				/*
190168404Spjd				 * The option name matches exactly.
191168404Spjd				 */
192168404Spjd				;
193168404Spjd			} else if (*s == '=')
194168404Spjd			{
195168404Spjd				/*
196248571Smm				 * The option name is followed by "=value".
197185029Spjd				 */
198248571Smm				if (o != NULL &&
199219089Spjd				    (o->otype & OTYPE) != STRING &&
200219089Spjd				    (o->otype & OTYPE) != NUMBER)
201168404Spjd				{
202168404Spjd					parg.p_string = printopt;
203168404Spjd					error("The %s option should not be followed by =",
204168404Spjd						&parg);
205168404Spjd					quit(QUIT_ERROR);
206168404Spjd				}
207168404Spjd				s++;
208185029Spjd			} else
209168404Spjd			{
210219089Spjd				/*
211168404Spjd				 * The specified name is longer than the
212236884Smm				 * real option name.
213185029Spjd				 */
214185029Spjd				o = NULL;
215168404Spjd			}
216168404Spjd		}
217168404Spjd		if (o == NULL)
218168404Spjd		{
219168404Spjd			parg.p_string = printopt;
220168404Spjd			if (err == OPT_AMBIG)
221168404Spjd				error("%s is an ambiguous abbreviation (\"less --help\" for help)",
222185029Spjd					&parg);
223168404Spjd			else
224168404Spjd				error("There is no %s option (\"less --help\" for help)",
225219089Spjd					&parg);
226185029Spjd			quit(QUIT_ERROR);
227219089Spjd		}
228219089Spjd
229185029Spjd		str = NULL;
230219089Spjd		switch (o->otype & OTYPE)
231219089Spjd		{
232219089Spjd		case BOOL:
233168404Spjd			if (set_default)
234219089Spjd				*(o->ovar) = o->odefault;
235168404Spjd			else
236224171Sgibbs				*(o->ovar) = ! o->odefault;
237224171Sgibbs			break;
238168404Spjd		case TRIPLE:
239236960Smm			if (set_default)
240219089Spjd				*(o->ovar) = o->odefault;
241168404Spjd			else
242168404Spjd				*(o->ovar) = flip_triple(o->odefault, lc);
243168404Spjd			break;
244228020Smm		case STRING:
245168404Spjd			if (*s == '\0')
246168404Spjd			{
247185029Spjd				/*
248168404Spjd				 * Set pendopt and return.
249185029Spjd				 * We will get the string next time
250236155Smm				 * scan_option is called.
251236155Smm				 */
252168404Spjd				pendopt = o;
253168404Spjd				return;
254168404Spjd			}
255219089Spjd			/*
256219089Spjd			 * Don't do anything here.
257168404Spjd			 * All processing of STRING options is done by
258228020Smm			 * the handling function.
259185029Spjd			 */
260168404Spjd			while (*s == ' ')
261185029Spjd				s++;
262168404Spjd			s = optstring(s, &str, printopt, o->odesc[1]);
263168404Spjd			break;
264168404Spjd		case NUMBER:
265219089Spjd			if (*s == '\0')
266219089Spjd			{
267219089Spjd				pendopt = o;
268219089Spjd				return;
269228103Smm			}
270228103Smm			*(o->ovar) = getnum(&s, printopt, (int*)NULL);
271168404Spjd			break;
272168404Spjd		}
273168404Spjd		/*
274168404Spjd		 * If the option has a handling function, call it.
275168404Spjd		 */
276168404Spjd		if (o->ofunc != NULL)
277168404Spjd			(*o->ofunc)(INIT, str);
278168404Spjd	}
279168404Spjd}
280168404Spjd
281185029Spjd/*
282185029Spjd * Toggle command line flags from within the program.
283168404Spjd * Used by the "-" and "_" commands.
284168404Spjd * how_toggle may be:
285168404Spjd *	OPT_NO_TOGGLE	just report the current setting, without changing it.
286219089Spjd *	OPT_TOGGLE	invert the current setting
287168404Spjd *	OPT_UNSET	set to the default value
288185029Spjd *	OPT_SET		set to the inverse of the default value
289185029Spjd */
290185029Spjd	public void
291219089Spjdtoggle_option(o, lower, s, how_toggle)
292185029Spjd	struct loption *o;
293168404Spjd	int lower;
294168404Spjd	char *s;
295168404Spjd	int how_toggle;
296168404Spjd{
297168404Spjd	register int num;
298185029Spjd	int no_prompt;
299168404Spjd	int err;
300168404Spjd	PARG parg;
301168404Spjd
302168404Spjd	no_prompt = (how_toggle & OPT_NO_PROMPT);
303168404Spjd	how_toggle &= ~OPT_NO_PROMPT;
304168404Spjd
305168404Spjd	if (o == NULL)
306168404Spjd	{
307168404Spjd		error("No such option", NULL_PARG);
308168404Spjd		return;
309168404Spjd	}
310168404Spjd
311168404Spjd	if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE))
312168404Spjd	{
313168404Spjd		parg.p_string = opt_desc(o);
314168404Spjd		error("Cannot change the %s option", &parg);
315168404Spjd		return;
316168404Spjd	}
317168404Spjd
318168404Spjd	if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY))
319168404Spjd	{
320168404Spjd		parg.p_string = opt_desc(o);
321168404Spjd		error("Cannot query the %s option", &parg);
322168404Spjd		return;
323168404Spjd	}
324168404Spjd
325168404Spjd	/*
326168404Spjd	 * Check for something which appears to be a do_toggle
327168404Spjd	 * (because the "-" command was used), but really is not.
328168404Spjd	 * This could be a string option with no string, or
329168404Spjd	 * a number option with no number.
330168404Spjd	 */
331168404Spjd	switch (o->otype & OTYPE)
332185029Spjd	{
333185029Spjd	case STRING:
334168404Spjd	case NUMBER:
335168404Spjd		if (how_toggle == OPT_TOGGLE && *s == '\0')
336168404Spjd			how_toggle = OPT_NO_TOGGLE;
337168404Spjd		break;
338219089Spjd	}
339185029Spjd
340168404Spjd#if HILITE_SEARCH
341168404Spjd	if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
342185029Spjd		repaint_hilite(0);
343185029Spjd#endif
344236884Smm
345236884Smm	/*
346236884Smm	 * Now actually toggle (change) the variable.
347236884Smm	 */
348236884Smm	if (how_toggle != OPT_NO_TOGGLE)
349243014Smm	{
350168404Spjd		switch (o->otype & OTYPE)
351168404Spjd		{
352168404Spjd		case BOOL:
353168404Spjd			/*
354168404Spjd			 * Boolean.
355168404Spjd			 */
356168404Spjd			switch (how_toggle)
357168404Spjd			{
358168404Spjd			case OPT_TOGGLE:
359168404Spjd				*(o->ovar) = ! *(o->ovar);
360168404Spjd				break;
361168404Spjd			case OPT_UNSET:
362168404Spjd				*(o->ovar) = o->odefault;
363168404Spjd				break;
364185029Spjd			case OPT_SET:
365185029Spjd				*(o->ovar) = ! o->odefault;
366168404Spjd				break;
367168404Spjd			}
368168404Spjd			break;
369168404Spjd		case TRIPLE:
370168404Spjd			/*
371168404Spjd			 * Triple:
372168404Spjd			 *	If user gave the lower case letter, then switch
373168404Spjd			 *	to 1 unless already 1, in which case make it 0.
374168404Spjd			 *	If user gave the upper case letter, then switch
375168404Spjd			 *	to 2 unless already 2, in which case make it 0.
376168404Spjd			 */
377168404Spjd			switch (how_toggle)
378168404Spjd			{
379185029Spjd			case OPT_TOGGLE:
380185029Spjd				*(o->ovar) = flip_triple(*(o->ovar), lower);
381185029Spjd				break;
382185029Spjd			case OPT_UNSET:
383185029Spjd				*(o->ovar) = o->odefault;
384185029Spjd				break;
385185029Spjd			case OPT_SET:
386219089Spjd				*(o->ovar) = flip_triple(o->odefault, lower);
387185029Spjd				break;
388185029Spjd			}
389168404Spjd			break;
390168404Spjd		case STRING:
391168404Spjd			/*
392168404Spjd			 * String: don't do anything here.
393238926Smm			 *	The handling function will do everything.
394238926Smm			 */
395238926Smm			switch (how_toggle)
396238926Smm			{
397238926Smm			case OPT_SET:
398238926Smm			case OPT_UNSET:
399238926Smm				error("Cannot use \"-+\" or \"--\" for a string option",
400238926Smm					NULL_PARG);
401238926Smm				return;
402238926Smm			}
403238926Smm			break;
404238926Smm		case NUMBER:
405168404Spjd			/*
406185029Spjd			 * Number: set the variable to the given number.
407185029Spjd			 */
408185029Spjd			switch (how_toggle)
409185029Spjd			{
410185029Spjd			case OPT_TOGGLE:
411185029Spjd				num = getnum(&s, NULL, &err);
412185029Spjd				if (!err)
413185029Spjd					*(o->ovar) = num;
414185029Spjd				break;
415185029Spjd			case OPT_UNSET:
416185029Spjd				*(o->ovar) = o->odefault;
417185029Spjd				break;
418185029Spjd			case OPT_SET:
419185029Spjd				error("Can't use \"-!\" for a numeric option",
420185029Spjd					NULL_PARG);
421185029Spjd				return;
422185029Spjd			}
423185029Spjd			break;
424185029Spjd		}
425185029Spjd	}
426185029Spjd
427185029Spjd	/*
428238926Smm	 * Call the handling function for any special action
429238926Smm	 * specific to this option.
430236884Smm	 */
431236884Smm	if (o->ofunc != NULL)
432185029Spjd		(*o->ofunc)((how_toggle==OPT_NO_TOGGLE) ? QUERY : TOGGLE, s);
433185029Spjd
434185029Spjd#if HILITE_SEARCH
435185029Spjd	if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
436238926Smm		chg_hilite();
437238926Smm#endif
438238926Smm
439238926Smm	if (!no_prompt)
440238926Smm	{
441238926Smm		/*
442238926Smm		 * Print a message describing the new setting.
443238926Smm		 */
444238926Smm		switch (o->otype & OTYPE)
445238926Smm		{
446238926Smm		case BOOL:
447238926Smm		case TRIPLE:
448238926Smm			/*
449238926Smm			 * Print the odesc message.
450238926Smm			 */
451238926Smm			error(o->odesc[*(o->ovar)], NULL_PARG);
452236884Smm			break;
453236884Smm		case NUMBER:
454236884Smm			/*
455236884Smm			 * The message is in odesc[1] and has a %d for
456185029Spjd			 * the value of the variable.
457209962Smm			 */
458209962Smm			parg.p_int = *(o->ovar);
459209962Smm			error(o->odesc[1], &parg);
460209962Smm			break;
461185029Spjd		case STRING:
462185029Spjd			/*
463185029Spjd			 * Message was already printed by the handling function.
464185029Spjd			 */
465185029Spjd			break;
466185029Spjd		}
467185029Spjd	}
468185029Spjd
469185029Spjd	if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT))
470185029Spjd		screen_trashed = TRUE;
471185029Spjd}
472185029Spjd
473185029Spjd/*
474185029Spjd * "Toggle" a triple-valued option.
475185029Spjd */
476185029Spjd	static int
477185029Spjdflip_triple(val, lc)
478185029Spjd	int val;
479185029Spjd	int lc;
480185029Spjd{
481168404Spjd	if (lc)
482168404Spjd		return ((val == OPT_ON) ? OPT_OFF : OPT_ON);
483168404Spjd	else
484168404Spjd		return ((val == OPT_ONPLUS) ? OPT_OFF : OPT_ONPLUS);
485168404Spjd}
486168404Spjd
487168404Spjd/*
488168404Spjd * Determine if an option takes a parameter.
489168404Spjd */
490168404Spjd	public int
491168404Spjdopt_has_param(o)
492168404Spjd	struct loption *o;
493168404Spjd{
494168404Spjd	if (o == NULL)
495168404Spjd		return (0);
496168404Spjd	if (o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE))
497168404Spjd		return (0);
498168404Spjd	return (1);
499168404Spjd}
500168404Spjd
501168404Spjd/*
502168404Spjd * Return the prompt to be used for a given option letter.
503168404Spjd * Only string and number valued options have prompts.
504168404Spjd */
505168404Spjd	public char *
506168404Spjdopt_prompt(o)
507168404Spjd	struct loption *o;
508168404Spjd{
509168404Spjd	if (o == NULL || (o->otype & (STRING|NUMBER)) == 0)
510168404Spjd		return ("?");
511168404Spjd	return (o->odesc[0]);
512168404Spjd}
513168404Spjd
514168404Spjd/*
515168404Spjd * Return whether or not there is a string option pending;
516168404Spjd * that is, if the previous option was a string-valued option letter
517168404Spjd * (like -P) without a following string.
518168404Spjd * In that case, the current option is taken to be the string for
519168404Spjd * the previous option.
520168404Spjd */
521168404Spjd	public int
522168404Spjdisoptpending()
523168404Spjd{
524168404Spjd	return (pendopt != NULL);
525168404Spjd}
526168404Spjd
527168404Spjd/*
528168404Spjd * Print error message about missing string.
529168404Spjd */
530168404Spjd	static void
531168404Spjdnostring(printopt)
532168404Spjd	char *printopt;
533168404Spjd{
534168404Spjd	PARG parg;
535168404Spjd	parg.p_string = printopt;
536168404Spjd	error("Value is required after %s", &parg);
537168404Spjd}
538168404Spjd
539168404Spjd/*
540168404Spjd * Print error message if a STRING type option is not followed by a string.
541168404Spjd */
542168404Spjd	public void
543168404Spjdnopendopt()
544168404Spjd{
545168404Spjd	nostring(opt_desc(pendopt));
546168404Spjd}
547168404Spjd
548185029Spjd/*
549185029Spjd * Scan to end of string or to an END_OPTION_STRING character.
550168404Spjd * In the latter case, replace the char with a null char.
551168404Spjd * Return a pointer to the remainder of the string, if any.
552168404Spjd */
553168404Spjd	static char *
554168404Spjdoptstring(s, p_str, printopt, validchars)
555168404Spjd	char *s;
556168404Spjd	char **p_str;
557168404Spjd	char *printopt;
558168404Spjd	char *validchars;
559168404Spjd{
560168404Spjd	register char *p;
561168404Spjd
562168404Spjd	if (*s == '\0')
563168404Spjd	{
564185029Spjd		nostring(printopt);
565185029Spjd		quit(QUIT_ERROR);
566185029Spjd	}
567168404Spjd	*p_str = s;
568185029Spjd	for (p = s;  *p != '\0';  p++)
569185029Spjd	{
570185029Spjd		if (*p == END_OPTION_STRING ||
571185029Spjd		    (validchars != NULL && strchr(validchars, *p) == NULL))
572185029Spjd		{
573185029Spjd			switch (*p)
574185029Spjd			{
575185029Spjd			case END_OPTION_STRING:
576168404Spjd			case ' ':  case '\t':  case '-':
577168404Spjd				/* Replace the char with a null to terminate string. */
578168404Spjd				*p++ = '\0';
579168404Spjd				break;
580168404Spjd			default:
581168404Spjd				/* Cannot replace char; make a copy of the string. */
582168404Spjd				*p_str = (char *) ecalloc(p-s+1, sizeof(char));
583168404Spjd				strncpy(*p_str, s, p-s);
584168404Spjd				(*p_str)[p-s] = '\0';
585168404Spjd				break;
586168404Spjd			}
587168404Spjd			break;
588219089Spjd		}
589168404Spjd	}
590219089Spjd	return (p);
591219089Spjd}
592168404Spjd
593168404Spjd/*
594168404Spjd */
595168404Spjd	static int
596168404Spjdnum_error(printopt, errp)
597185029Spjd	char *printopt;
598168404Spjd	int *errp;
599168404Spjd{
600168404Spjd	PARG parg;
601168404Spjd
602168404Spjd	if (errp != NULL)
603168404Spjd	{
604168404Spjd		*errp = TRUE;
605168404Spjd		return (-1);
606168404Spjd	}
607168404Spjd	if (printopt != NULL)
608168404Spjd	{
609168404Spjd		parg.p_string = printopt;
610168404Spjd		error("Number is required after %s", &parg);
611168404Spjd	}
612168404Spjd	quit(QUIT_ERROR);
613168404Spjd	/* NOTREACHED */
614168404Spjd	return (-1);
615168404Spjd}
616168404Spjd
617168404Spjd/*
618185029Spjd * Translate a string into a number.
619185029Spjd * Like atoi(), but takes a pointer to a char *, and updates
620185029Spjd * the char * to point after the translated number.
621168404Spjd */
622168404Spjd	public int
623168404Spjdgetnum(sp, printopt, errp)
624168404Spjd	char **sp;
625168404Spjd	char *printopt;
626168404Spjd	int *errp;
627224171Sgibbs{
628224171Sgibbs	register char *s;
629224171Sgibbs	register int n;
630224171Sgibbs	register int neg;
631224171Sgibbs
632224171Sgibbs	s = skipsp(*sp);
633224171Sgibbs	neg = FALSE;
634224171Sgibbs	if (*s == '-')
635224171Sgibbs	{
636224171Sgibbs		neg = TRUE;
637224171Sgibbs		s++;
638224171Sgibbs	}
639224171Sgibbs	if (*s < '0' || *s > '9')
640224171Sgibbs		return (num_error(printopt, errp));
641224171Sgibbs
642224171Sgibbs	n = 0;
643224171Sgibbs	while (*s >= '0' && *s <= '9')
644224171Sgibbs		n = 10 * n + *s++ - '0';
645224171Sgibbs	*sp = s;
646224171Sgibbs	if (errp != NULL)
647224171Sgibbs		*errp = FALSE;
648224171Sgibbs	if (neg)
649224171Sgibbs		n = -n;
650224171Sgibbs	return (n);
651224171Sgibbs}
652224171Sgibbs
653224171Sgibbs/*
654224171Sgibbs * Translate a string into a fraction, represented by the part of a
655224171Sgibbs * number which would follow a decimal point.
656224171Sgibbs * The value of the fraction is returned as parts per NUM_FRAC_DENOM.
657224171Sgibbs * That is, if "n" is returned, the fraction intended is n/NUM_FRAC_DENOM.
658224171Sgibbs */
659224171Sgibbs	public long
660224171Sgibbsgetfraction(sp, printopt, errp)
661224171Sgibbs	char **sp;
662224171Sgibbs	char *printopt;
663224171Sgibbs	int *errp;
664224171Sgibbs{
665224171Sgibbs	register char *s;
666224171Sgibbs	long frac = 0;
667224171Sgibbs	int fraclen = 0;
668224171Sgibbs
669224171Sgibbs	s = skipsp(*sp);
670224171Sgibbs	if (*s < '0' || *s > '9')
671224171Sgibbs		return (num_error(printopt, errp));
672224171Sgibbs
673224171Sgibbs	for ( ;  *s >= '0' && *s <= '9';  s++)
674224171Sgibbs	{
675224171Sgibbs		frac = (frac * 10) + (*s - '0');
676224171Sgibbs		fraclen++;
677224171Sgibbs	}
678224171Sgibbs	if (fraclen > NUM_LOG_FRAC_DENOM)
679224171Sgibbs		while (fraclen-- > NUM_LOG_FRAC_DENOM)
680224171Sgibbs			frac /= 10;
681224171Sgibbs	else
682224171Sgibbs		while (fraclen++ < NUM_LOG_FRAC_DENOM)
683224171Sgibbs			frac *= 10;
684224171Sgibbs	*sp = s;
685224171Sgibbs	if (errp != NULL)
686224171Sgibbs		*errp = FALSE;
687224171Sgibbs	return (frac);
688224171Sgibbs}
689224171Sgibbs
690224171Sgibbs
691224171Sgibbs/*
692224171Sgibbs * Get the value of the -e flag.
693224171Sgibbs */
694224171Sgibbs	public int
695224171Sgibbsget_quit_at_eof()
696224171Sgibbs{
697224171Sgibbs	if (!less_is_more)
698224171Sgibbs		return quit_at_eof;
699224171Sgibbs	/* When less_is_more is set, the -e flag semantics are different. */
700224171Sgibbs	return quit_at_eof ? OPT_ON : OPT_ONPLUS;
701224171Sgibbs}
702224171Sgibbs