mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 15:32:35 +00:00
Tightened syntax checks to discover bad numerical arguments
This commit is contained in:
parent
88cdeed092
commit
893d031cc2
10 changed files with 233 additions and 56 deletions
4
CHANGES
4
CHANGES
|
@ -33,6 +33,10 @@ Corrections:
|
|||
|
||||
Fixed bad parser error message on "socat /tmp/x\"x/x -"
|
||||
|
||||
Tightened syntax checks to detect numerical arguments that are missing
|
||||
or have trailing garbage.
|
||||
Test: INTEGER_GARBAGE
|
||||
|
||||
Porting:
|
||||
OpenSSL, at least 1.1 on Ubuntu, crashed with SIGSEGV under certain
|
||||
conditions: client connection to server with certificate with empty
|
||||
|
|
24
filan_main.c
24
filan_main.c
|
@ -21,7 +21,7 @@ static void filan_usage(FILE *fd);
|
|||
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
const char **arg1, *a;
|
||||
const char **arg1, *a0, *a;
|
||||
const char *filename = NULL, *waittimetxt;
|
||||
unsigned int m = 0; /* first FD (default) */
|
||||
unsigned int n = FD_SETSIZE; /* last excl. */
|
||||
|
@ -50,27 +50,39 @@ int main(int argc, const char *argv[]) {
|
|||
case 'S': style = arg1[0][1]; break;
|
||||
case 'r': filan_rawoutput = true; break;
|
||||
case 'i': if (arg1[0][2]) {
|
||||
a = *arg1+2;
|
||||
a = a0 = *arg1+2;
|
||||
} else {
|
||||
++arg1, --argc;
|
||||
if ((a = *arg1) == NULL) {
|
||||
if ((a = a0 = *arg1) == NULL) {
|
||||
Error("option -i requires an argument");
|
||||
filan_usage(stderr); exit(1);
|
||||
}
|
||||
}
|
||||
m = strtoul(a, (char **)&a, 0);
|
||||
if (a == a0) {
|
||||
Error1("not a numerical arg in \"-b %s\"", a0);
|
||||
}
|
||||
if (*a != '\0') {
|
||||
Error1("trailing garbage in \"-b %s\"", a0);
|
||||
}
|
||||
n = m;
|
||||
break;
|
||||
case 'n': if (arg1[0][2]) {
|
||||
a = *arg1+2;
|
||||
a = a0 = *arg1+2;
|
||||
} else {
|
||||
++arg1, --argc;
|
||||
if ((a = *arg1) == NULL) {
|
||||
if ((a = a0 = *arg1) == NULL) {
|
||||
Error("option -n requires an argument");
|
||||
filan_usage(stderr); exit(1);
|
||||
}
|
||||
}
|
||||
n = strtoul(a, (char **)&a, 0);
|
||||
if (a == a0) {
|
||||
Error1("not a numerical arg in \"-b %s\"", a0);
|
||||
}
|
||||
if (*a != '\0') {
|
||||
Error1("trailing garbage in \"-b %s\"", a0);
|
||||
}
|
||||
break;
|
||||
case 'f': if (arg1[0][2]) {
|
||||
filename = *arg1+2;
|
||||
|
@ -135,7 +147,7 @@ int main(int argc, const char *argv[]) {
|
|||
else if (!strcmp(outfname,"stderr")) { fdout=stderr; }
|
||||
/* file descriptor */
|
||||
else if (*outfname == '+') {
|
||||
a = outfname+1;
|
||||
a = outfname+1;
|
||||
fildes = strtoul(a, (char **)&a, 0);
|
||||
if ((fdout = fdopen(fildes, "w")) == NULL) {
|
||||
Error2("can't fdopen file descriptor %lu: %s\n", fildes, strerror(errno));
|
||||
|
|
6
socat.c
6
socat.c
|
@ -238,7 +238,7 @@ int main(int argc, const char *argv[]) {
|
|||
Exit(1);
|
||||
}
|
||||
}
|
||||
socat_opts.bufsiz = strtoul(a, (char **)&a, 0);
|
||||
socat_opts.bufsiz = Strtoul(a, (char **)&a, 0, "-b");
|
||||
break;
|
||||
case 's': if (arg1[0][2]) { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
|
||||
diag_set_int('e', E_FATAL); break;
|
||||
|
@ -251,7 +251,7 @@ int main(int argc, const char *argv[]) {
|
|||
Exit(1);
|
||||
}
|
||||
}
|
||||
rto = strtod(a, (char **)&a);
|
||||
rto = Strtod(a, (char **)&a, "-t");
|
||||
socat_opts.closwait.tv_sec = rto;
|
||||
socat_opts.closwait.tv_usec =
|
||||
(rto-socat_opts.closwait.tv_sec) * 1000000;
|
||||
|
@ -265,7 +265,7 @@ int main(int argc, const char *argv[]) {
|
|||
Exit(1);
|
||||
}
|
||||
}
|
||||
rto = strtod(a, (char **)&a);
|
||||
rto = Strtod(a, (char **)&a, "-T");
|
||||
socat_opts.total_timeout.tv_sec = rto;
|
||||
socat_opts.total_timeout.tv_usec =
|
||||
(rto-socat_opts.total_timeout.tv_sec) * 1000000;
|
||||
|
|
1
sycls.c
1
sycls.c
|
@ -1736,6 +1736,7 @@ void Unsetenv(const char *name) {
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if WITH_READLINE
|
||||
|
||||
char *Readline(const char *prompt) {
|
||||
|
|
2
sycls.h
2
sycls.h
|
@ -167,6 +167,8 @@ void Abort(void);
|
|||
int Mkstemp(char *template);
|
||||
int Setenv(const char *name, const char *value, int overwrite);
|
||||
void Unsetenv(const char *name);
|
||||
#endif /* WITH_SYCLS */
|
||||
#if WITH_SYCLS
|
||||
|
||||
char *Readline(const char *prompt);
|
||||
void Using_history(void);
|
||||
|
|
42
sysutils.c
42
sysutils.c
|
@ -824,3 +824,45 @@ int xiosetenvushort(const char *varname, unsigned short value, int overwrite) {
|
|||
return xiosetenv(varname, envbuff, overwrite, NULL);
|
||||
# undef XIO_SHORTLEN
|
||||
}
|
||||
|
||||
|
||||
unsigned long int Strtoul(const char *nptr, char **endptr, int base, const char *txt) {
|
||||
unsigned long res;
|
||||
|
||||
res = strtoul(nptr, endptr, base);
|
||||
if (nptr == *endptr) {
|
||||
Error1("parseopts(): missing numerical value of option \"%s\"", txt);
|
||||
}
|
||||
if (**endptr != '\0') {
|
||||
Error1("parseopts(): trailing garbage in numerical arg of option \"%s\"", txt);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
#if HAVE_STRTOLL
|
||||
long long int Strtoll(const char *nptr, char **endptr, int base, const char *txt) {
|
||||
long long int res;
|
||||
|
||||
res = strtoul(nptr, endptr, base);
|
||||
if (nptr == *endptr) {
|
||||
Error1("parseopts(): missing numerical value of option \"%s\"", txt);
|
||||
}
|
||||
if (**endptr != '\0') {
|
||||
Error1("parseopts(): trailing garbage in numerical arg of option \"%s\"", txt);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif /* HAVE_STRTOLL */
|
||||
|
||||
double Strtod(const char *nptr, char **endptr, const char *txt) {
|
||||
double res;
|
||||
|
||||
res = strtod(nptr, endptr);
|
||||
if (nptr == *endptr) {
|
||||
Error1("parseopts(): missing numerical value of option \"%s\"", txt);
|
||||
}
|
||||
if (**endptr != '\0') {
|
||||
Error1("parseopts(): trailing garbage in numerical arg of option \"%s\"", txt);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -107,5 +107,8 @@ extern int xiosetenvulong(const char *varname, unsigned long value,
|
|||
int overwrite);
|
||||
extern int xiosetenvushort(const char *varname, unsigned short value,
|
||||
int overwrite);
|
||||
extern unsigned long int Strtoul(const char *nptr, char **endptr, int base, const char *txt);
|
||||
extern long long int Strtoll(const char *nptr, char **endptr, int base, const char *txt);
|
||||
extern double Strtod(const char *nptr, char **endptr, const char *txt);
|
||||
|
||||
#endif /* !defined(__sysutils_h_included) */
|
||||
|
|
67
test.sh
67
test.sh
|
@ -13886,7 +13886,7 @@ N=$((N+1))
|
|||
# Test if unbalanced quoting in Socat addresses is detected
|
||||
NAME=UNBALANCED_QUOTE
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%bugs%*|*%$NAME%*)
|
||||
*%$N%*|*%functions%*|*%syntax%*|*%bugs%*|*%$NAME%*)
|
||||
TEST="$NAME: Test fix of unbalanced quoting"
|
||||
# Invoke Socat with an address containing unbalanced quoting. If Socat prints
|
||||
# a "syntax error" message, the test succeeds
|
||||
|
@ -13900,6 +13900,8 @@ printf "test $F_n $TEST... " $N
|
|||
$CMD0 >/dev/null 2>"${te}0"
|
||||
if grep -q "syntax error" "${te}0"; then
|
||||
$PRINTF "$OK\n"
|
||||
if [ "$VERBOSE" ]; then echo "$CMD0" >&2; fi
|
||||
if [ "$debug" ]; then cat ${te} >&2; fi
|
||||
numOK=$((numOK+1))
|
||||
else
|
||||
$PRINTF "$FAILED\n"
|
||||
|
@ -15537,6 +15539,69 @@ esac
|
|||
PORT=$((PORT+1))
|
||||
N=$((N+1))
|
||||
|
||||
# Test if trailing garbage in integer type options gives error
|
||||
NAME=MISSING_INTEGER
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%syntax%*|*%bugs%*|*%$NAME%*)
|
||||
TEST="$NAME: Error on option that's missing integer value"
|
||||
# Invoke Socat with pty and option ispeed=b19200.
|
||||
# When socat terminates with error the test succeeded
|
||||
if ! eval $NUMCOND; then :; else
|
||||
tf="$td/test$N.stdout"
|
||||
te="$td/test$N.stderr"
|
||||
tdiff="$td/test$N.diff"
|
||||
da="test$N $(date) $RANDOM"
|
||||
CMD0="$TRACE $SOCAT $opts - PTY,ispeed=b19200"
|
||||
printf "test $F_n $TEST... " $N
|
||||
$CMD0 </dev/null >/dev/null 2>"${te}0"
|
||||
if grep -q "missing numerical value" "${te}0"; then
|
||||
$PRINTF "$OK\n"
|
||||
numOK=$((numOK+1))
|
||||
else
|
||||
$PRINTF "$FAILED\n"
|
||||
echo "$CMD0"
|
||||
cat "${te}0"
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
fi
|
||||
fi # NUMCOND
|
||||
;;
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
# Test if trailing garbage in integer type options gives error
|
||||
NAME=INTEGER_GARBAGE
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%syntax%*|*%bugs%*|*%$NAME%*)
|
||||
TEST="$NAME: Error on trailing garbabe"
|
||||
# Invoke Socat with pty and option ispeed=b19200.
|
||||
# When socat terminates with error the test succeeded
|
||||
if ! eval $NUMCOND; then :; else
|
||||
tf="$td/test$N.stdout"
|
||||
te="$td/test$N.stderr"
|
||||
tdiff="$td/test$N.diff"
|
||||
da="test$N $(date) $RANDOM"
|
||||
CMD0="$TRACE $SOCAT $opts - PTY,ispeed=19200B"
|
||||
printf "test $F_n $TEST... " $N
|
||||
$CMD0 </dev/null >/dev/null 2>"${te}0"
|
||||
if grep -q "trailing garbage" "${te}0"; then
|
||||
$PRINTF "$OK\n"
|
||||
if [ "$VERBOSE" ]; then echo "$CMD0" >&2; fi
|
||||
if [ "$debug" ]; then cat ${te} >&2; fi
|
||||
numOK=$((numOK+1))
|
||||
else
|
||||
$PRINTF "$FAILED\n"
|
||||
echo "$CMD0"
|
||||
cat "${te}0"
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
fi
|
||||
fi # NUMCOND
|
||||
;;
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
|
||||
# end of common tests
|
||||
|
||||
##################################################################################
|
||||
|
|
2
utils.c
2
utils.c
|
@ -160,7 +160,7 @@ char *xiosubstr(char *scratch, const char *str, size_t from, size_t len) {
|
|||
*scratch = '\0';
|
||||
return scratch0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* since version 1.7.2.4 socat supports C-99 behaviour of snprintf but still
|
||||
can handle the old glibc case with -1 return on truncation.
|
||||
|
|
138
xioopts.c
138
xioopts.c
|
@ -1926,7 +1926,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
nestlex(a, &tokp, &len, endkey, hquotes, squotes, nests,
|
||||
true, true, false);
|
||||
if (parsres < 0) {
|
||||
Error1("option too long: \"%s\"", *a);
|
||||
Error1("option too long: \"%s\"", *a);
|
||||
return -1;
|
||||
} else if (parsres > 0) {
|
||||
Error1("syntax error in \"%s\"", *a);
|
||||
|
@ -2006,9 +2006,9 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
if (assign) {
|
||||
unsigned long ul;
|
||||
char *rest;
|
||||
ul = strtoul(token, &rest/*!*/, 0);
|
||||
ul = Strtoul(token, &rest, 0, a0);
|
||||
if (ul > UCHAR_MAX) {
|
||||
Error3("parseopts_table(%s): byte value exceeds limit (%lu vs. %u), using max",
|
||||
Error3("parseopts(): option \"%s\": byte value exceeds limit (%lu vs. %u), using max",
|
||||
a0, ul, UCHAR_MAX);
|
||||
(*opts)[i].value.u_byte = UCHAR_MAX;
|
||||
} else {
|
||||
|
@ -2026,7 +2026,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
case TYPE_INT:
|
||||
if (assign) {
|
||||
char *rest;
|
||||
(*opts)[i].value.u_int = strtoul(token, &rest/*!*/, 0);
|
||||
(*opts)[i].value.u_int = Strtoul(token, &rest, 0, a0);
|
||||
} else {
|
||||
(*opts)[i].value.u_int = 1;
|
||||
}
|
||||
|
@ -2038,10 +2038,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
(*opts)[i].value.u_bool = 1;
|
||||
} else {
|
||||
char *rest;
|
||||
(*opts)[i].value.u_bool = strtoul(token, &rest, 0);
|
||||
if (rest && *rest) {
|
||||
Error1("error in option \"%s\": \"0\" or \"1\" required", a0);
|
||||
}
|
||||
(*opts)[i].value.u_bool = Strtoul(token, &rest, 0, a0);
|
||||
}
|
||||
Info2("setting option \"%s\" to %d", ent->desc->defname,
|
||||
(*opts)[i].value.u_bool);
|
||||
|
@ -2055,11 +2052,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
(*opts)[i].value.u_uint = 1;
|
||||
} else {
|
||||
char *rest;
|
||||
ulongval = strtoul(token, &rest/*!*/, 0);
|
||||
if (ulongval > UINT_MAX) {
|
||||
Error3("parseopts_table(%s): unsigned int value exceeds limit (%lu vs. %u), using max",
|
||||
a0, ulongval, UINT_MAX);
|
||||
}
|
||||
ulongval = Strtoul(token, &rest, 0, a0);
|
||||
(*opts)[i].value.u_uint = ulongval;
|
||||
}
|
||||
Info2("setting option \"%s\" to %u", ent->desc->defname,
|
||||
|
@ -2074,11 +2067,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
(*opts)[i].value.u_ushort = 1;
|
||||
} else {
|
||||
char *rest;
|
||||
ulongval = strtoul(token, &rest/*!*/, 0);
|
||||
if (ulongval > USHRT_MAX) {
|
||||
Error3("parseopts_table(%s): unsigned short value exceeds limit (%lu vs. %u), using max",
|
||||
a0, ulongval, USHRT_MAX);
|
||||
}
|
||||
ulongval = Strtoul(token, &rest, 0, a0);
|
||||
(*opts)[i].value.u_ushort = ulongval;
|
||||
}
|
||||
Info2("setting option \"%s\" to %u", ent->desc->defname,
|
||||
|
@ -2096,7 +2085,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
(*opts)[i].value.u_long = 1;
|
||||
} else {
|
||||
char *rest;
|
||||
slongval = strtol(token, &rest, 0);
|
||||
slongval = Strtoul(token, &rest, 0, a0);
|
||||
(*opts)[i].value.u_long = slongval;
|
||||
}
|
||||
Info2("setting option \"%s\" to %lu", ent->desc->defname,
|
||||
|
@ -2111,7 +2100,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
(*opts)[i].value.u_ulong = 1;
|
||||
} else {
|
||||
char *rest;
|
||||
ulongval = strtoul(token, &rest, 0);
|
||||
ulongval = Strtoul(token, &rest, 0, a0);
|
||||
(*opts)[i].value.u_ulong = ulongval;
|
||||
}
|
||||
Info2("setting option \"%s\" to %lu", ent->desc->defname,
|
||||
|
@ -2131,11 +2120,14 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
} else {
|
||||
char *rest;
|
||||
# if HAVE_STRTOLL
|
||||
slonglongval = strtoll(token, &rest, 0);
|
||||
slonglongval = Strtoll(token, &rest, 0, a0);
|
||||
# else
|
||||
/* in this case, input value range is limited */
|
||||
slonglongval = strtol(token, &rest, 0);
|
||||
slonglongval = Strtol(token, &rest, 0, a0);
|
||||
# endif /* HAVE_STRTOLL */
|
||||
if (*rest != '\0') {
|
||||
Error1("parseopts(): trailing garbage in numerical arg of option \"%s\"", a0);
|
||||
}
|
||||
(*opts)[i].value.u_longlong = slonglongval;
|
||||
}
|
||||
Info2("setting option \"%s\" to %Lu", ent->desc->defname,
|
||||
|
@ -2150,7 +2142,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
}
|
||||
if (isdigit((*token)&0xff)) {
|
||||
char *rest;
|
||||
(*opts)[i].value.u_uidt = strtoul(token, &rest/*!*/, 0);
|
||||
(*opts)[i].value.u_uidt = Strtoul(token, &rest, 0, a0);
|
||||
} else {
|
||||
struct passwd *pwd;
|
||||
if ((pwd = getpwnam(token)) == NULL) {
|
||||
|
@ -2168,7 +2160,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
continue; }
|
||||
if (isdigit((token[0])&0xff)) {
|
||||
char *rest;
|
||||
(*opts)[i].value.u_gidt = strtoul(token, &rest/*!*/, 0);
|
||||
(*opts)[i].value.u_gidt = Strtoul(token, &rest, 0, a0);
|
||||
} else {
|
||||
struct group *grp;
|
||||
grp = getgrnam(token);
|
||||
|
@ -2188,7 +2180,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
}
|
||||
{
|
||||
char *rest;
|
||||
(*opts)[i].value.u_modet = strtoul(token, &rest/*!*/, 8);
|
||||
(*opts)[i].value.u_modet = Strtoul(token, &rest, 8, a0);
|
||||
}
|
||||
Info2("setting option \"%s\" to %u", ent->desc->defname,
|
||||
(*opts)[i].value.u_modet);
|
||||
|
@ -2229,7 +2221,8 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
continue;
|
||||
} else {
|
||||
double val;
|
||||
val = strtod(token, NULL);
|
||||
char *rest;
|
||||
val = Strtod(token, &rest, a0);
|
||||
if (val == HUGE_VAL || val == -HUGE_VAL ||
|
||||
val == 0.0 && errno == ERANGE) {
|
||||
Error2("strtod(\"%s\", NULL): %s", token, strerror(errno));
|
||||
|
@ -2248,7 +2241,8 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
continue;
|
||||
} else {
|
||||
double val;
|
||||
val = strtod(token, NULL);
|
||||
char *rest;
|
||||
val = Strtod(token, &rest, a0);
|
||||
if (val == HUGE_VAL || val == -HUGE_VAL ||
|
||||
val == 0.0 && errno == ERANGE) {
|
||||
Error2("strtod(\"%s\", NULL): %s", token, strerror(errno));
|
||||
|
@ -2270,7 +2264,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
(*opts)[i].value.u_linger.l_onoff = 1;
|
||||
{
|
||||
char *rest;
|
||||
(*opts)[i].value.u_linger.l_linger = strtoul(token, &rest/*!*/, 0);
|
||||
(*opts)[i].value.u_linger.l_linger = Strtoul(token, &rest, 0, a0);
|
||||
}
|
||||
Info3("setting option \"%s\" to {%d,%d}", ent->desc->defname,
|
||||
(*opts)[i].value.u_linger.l_onoff,
|
||||
|
@ -2287,12 +2281,15 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
{
|
||||
char *rest;
|
||||
(*opts)[i].value.u_int = strtoul(token, &rest, 0);
|
||||
if (*rest != ':') {
|
||||
Error1("option \"%s\": 2 arguments required",
|
||||
if (token == rest) {
|
||||
Error1("parseopts(): missing numerical value of option \"%s\"", a0);
|
||||
}
|
||||
if (*rest == '\0') {
|
||||
Error1("parseopts(): option \"%s\": 2 arguments required",
|
||||
ent->desc->defname);
|
||||
}
|
||||
++rest;
|
||||
(*opts)[i].value2.u_int = strtoul(rest, &rest, 0);
|
||||
(*opts)[i].value2.u_int = Strtoul(rest, &rest, 0, a0);
|
||||
}
|
||||
Info3("setting option \"%s\" to %d:%d", ent->desc->defname,
|
||||
(*opts)[i].value.u_int, (*opts)[i].value2.u_int);
|
||||
|
@ -2306,8 +2303,14 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
{
|
||||
char *rest;
|
||||
(*opts)[i].value.u_int = strtoul(token, &rest, 0);
|
||||
if (token == rest) {
|
||||
Error1("parseopts(): missing numerical value of option \"%s\"", a0);
|
||||
}
|
||||
if (*rest != ':') {
|
||||
Error1("option \"%s\": 2 arguments required",
|
||||
Error1("parseopts(): trailing garbage in numerical arg of option \"%s\"", a0);
|
||||
}
|
||||
if (*rest == '\0') {
|
||||
Error1("parseopts(): option \"%s\": 2 arguments required",
|
||||
ent->desc->defname);
|
||||
}
|
||||
++rest;
|
||||
|
@ -2334,8 +2337,14 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
{
|
||||
char *rest;
|
||||
(*opts)[i].value.u_int = strtoul(token, &rest, 0);
|
||||
if (token == rest) {
|
||||
Error1("parseopts(): missing numerical value of option \"%s\"", a0);
|
||||
}
|
||||
if (*rest != ':') {
|
||||
Error1("option \"%s\": 2 arguments required",
|
||||
Error1("parseopts(): trailing garbage in numerical arg of option \"%s\"", a0);
|
||||
}
|
||||
if (*rest == '\0') {
|
||||
Error1("parseopts(): option \"%s\": 2 arguments required",
|
||||
ent->desc->defname);
|
||||
}
|
||||
++rest;
|
||||
|
@ -2355,18 +2364,28 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
{
|
||||
char *rest;
|
||||
(*opts)[i].value.u_int = strtoul(token, &rest, 0);
|
||||
if (token == rest) {
|
||||
Error1("parseopts(): missing numerical value of option \"%s\"", a0);
|
||||
}
|
||||
if (*rest == '\0') {
|
||||
Error1("parseopts(): option \"%s\": 3 arguments required", ent->desc->defname);
|
||||
}
|
||||
if (*rest != ':') {
|
||||
Error1("option \"%s\": 3 arguments required",
|
||||
ent->desc->defname);
|
||||
Error1("parseopts(): trailing garbage in 1st numerical arg of option \"%s\"", a0);
|
||||
}
|
||||
++rest;
|
||||
(*opts)[i].value2.u_int = strtoul(rest, &rest, 0);
|
||||
if (token == rest) {
|
||||
Error1("parseopts(): missing numerical value of option \"%s\"", a0);
|
||||
}
|
||||
if (*rest == '\0') {
|
||||
Error1("parseopts(): option \"%s\": 3 arguments required", ent->desc->defname);
|
||||
}
|
||||
if (*rest != ':') {
|
||||
Error1("option \"%s\": 3 arguments required",
|
||||
ent->desc->defname);
|
||||
Error1("parseopts(): trailing garbage in 2nd numerical arg of option \"%s\"", a0);
|
||||
}
|
||||
++rest;
|
||||
(*opts)[i].value3.u_int = strtoul(rest, &rest, 0);
|
||||
(*opts)[i].value3.u_int = Strtoul(rest, &rest, 0, a0);
|
||||
}
|
||||
Info4("setting option \"%s\" to %d:%d:%d", ent->desc->defname,
|
||||
(*opts)[i].value.u_int, (*opts)[i].value2.u_int, (*opts)[i].value3.u_int);
|
||||
|
@ -2381,16 +2400,28 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
{
|
||||
char *rest;
|
||||
(*opts)[i].value.u_int = strtoul(token, &rest, 0);
|
||||
if (*rest != ':') {
|
||||
if (token == rest) {
|
||||
Error1("parseopts(): missing numerical value of option \"%s\"", a0);
|
||||
}
|
||||
if (*rest == '\0') {
|
||||
Error1("option \"%s\": 3 arguments required",
|
||||
ent->desc->defname);
|
||||
}
|
||||
if (*rest != ':') {
|
||||
Error1("parseopts(): trailing garbage in 1st numerical arg of option \"%s\"", a0);
|
||||
}
|
||||
++rest;
|
||||
(*opts)[i].value2.u_int = strtoul(rest, &rest, 0);
|
||||
if (*rest != ':') {
|
||||
if (token == rest) {
|
||||
Error1("parseopts(): missing numerical value of option \"%s\"", a0);
|
||||
}
|
||||
if (*rest == '\0') {
|
||||
Error1("option \"%s\": 3 arguments required",
|
||||
ent->desc->defname);
|
||||
}
|
||||
if (*rest != ':') {
|
||||
Error1("parseopts(): trailing garbage in 2nd numerical arg of option \"%s\"", a0);
|
||||
}
|
||||
++rest;
|
||||
optlen = 0;
|
||||
if ((result = dalan(rest, optbuf, &optlen, sizeof(optbuf), 'i')) != 0) {
|
||||
|
@ -2415,16 +2446,28 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
{
|
||||
char *rest;
|
||||
(*opts)[i].value.u_int = strtoul(token, &rest, 0);
|
||||
if (*rest != ':') {
|
||||
Error1("option \"%s\": 3 arguments required",
|
||||
if (token == rest) {
|
||||
Error1("parseopts(): missing numerical value of option \"%s\"", a0);
|
||||
}
|
||||
if (*rest == '\0') {
|
||||
Error1("parseopts(): option \"%s\": 3 arguments required",
|
||||
ent->desc->defname);
|
||||
}
|
||||
if (*rest != ':') {
|
||||
Error1("parseopts(): trailing garbage in 1st numerical arg of option \"%s\"", a0);
|
||||
}
|
||||
++rest;
|
||||
(*opts)[i].value2.u_int = strtoul(rest, &rest, 0);
|
||||
if (*rest != ':') {
|
||||
Error1("option \"%s\": 3 arguments required",
|
||||
if (token == rest) {
|
||||
Error1("parseopts(): missing numerical value of option \"%s\"", a0);
|
||||
}
|
||||
if (*rest == '\0') {
|
||||
Error1("parseopts(): option \"%s\": 3 arguments required",
|
||||
ent->desc->defname);
|
||||
}
|
||||
if (*rest != ':') {
|
||||
Error1("parseopts(): trailing garbage in 2nd numerical arg of option \"%s\"", a0);
|
||||
}
|
||||
++rest;
|
||||
if (((*opts)[i].value3.u_string = strdup(rest)) == NULL) {
|
||||
Error("out of memory"); return -1;
|
||||
|
@ -2873,9 +2916,14 @@ int retropt_int(struct opt *opts, int optcode, int *result) {
|
|||
|
||||
while (opt->desc != ODESC_END) {
|
||||
if (opt->desc != ODESC_DONE && opt->desc->optcode == optcode) {
|
||||
char *rest;
|
||||
switch (opt->desc->type) {
|
||||
case TYPE_INT: *result = opt->value.u_int; break;
|
||||
case TYPE_STRING: *result = strtol(opt->value.u_string, NULL, 0);
|
||||
case TYPE_STRING: *result = strtol(opt->value.u_string, &rest, 0);
|
||||
if (*rest != '\0') {
|
||||
Error1("retropts: trailing garbage in numerical arg of option \"%s\"",
|
||||
opt->desc->defname);
|
||||
}
|
||||
break;
|
||||
default: Error2("cannot convert type %d of option %s to int",
|
||||
opt->desc->type, opt->desc->defname);
|
||||
|
|
Loading…
Reference in a new issue