version 1.4, 2003/03/13 09:09:32 |
version 1.5, 2003/04/13 18:26:26 |
|
|
/* $OpenBSD$ */ |
|
|
|
/* |
/* |
* Copyright (c) 1984,1985,1989,1994,1995 Mark Nudelman |
* Copyright (C) 1984-2002 Mark Nudelman |
* All rights reserved. |
|
* |
* |
* Redistribution and use in source and binary forms, with or without |
* You may distribute under the terms of either the GNU General Public |
* modification, are permitted provided that the following conditions |
* License or the Less License, as specified in the README file. |
* are met: |
|
* 1. Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* 2. Redistributions in binary form must reproduce the above copyright |
|
* notice in the documentation and/or other materials provided with |
|
* the distribution. |
|
* |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY |
* For more information about less, or for information on how to |
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* contact the author, see the README file. |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
|
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
*/ |
*/ |
|
|
|
|
|
|
#include "less.h" |
#include "less.h" |
#include "option.h" |
#include "option.h" |
|
|
static struct option *pendopt; |
static struct loption *pendopt; |
public int plusoption = FALSE; |
public int plusoption = FALSE; |
|
|
static char *propt(); |
static char *propt(); |
|
|
scan_option(s) |
scan_option(s) |
char *s; |
char *s; |
{ |
{ |
struct option *o; |
register struct loption *o; |
int c; |
register int optc; |
|
char *optname; |
|
char *printopt; |
char *str; |
char *str; |
int set_default; |
int set_default; |
|
int lc; |
|
int err; |
PARG parg; |
PARG parg; |
|
|
if (s == NULL) |
if (s == NULL) |
return; |
return; |
|
|
/* |
/* |
* If we have a pending string-valued option, handle it now. |
* If we have a pending option which requires an argument, |
|
* handle it now. |
* This happens if the previous option was, for example, "-P" |
* This happens if the previous option was, for example, "-P" |
* without a following string. In that case, the current |
* without a following string. In that case, the current |
* option is simply the string for the previous option. |
* option is simply the argument for the previous option. |
*/ |
*/ |
if (pendopt != NULL) |
if (pendopt != NULL) |
{ |
{ |
(*pendopt->ofunc)(INIT, s); |
switch (pendopt->otype & OTYPE) |
|
{ |
|
case STRING: |
|
(*pendopt->ofunc)(INIT, s); |
|
break; |
|
case NUMBER: |
|
printopt = propt(pendopt->oletter); |
|
*(pendopt->ovar) = getnum(&s, printopt, (int*)NULL); |
|
break; |
|
} |
pendopt = NULL; |
pendopt = NULL; |
return; |
return; |
} |
} |
|
|
set_default = FALSE; |
set_default = FALSE; |
|
optname = NULL; |
|
|
while (*s != '\0') |
while (*s != '\0') |
{ |
{ |
/* |
/* |
* Check some special cases first. |
* Check some special cases first. |
*/ |
*/ |
switch (c = *s++) |
switch (optc = *s++) |
{ |
{ |
case ' ': |
case ' ': |
case '\t': |
case '\t': |
|
|
continue; |
continue; |
case '-': |
case '-': |
/* |
/* |
|
* "--" indicates an option name instead of a letter. |
|
*/ |
|
if (*s == '-') |
|
{ |
|
optname = ++s; |
|
break; |
|
} |
|
/* |
* "-+" means set these options back to their defaults. |
* "-+" means set these options back to their defaults. |
* (They may have been set otherwise by previous |
* (They may have been set otherwise by previous |
* options.) |
* options.) |
*/ |
*/ |
if (set_default = (*s == '+')) |
set_default = (*s == '+'); |
|
if (set_default) |
s++; |
s++; |
continue; |
continue; |
case '+': |
case '+': |
|
|
* EVERY input file. |
* EVERY input file. |
*/ |
*/ |
plusoption = TRUE; |
plusoption = TRUE; |
if (*s == '+') |
s = optstring(s, &str, propt('+'), NULL); |
every_first_cmd = save(++s); |
if (*str == '+') |
|
every_first_cmd = save(++str); |
else |
else |
ungetsc(s); |
ungetsc(str); |
s = optstring(s, c); |
|
continue; |
continue; |
case '0': case '1': case '2': case '3': case '4': |
case '0': case '1': case '2': case '3': case '4': |
case '5': case '6': case '7': case '8': case '9': |
case '5': case '6': case '7': case '8': case '9': |
|
|
* window size. |
* window size. |
*/ |
*/ |
s--; |
s--; |
c = 'z'; |
optc = 'z'; |
break; |
break; |
} |
} |
|
|
|
|
* Not a special case. |
* Not a special case. |
* Look up the option letter in the option table. |
* Look up the option letter in the option table. |
*/ |
*/ |
o = findopt(c); |
err = 0; |
|
if (optname == NULL) |
|
{ |
|
printopt = propt(optc); |
|
lc = SIMPLE_IS_LOWER(optc); |
|
o = findopt(optc); |
|
} else |
|
{ |
|
printopt = optname; |
|
lc = SIMPLE_IS_LOWER(optname[0]); |
|
o = findopt_name(&optname, NULL, &err); |
|
s = optname; |
|
optname = NULL; |
|
if (*s == '\0' || *s == ' ') |
|
{ |
|
/* |
|
* The option name matches exactly. |
|
*/ |
|
; |
|
} else if (*s == '=') |
|
{ |
|
/* |
|
* The option name is followed by "=value". |
|
*/ |
|
if (o != NULL && |
|
(o->otype & OTYPE) != STRING && |
|
(o->otype & OTYPE) != NUMBER) |
|
{ |
|
parg.p_string = printopt; |
|
error("The %s option should not be followed by =", |
|
&parg); |
|
quit(QUIT_ERROR); |
|
} |
|
s++; |
|
} else |
|
{ |
|
/* |
|
* The specified name is longer than the |
|
* real option name. |
|
*/ |
|
o = NULL; |
|
} |
|
} |
if (o == NULL) |
if (o == NULL) |
{ |
{ |
parg.p_string = propt(c); |
parg.p_string = printopt; |
#if MSOFTC || OS2 |
if (err == OPT_AMBIG) |
error("There is no %s flag (\"less -?\" for help)", |
error("%s is an ambiguous abbreviation (\"less --help\" for help)", |
&parg); |
&parg); |
#else |
else |
error("There is no %s flag (\"less -\\?\" for help)", |
error("There is no %s option (\"less --help\" for help)", |
&parg); |
&parg); |
#endif |
|
quit(QUIT_ERROR); |
quit(QUIT_ERROR); |
} |
} |
|
|
|
str = NULL; |
switch (o->otype & OTYPE) |
switch (o->otype & OTYPE) |
{ |
{ |
case BOOL: |
case BOOL: |
|
|
if (set_default) |
if (set_default) |
*(o->ovar) = o->odefault; |
*(o->ovar) = o->odefault; |
else |
else |
*(o->ovar) = flip_triple(o->odefault, |
*(o->ovar) = flip_triple(o->odefault, lc); |
(o->oletter == c)); |
|
break; |
break; |
case STRING: |
case STRING: |
if (*s == '\0') |
if (*s == '\0') |
|
|
* All processing of STRING options is done by |
* All processing of STRING options is done by |
* the handling function. |
* the handling function. |
*/ |
*/ |
str = s; |
while (*s == ' ') |
s = optstring(s, c); |
s++; |
|
s = optstring(s, &str, printopt, o->odesc[1]); |
break; |
break; |
case NUMBER: |
case NUMBER: |
*(o->ovar) = getnum(&s, c, (int*)NULL); |
if (*s == '\0') |
|
{ |
|
pendopt = o; |
|
return; |
|
} |
|
*(o->ovar) = getnum(&s, printopt, (int*)NULL); |
break; |
break; |
} |
} |
/* |
/* |
|
|
char *s; |
char *s; |
int how_toggle; |
int how_toggle; |
{ |
{ |
struct option *o; |
register struct loption *o; |
int num; |
register int num; |
|
int no_prompt; |
int err; |
int err; |
PARG parg; |
PARG parg; |
|
|
|
no_prompt = (how_toggle & OPT_NO_PROMPT); |
|
how_toggle &= ~OPT_NO_PROMPT; |
|
|
/* |
/* |
* Look up the option letter in the option table. |
* Look up the option letter in the option table. |
*/ |
*/ |
|
|
if (o == NULL) |
if (o == NULL) |
{ |
{ |
parg.p_string = propt(c); |
parg.p_string = propt(c); |
error("There is no %s flag", &parg); |
error("There is no %s option", &parg); |
return; |
return; |
} |
} |
|
|
if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE)) |
if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE)) |
{ |
{ |
parg.p_string = propt(c); |
parg.p_string = propt(c); |
error("Cannot change the %s flag", &parg); |
error("Cannot change the %s option", &parg); |
return; |
return; |
} |
} |
|
|
if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY)) |
if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY)) |
{ |
{ |
parg.p_string = propt(c); |
parg.p_string = propt(c); |
error("Cannot query the %s flag", &parg); |
error("Cannot query the %s option", &parg); |
return; |
return; |
} |
} |
|
|
|
|
{ |
{ |
case OPT_TOGGLE: |
case OPT_TOGGLE: |
*(o->ovar) = flip_triple(*(o->ovar), |
*(o->ovar) = flip_triple(*(o->ovar), |
o->oletter == c); |
islower(c)); |
break; |
break; |
case OPT_UNSET: |
case OPT_UNSET: |
*(o->ovar) = o->odefault; |
*(o->ovar) = o->odefault; |
break; |
break; |
case OPT_SET: |
case OPT_SET: |
*(o->ovar) = flip_triple(o->odefault, |
*(o->ovar) = flip_triple(o->odefault, |
o->oletter == c); |
islower(c)); |
break; |
break; |
} |
} |
break; |
break; |
|
|
{ |
{ |
case OPT_SET: |
case OPT_SET: |
case OPT_UNSET: |
case OPT_UNSET: |
error("Can't use \"-+\" or \"--\" for a string flag", |
error("Cannot use \"-+\" or \"--\" for a string option", |
NULL_PARG); |
NULL_PARG); |
return; |
return; |
} |
} |
|
|
switch (how_toggle) |
switch (how_toggle) |
{ |
{ |
case OPT_TOGGLE: |
case OPT_TOGGLE: |
num = getnum(&s, '\0', &err); |
num = getnum(&s, NULL, &err); |
if (!err) |
if (!err) |
*(o->ovar) = num; |
*(o->ovar) = num; |
break; |
break; |
|
|
*(o->ovar) = o->odefault; |
*(o->ovar) = o->odefault; |
break; |
break; |
case OPT_SET: |
case OPT_SET: |
error("Can't use \"--\" for a numeric flag", |
error("Can't use \"-!\" for a numeric option", |
NULL_PARG); |
NULL_PARG); |
return; |
return; |
} |
} |
|
|
chg_hilite(); |
chg_hilite(); |
#endif |
#endif |
|
|
/* |
if (!no_prompt) |
* Print a message describing the new setting. |
|
*/ |
|
switch (o->otype & OTYPE) |
|
{ |
{ |
case BOOL: |
|
case TRIPLE: |
|
/* |
/* |
* Print the odesc message. |
* Print a message describing the new setting. |
*/ |
*/ |
error(o->odesc[*(o->ovar)], NULL_PARG); |
switch (o->otype & OTYPE) |
break; |
{ |
case NUMBER: |
case BOOL: |
/* |
case TRIPLE: |
* The message is in odesc[1] and has a %d for |
/* |
* the value of the variable. |
* Print the odesc message. |
*/ |
*/ |
parg.p_int = *(o->ovar); |
error(o->odesc[*(o->ovar)], NULL_PARG); |
error(o->odesc[1], &parg); |
break; |
break; |
case NUMBER: |
case STRING: |
/* |
/* |
* The message is in odesc[1] and has a %d for |
* Message was already printed by the handling function. |
* the value of the variable. |
*/ |
*/ |
break; |
parg.p_int = *(o->ovar); |
|
error(o->odesc[1], &parg); |
|
break; |
|
case STRING: |
|
/* |
|
* Message was already printed by the handling function. |
|
*/ |
|
break; |
|
} |
} |
} |
|
|
if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT)) |
if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT)) |
|
|
{ |
{ |
static char buf[8]; |
static char buf[8]; |
|
|
snprintf(buf, sizeof buf, "-%s", prchar(c)); |
snprintf(buf, sizeof(buf), "-%s", prchar(c)); |
return (buf); |
return (buf); |
} |
} |
|
|
|
|
single_char_option(c) |
single_char_option(c) |
int c; |
int c; |
{ |
{ |
struct option *o; |
register struct loption *o; |
|
|
o = findopt(c); |
o = findopt(c); |
if (o == NULL) |
if (o == NULL) |
|
|
opt_prompt(c) |
opt_prompt(c) |
int c; |
int c; |
{ |
{ |
struct option *o; |
register struct loption *o; |
|
|
o = findopt(c); |
o = findopt(c); |
if (o == NULL || (o->otype & (STRING|NUMBER)) == 0) |
if (o == NULL || (o->otype & (STRING|NUMBER)) == 0) |
|
|
* Print error message about missing string. |
* Print error message about missing string. |
*/ |
*/ |
static void |
static void |
nostring(c) |
nostring(printopt) |
int c; |
char *printopt; |
{ |
{ |
PARG parg; |
PARG parg; |
parg.p_string = propt(c); |
parg.p_string = printopt; |
error("String is required after %s", &parg); |
error("Value is required after %s", &parg); |
} |
} |
|
|
/* |
/* |
|
|
public void |
public void |
nopendopt() |
nopendopt() |
{ |
{ |
nostring(pendopt->oletter); |
nostring(propt(pendopt->oletter)); |
} |
} |
|
|
/* |
/* |
|
|
* Return a pointer to the remainder of the string, if any. |
* Return a pointer to the remainder of the string, if any. |
*/ |
*/ |
static char * |
static char * |
optstring(s, c) |
optstring(s, p_str, printopt, validchars) |
char *s; |
char *s; |
int c; |
char **p_str; |
|
char *printopt; |
|
char *validchars; |
{ |
{ |
char *p; |
register char *p; |
|
|
if (*s == '\0') |
if (*s == '\0') |
{ |
{ |
nostring(c); |
nostring(printopt); |
quit(QUIT_ERROR); |
quit(QUIT_ERROR); |
} |
} |
|
*p_str = s; |
for (p = s; *p != '\0'; p++) |
for (p = s; *p != '\0'; p++) |
if (*p == END_OPTION_STRING) |
{ |
|
if (*p == END_OPTION_STRING || |
|
(validchars != NULL && strchr(validchars, *p) == NULL)) |
{ |
{ |
*p = '\0'; |
switch (*p) |
return (p+1); |
{ |
|
case END_OPTION_STRING: |
|
case ' ': case '\t': case '-': |
|
/* Replace the char with a null to terminate string. */ |
|
*p++ = '\0'; |
|
break; |
|
default: |
|
/* Cannot replace char; make a copy of the string. */ |
|
*p_str = (char *) ecalloc(p-s+1, sizeof(char)); |
|
strncpy(*p_str, s, p-s); |
|
(*p_str)[p-s] = '\0'; |
|
break; |
|
} |
|
break; |
} |
} |
|
} |
return (p); |
return (p); |
} |
} |
|
|
|
|
* the char * to point after the translated number. |
* the char * to point after the translated number. |
*/ |
*/ |
public int |
public int |
getnum(sp, c, errp) |
getnum(sp, printopt, errp) |
char **sp; |
char **sp; |
int c; |
char *printopt; |
int *errp; |
int *errp; |
{ |
{ |
char *s; |
register char *s; |
int n; |
register int n; |
int neg; |
register int neg; |
PARG parg; |
PARG parg; |
|
|
s = skipsp(*sp); |
s = skipsp(*sp); |
|
|
*errp = TRUE; |
*errp = TRUE; |
return (-1); |
return (-1); |
} |
} |
parg.p_string = propt(c); |
if (printopt != NULL) |
error("Number is required after %s", &parg); |
{ |
|
parg.p_string = printopt; |
|
error("Number is required after %s", &parg); |
|
} |
quit(QUIT_ERROR); |
quit(QUIT_ERROR); |
} |
} |
|
|