"SfR Fresh" - the SfR Freeware/Shareware Archive

Member "less-424/option.c" of archive less-424.tar.gz:


As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
    1 /*
    2  * Copyright (C) 1984-2008  Mark Nudelman
    3  *
    4  * You may distribute under the terms of either the GNU General Public
    5  * License or the Less License, as specified in the README file.
    6  *
    7  * For more information about less, or for information on how to
    8  * contact the author, see the README file.
    9  */
   10 
   11 
   12 /*
   13  * Process command line options.
   14  *
   15  * Each option is a single letter which controls a program variable.
   16  * The options have defaults which may be changed via
   17  * the command line option, toggled via the "-" command,
   18  * or queried via the "_" command.
   19  */
   20 
   21 #include "less.h"
   22 #include "option.h"
   23 
   24 static struct loption *pendopt;
   25 public int plusoption = FALSE;
   26 
   27 static char *propt();
   28 static char *optstring();
   29 static int flip_triple();
   30 
   31 extern int screen_trashed;
   32 extern int less_is_more;
   33 extern int quit_at_eof;
   34 extern char *every_first_cmd;
   35 
   36 /*
   37  * Scan an argument (either from the command line or from the
   38  * LESS environment variable) and process it.
   39  */
   40 	public void
   41 scan_option(s)
   42 	char *s;
   43 {
   44 	register struct loption *o;
   45 	register int optc;
   46 	char *optname;
   47 	char *printopt;
   48 	char *str;
   49 	int set_default;
   50 	int lc;
   51 	int err;
   52 	PARG parg;
   53 
   54 	if (s == NULL)
   55 		return;
   56 
   57 	/*
   58 	 * If we have a pending option which requires an argument,
   59 	 * handle it now.
   60 	 * This happens if the previous option was, for example, "-P"
   61 	 * without a following string.  In that case, the current
   62 	 * option is simply the argument for the previous option.
   63 	 */
   64 	if (pendopt != NULL)
   65 	{
   66 		switch (pendopt->otype & OTYPE)
   67 		{
   68 		case STRING:
   69 			(*pendopt->ofunc)(INIT, s);
   70 			break;
   71 		case NUMBER:
   72 			printopt = propt(pendopt->oletter);
   73 			*(pendopt->ovar) = getnum(&s, printopt, (int*)NULL);
   74 			break;
   75 		}
   76 		pendopt = NULL;
   77 		return;
   78 	}
   79 
   80 	set_default = FALSE;
   81 	optname = NULL;
   82 
   83 	while (*s != '\0')
   84 	{
   85 		/*
   86 		 * Check some special cases first.
   87 		 */
   88 		switch (optc = *s++)
   89 		{
   90 		case ' ':
   91 		case '\t':
   92 		case END_OPTION_STRING:
   93 			continue;
   94 		case '-':
   95 			/*
   96 			 * "--" indicates an option name instead of a letter.
   97 			 */
   98 			if (*s == '-')
   99 			{
  100 				optname = ++s;
  101 				break;
  102 			}
  103 			/*
  104 			 * "-+" means set these options back to their defaults.
  105 			 * (They may have been set otherwise by previous
  106 			 * options.)
  107 			 */
  108 			set_default = (*s == '+');
  109 			if (set_default)
  110 				s++;
  111 			continue;
  112 		case '+':
  113 			/*
  114 			 * An option prefixed by a "+" is ungotten, so
  115 			 * that it is interpreted as less commands
  116 			 * processed at the start of the first input file.
  117 			 * "++" means process the commands at the start of
  118 			 * EVERY input file.
  119 			 */
  120 			plusoption = TRUE;
  121 			s = optstring(s, &str, propt('+'), NULL);
  122 			if (*str == '+')
  123 				every_first_cmd = save(++str);
  124 			else
  125 				ungetsc(str);
  126 			continue;
  127 		case '0':  case '1':  case '2':  case '3':  case '4':
  128 		case '5':  case '6':  case '7':  case '8':  case '9':
  129 			/*
  130 			 * Special "more" compatibility form "-<number>"
  131 			 * instead of -z<number> to set the scrolling
  132 			 * window size.
  133 			 */
  134 			s--;
  135 			optc = 'z';
  136 			break;
  137 		case 'n':
  138 			if (less_is_more)
  139 				optc = 'z';
  140 			break;
  141 		}
  142 
  143 		/*
  144 		 * Not a special case.
  145 		 * Look up the option letter in the option table.
  146 		 */
  147 		err = 0;
  148 		if (optname == NULL)
  149 		{
  150 			printopt = propt(optc);
  151 			lc = ASCII_IS_LOWER(optc);
  152 			o = findopt(optc);
  153 		} else
  154 		{
  155 			printopt = optname;
  156 			lc = ASCII_IS_LOWER(optname[0]);
  157 			o = findopt_name(&optname, NULL, &err);
  158 			s = optname;
  159 			optname = NULL;
  160 			if (*s == '\0' || *s == ' ')
  161 			{
  162 				/*
  163 				 * The option name matches exactly.
  164 				 */
  165 				;
  166 			} else if (*s == '=')
  167 			{
  168 				/*
  169 				 * The option name is followed by "=value".
  170 				 */
  171 				if (o != NULL &&
  172 				    (o->otype & OTYPE) != STRING &&
  173 				    (o->otype & OTYPE) != NUMBER)
  174 				{
  175 					parg.p_string = printopt;
  176 					error("The %s option should not be followed by =",
  177 						&parg);
  178 					quit(QUIT_ERROR);
  179 				}
  180 				s++;
  181 			} else
  182 			{
  183 				/*
  184 				 * The specified name is longer than the
  185 				 * real option name.
  186 				 */
  187 				o = NULL;
  188 			}
  189 		}
  190 		if (o == NULL)
  191 		{
  192 			parg.p_string = printopt;
  193 			if (err == OPT_AMBIG)
  194 				error("%s is an ambiguous abbreviation (\"less --help\" for help)",
  195 					&parg);
  196 			else
  197 				error("There is no %s option (\"less --help\" for help)",
  198 					&parg);
  199 			quit(QUIT_ERROR);
  200 		}
  201 
  202 		str = NULL;
  203 		switch (o->otype & OTYPE)
  204 		{
  205 		case BOOL:
  206 			if (set_default)
  207 				*(o->ovar) = o->odefault;
  208 			else
  209 				*(o->ovar) = ! o->odefault;
  210 			break;
  211 		case TRIPLE:
  212 			if (set_default)
  213 				*(o->ovar) = o->odefault;
  214 			else
  215 				*(o->ovar) = flip_triple(o->odefault, lc);
  216 			break;
  217 		case STRING:
  218 			if (*s == '\0')
  219 			{
  220 				/*
  221 				 * Set pendopt and return.
  222 				 * We will get the string next time
  223 				 * scan_option is called.
  224 				 */
  225 				pendopt = o;
  226 				return;
  227 			}
  228 			/*
  229 			 * Don't do anything here.
  230 			 * All processing of STRING options is done by
  231 			 * the handling function.
  232 			 */
  233 			while (*s == ' ')
  234 				s++;
  235 			s = optstring(s, &str, printopt, o->odesc[1]);
  236 			break;
  237 		case NUMBER:
  238 			if (*s == '\0')
  239 			{
  240 				pendopt = o;
  241 				return;
  242 			}
  243 			*(o->ovar) = getnum(&s, printopt, (int*)NULL);
  244 			break;
  245 		}
  246 		/*
  247 		 * If the option has a handling function, call it.
  248 		 */
  249 		if (o->ofunc != NULL)
  250 			(*o->ofunc)(INIT, str);
  251 	}
  252 }
  253 
  254 /*
  255  * Toggle command line flags from within the program.
  256  * Used by the "-" and "_" commands.
  257  * how_toggle may be:
  258  *	OPT_NO_TOGGLE	just report the current setting, without changing it.
  259  *	OPT_TOGGLE	invert the current setting
  260  *	OPT_UNSET	set to the default value
  261  *	OPT_SET		set to the inverse of the default value
  262  */
  263 	public void
  264 toggle_option(c, s, how_toggle)
  265 	int c;
  266 	char *s;
  267 	int how_toggle;
  268 {
  269 	register struct loption *o;
  270 	register int num;
  271 	int no_prompt;
  272 	int err;
  273 	PARG parg;
  274 
  275 	no_prompt = (how_toggle & OPT_NO_PROMPT);
  276 	how_toggle &= ~OPT_NO_PROMPT;
  277 
  278 	/*
  279 	 * Look up the option letter in the option table.
  280 	 */
  281 	o = findopt(c);
  282 	if (o == NULL)
  283 	{
  284 		parg.p_string = propt(c);
  285 		error("There is no %s option", &parg);
  286 		return;
  287 	}
  288 
  289 	if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE))
  290 	{
  291 		parg.p_string = propt(c);
  292 		error("Cannot change the %s option", &parg);
  293 		return;
  294 	}
  295 
  296 	if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY))
  297 	{
  298 		parg.p_string = propt(c);
  299 		error("Cannot query the %s option", &parg);
  300 		return;
  301 	}
  302 
  303 	/*
  304 	 * Check for something which appears to be a do_toggle
  305 	 * (because the "-" command was used), but really is not.
  306 	 * This could be a string option with no string, or
  307 	 * a number option with no number.
  308 	 */
  309 	switch (o->otype & OTYPE)
  310 	{
  311 	case STRING:
  312 	case NUMBER:
  313 		if (how_toggle == OPT_TOGGLE && *s == '\0')
  314 			how_toggle = OPT_NO_TOGGLE;
  315 		break;
  316 	}
  317 
  318 #if HILITE_SEARCH
  319 	if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
  320 		repaint_hilite(0);
  321 #endif
  322 
  323 	/*
  324 	 * Now actually toggle (change) the variable.
  325 	 */
  326 	if (how_toggle != OPT_NO_TOGGLE)
  327 	{
  328 		switch (o->otype & OTYPE)
  329 		{
  330 		case BOOL:
  331 			/*
  332 			 * Boolean.
  333 			 */
  334 			switch (how_toggle)
  335 			{
  336 			case OPT_TOGGLE:
  337 				*(o->ovar) = ! *(o->ovar);
  338 				break;
  339 			case OPT_UNSET:
  340 				*(o->ovar) = o->odefault;
  341 				break;
  342 			case OPT_SET:
  343 				*(o->ovar) = ! o->odefault;
  344 				break;
  345 			}
  346 			break;
  347 		case TRIPLE:
  348 			/*
  349 			 * Triple:
  350 			 *	If user gave the lower case letter, then switch
  351 			 *	to 1 unless already 1, in which case make it 0.
  352 			 *	If user gave the upper case letter, then switch
  353 			 *	to 2 unless already 2, in which case make it 0.
  354 			 */
  355 			switch (how_toggle)
  356 			{
  357 			case OPT_TOGGLE:
  358 				*(o->ovar) = flip_triple(*(o->ovar),
  359 						ASCII_IS_LOWER(c));
  360 				break;
  361 			case OPT_UNSET:
  362 				*(o->ovar) = o->odefault;
  363 				break;
  364 			case OPT_SET:
  365 				*(o->ovar) = flip_triple(o->odefault,
  366 						ASCII_IS_LOWER(c));
  367 				break;
  368 			}
  369 			break;
  370 		case STRING:
  371 			/*
  372 			 * String: don't do anything here.
  373 			 *	The handling function will do everything.
  374 			 */
  375 			switch (how_toggle)
  376 			{
  377 			case OPT_SET:
  378 			case OPT_UNSET:
  379 				error("Cannot use \"-+\" or \"--\" for a string option",
  380 					NULL_PARG);
  381 				return;
  382 			}
  383 			break;
  384 		case NUMBER:
  385 			/*
  386 			 * Number: set the variable to the given number.
  387 			 */
  388 			switch (how_toggle)
  389 			{
  390 			case OPT_TOGGLE:
  391 				num = getnum(&s, NULL, &err);
  392 				if (!err)
  393 					*(o->ovar) = num;
  394 				break;
  395 			case OPT_UNSET:
  396 				*(o->ovar) = o->odefault;
  397 				break;
  398 			case OPT_SET:
  399 				error("Can't use \"-!\" for a numeric option",
  400 					NULL_PARG);
  401 				return;
  402 			}
  403 			break;
  404 		}
  405 	}
  406 
  407 	/*
  408 	 * Call the handling function for any special action
  409 	 * specific to this option.
  410 	 */
  411 	if (o->ofunc != NULL)
  412 		(*o->ofunc)((how_toggle==OPT_NO_TOGGLE) ? QUERY : TOGGLE, s);
  413 
  414 #if HILITE_SEARCH
  415 	if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
  416 		chg_hilite();
  417 #endif
  418 
  419 	if (!no_prompt)
  420 	{
  421 		/*
  422 		 * Print a message describing the new setting.
  423 		 */
  424 		switch (o->otype & OTYPE)
  425 		{
  426 		case BOOL:
  427 		case TRIPLE:
  428 			/*
  429 			 * Print the odesc message.
  430 			 */
  431 			error(o->odesc[*(o->ovar)], NULL_PARG);
  432 			break;
  433 		case NUMBER:
  434 			/*
  435 			 * The message is in odesc[1] and has a %d for
  436 			 * the value of the variable.
  437 			 */
  438 			parg.p_int = *(o->ovar);
  439 			error(o->odesc[1], &parg);
  440 			break;
  441 		case STRING:
  442 			/*
  443 			 * Message was already printed by the handling function.
  444 			 */
  445 			break;
  446 		}
  447 	}
  448 
  449 	if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT))
  450 		screen_trashed = TRUE;
  451 }
  452 
  453 /*
  454  * "Toggle" a triple-valued option.
  455  */
  456 	static int
  457 flip_triple(val, lc)
  458 	int val;
  459 	int lc;
  460 {
  461 	if (lc)
  462 		return ((val == OPT_ON) ? OPT_OFF : OPT_ON);
  463 	else
  464 		return ((val == OPT_ONPLUS) ? OPT_OFF : OPT_ONPLUS);
  465 }
  466 
  467 /*
  468  * Return a string suitable for printing as the "name" of an option.
  469  * For example, if the option letter is 'x', just return "-x".
  470  */
  471 	static char *
  472 propt(c)
  473 	int c;
  474 {
  475 	static char buf[8];
  476 
  477 	sprintf(buf, "-%s", prchar(c));
  478 	return (buf);
  479 }
  480 
  481 /*
  482  * Determine if an option is a single character option (BOOL or TRIPLE),
  483  * or if it a multi-character option (NUMBER).
  484  */
  485 	public int
  486 single_char_option(c)
  487 	int c;
  488 {
  489 	register struct loption *o;
  490 
  491 	o = findopt(c);
  492 	if (o == NULL)
  493 		return (TRUE);
  494 	return ((o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE)) != 0);
  495 }
  496 
  497 /*
  498  * Return the prompt to be used for a given option letter.
  499  * Only string and number valued options have prompts.
  500  */
  501 	public char *
  502 opt_prompt(c)
  503 	int c;
  504 {
  505 	register struct loption *o;
  506 
  507 	o = findopt(c);
  508 	if (o == NULL || (o->otype & (STRING|NUMBER)) == 0)
  509 		return (NULL);
  510 	return (o->odesc[0]);
  511 }
  512 
  513 /*
  514  * Return whether or not there is a string option pending;
  515  * that is, if the previous option was a string-valued option letter
  516  * (like -P) without a following string.
  517  * In that case, the current option is taken to be the string for
  518  * the previous option.
  519  */
  520 	public int
  521 isoptpending()
  522 {
  523 	return (pendopt != NULL);
  524 }
  525 
  526 /*
  527  * Print error message about missing string.
  528  */
  529 	static void
  530 nostring(printopt)
  531 	char *printopt;
  532 {
  533 	PARG parg;
  534 	parg.p_string = printopt;
  535 	error("Value is required after %s", &parg);
  536 }
  537 
  538 /*
  539  * Print error message if a STRING type option is not followed by a string.
  540  */
  541 	public void
  542 nopendopt()
  543 {
  544 	nostring(propt(pendopt->oletter));
  545 }
  546 
  547 /*
  548  * Scan to end of string or to an END_OPTION_STRING character.
  549  * In the latter case, replace the char with a null char.
  550  * Return a pointer to the remainder of the string, if any.
  551  */
  552 	static char *
  553 optstring(s, p_str, printopt, validchars)
  554 	char *s;
  555 	char **p_str;
  556 	char *printopt;
  557 	char *validchars;
  558 {
  559 	register char *p;
  560 
  561 	if (*s == '\0')
  562 	{
  563 		nostring(printopt);
  564 		quit(QUIT_ERROR);
  565 	}
  566 	*p_str = s;
  567 	for (p = s;  *p != '\0';  p++)
  568 	{
  569 		if (*p == END_OPTION_STRING ||
  570 		    (validchars != NULL && strchr(validchars, *p) == NULL))
  571 		{
  572 			switch (*p)
  573 			{
  574 			case END_OPTION_STRING:
  575 			case ' ':  case '\t':  case '-':
  576 				/* Replace the char with a null to terminate string. */
  577 				*p++ = '\0';
  578 				break;
  579 			default:
  580 				/* Cannot replace char; make a copy of the string. */
  581 				*p_str = (char *) ecalloc(p-s+1, sizeof(char));
  582 				strncpy(*p_str, s, p-s);
  583 				(*p_str)[p-s] = '\0';
  584 				break;
  585 			}
  586 			break;
  587 		}
  588 	}
  589 	return (p);
  590 }
  591 
  592 /*
  593  */
  594 	static int
  595 num_error(printopt, errp)
  596 	char *printopt;
  597 	int *errp;
  598 {
  599 	PARG parg;
  600 
  601 	if (errp != NULL)
  602 	{
  603 		*errp = TRUE;
  604 		return (-1);
  605 	}
  606 	if (printopt != NULL)
  607 	{
  608 		parg.p_string = printopt;
  609 		error("Number is required after %s", &parg);
  610 	}
  611 	quit(QUIT_ERROR);
  612 	/* NOTREACHED */
  613 	return (-1);
  614 }
  615 
  616 /*
  617  * Translate a string into a number.
  618  * Like atoi(), but takes a pointer to a char *, and updates
  619  * the char * to point after the translated number.
  620  */
  621 	public int
  622 getnum(sp, printopt, errp)
  623 	char **sp;
  624 	char *printopt;
  625 	int *errp;
  626 {
  627 	register char *s;
  628 	register int n;
  629 	register int neg;
  630 
  631 	s = skipsp(*sp);
  632 	neg = FALSE;
  633 	if (*s == '-')
  634 	{
  635 		neg = TRUE;
  636 		s++;
  637 	}
  638 	if (*s < '0' || *s > '9')
  639 		return (num_error(printopt, errp));
  640 
  641 	n = 0;
  642 	while (*s >= '0' && *s <= '9')
  643 		n = 10 * n + *s++ - '0';
  644 	*sp = s;
  645 	if (errp != NULL)
  646 		*errp = FALSE;
  647 	if (neg)
  648 		n = -n;
  649 	return (n);
  650 }
  651 
  652 /*
  653  * Translate a string into a fraction, represented by the part of a
  654  * number which would follow a decimal point.
  655  * The value of the fraction is returned as parts per NUM_FRAC_DENOM.
  656  * That is, if "n" is returned, the fraction intended is n/NUM_FRAC_DENOM.
  657  */
  658 	public long
  659 getfraction(sp, printopt, errp)
  660 	char **sp;
  661 	char *printopt;
  662 	int *errp;
  663 {
  664 	register char *s;
  665 	long frac = 0;
  666 	int fraclen = 0;
  667 
  668 	s = skipsp(*sp);
  669 	if (*s < '0' || *s > '9')
  670 		return (num_error(printopt, errp));
  671 
  672 	for ( ;  *s >= '0' && *s <= '9';  s++)
  673 	{
  674 		frac = (frac * 10) + (*s - '0');
  675 		fraclen++;
  676 	}
  677 	if (fraclen > NUM_LOG_FRAC_DENOM)
  678 		while (fraclen-- > NUM_LOG_FRAC_DENOM)
  679 			frac /= 10;
  680 	else
  681 		while (fraclen++ < NUM_LOG_FRAC_DENOM)
  682 			frac *= 10;
  683 	*sp = s;
  684 	if (errp != NULL)
  685 		*errp = FALSE;
  686 	return (frac);
  687 }
  688 
  689 
  690 /*
  691  * Get the value of the -e flag.
  692  */
  693 	public int
  694 get_quit_at_eof()
  695 {
  696 	if (!less_is_more)
  697 		return quit_at_eof;
  698 	/* When less_is_more is set, the -e flag semantics are different. */
  699 	return quit_at_eof ? OPT_ON : OPT_ONPLUS;
  700 }