[master] efdca94ee Give SF_Parse_{Decimal|Number} a 'strict' argument so we can relax them.
Poul-Henning Kamp
phk at FreeBSD.org
Wed Jun 2 11:46:05 UTC 2021
commit efdca94eec5e7cd933f9713d2468620f800f08b8
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date: Wed Jun 2 10:18:37 2021 +0000
Give SF_Parse_{Decimal|Number} a 'strict' argument so we can relax them.
Add test-coverage of internal function sf_parse_int()
diff --git a/include/vnum.h b/include/vnum.h
index 859d8cbb0..6016d325e 100644
--- a/include/vnum.h
+++ b/include/vnum.h
@@ -40,8 +40,8 @@ int64_t VNUM_bytes_unit(double r, const char *b, const char *e, uintmax_t rel,
const char *VNUM_2bytes(const char *p, uintmax_t *r, uintmax_t rel);
int64_t SF_Parse_Integer(const char **ipp, const char **errtxt);
-double SF_Parse_Decimal(const char **ipp, const char **errtxt);
-double SF_Parse_Number(const char **ipp, const char **errtxt);
+double SF_Parse_Decimal(const char **ipp, int strict, const char **errtxt);
+double SF_Parse_Number(const char **ipp, int strict, const char **errtxt);
#define VNUM_LEGAL_DURATION \
"Legal duration units are 'ms', 's', 'm', 'h', 'd', 'w' and 'y'"
diff --git a/lib/libvarnish/vnum.c b/lib/libvarnish/vnum.c
index ce66fc7e1..cf532eaf0 100644
--- a/lib/libvarnish/vnum.c
+++ b/lib/libvarnish/vnum.c
@@ -56,22 +56,24 @@ static const char err_fractional_bytes[] = "Fractional BYTES not allowed";
if (errtxt != NULL) \
*errtxt = (txt); \
errno = EINVAL; \
- return (0); \
+ return (retval); \
} while (0)
static int64_t
-sf_parse_int(const char **ipp, const char **errtxt, int maxdig)
+sf_parse_int(const char **ipp, const char **errtxt, int *sign, int maxdig)
{
int64_t retval = 0;
- int negative = 0, ndig = 0;
+ int ndig = 0;
AN(ipp);
AN(*ipp);
+ *errtxt = NULL;
+ *sign = 1;
errno = 0;
while (vct_isows(*(*ipp)))
(*ipp)++;
if(*(*ipp) == '-') {
- negative = 1;
+ *sign = -1;
(*ipp)++;
}
while (vct_isdigit(*(*ipp))) {
@@ -81,34 +83,37 @@ sf_parse_int(const char **ipp, const char **errtxt, int maxdig)
retval *= 10;
retval += *(*ipp)++ - 0x30;
}
+ if (ndig == 0)
+ BAIL(*sign < 0 ? err_invalid_num : err_miss_num);
while (vct_isows(*(*ipp)))
(*ipp)++;
- if (ndig == 0)
- BAIL(negative ? err_invalid_num : err_miss_num);
- if (negative)
- retval = -retval;
return (retval);
}
int64_t
SF_Parse_Integer(const char **ipp, const char **errtxt)
{
+ int64_t retval;
+ int sign;
- return(sf_parse_int(ipp, errtxt, 15));
+ retval = sf_parse_int(ipp, errtxt, &sign, 15);
+ return(retval * sign);
}
double
-SF_Parse_Decimal(const char **ipp, const char **errtxt)
+SF_Parse_Number(const char **ipp, int strict, const char **errtxt)
{
double retval, scale = 1;
- int ndig;
+ int sign, ndig;
- retval = (double)sf_parse_int(ipp, errtxt, 12);
- if (retval < 0)
- scale = -scale;
+ retval = (double)sf_parse_int(ipp, errtxt, &sign, 15);
+ if (strict && errno)
+ return (0);
do {
if (*(*ipp) != '.')
break;
+ if (retval < VRT_DECIMAL_MIN || retval > VRT_DECIMAL_MAX)
+ BAIL(err_fatnum);
(*ipp)++;
for(ndig = 0; ndig < 3; ndig++) {
scale *= .1;
@@ -116,40 +121,26 @@ SF_Parse_Decimal(const char **ipp, const char **errtxt)
break;
retval += scale * (*(*ipp)++ - 0x30);
}
- if (vct_isdigit(*(*ipp)))
+ if (strict && vct_isdigit(*(*ipp)))
BAIL(err_fatnum);
+ while (vct_isdigit(*(*ipp)))
+ (*ipp)++;
} while (0);
while (vct_isows(*(*ipp)))
(*ipp)++;
- return (retval);
+ return (retval * sign);
}
double
-SF_Parse_Number(const char **ipp, const char **errtxt)
+SF_Parse_Decimal(const char **ipp, int strict, const char **errtxt)
{
- double retval, scale = 1;
- int ndig;
+ double retval;
- retval = (double)sf_parse_int(ipp, errtxt, 15);
- if (retval < 0)
- scale = -scale;
- do {
- if (*(*ipp) != '.')
- break;
- if (retval < -999999999999 || retval > 999999999999)
- BAIL(err_fatnum);
- (*ipp)++;
- for(ndig = 0; ndig < 3; ndig++) {
- scale *= .1;
- if (!vct_isdigit(*(*ipp)))
- break;
- retval += scale * (*(*ipp)++ - 0x30);
- }
- if (vct_isdigit(*(*ipp)))
- BAIL(err_fatnum);
- } while (0);
- while (vct_isows(*(*ipp)))
- (*ipp)++;
+ retval = SF_Parse_Number(ipp, strict, errtxt);
+ if (errno)
+ return(retval);
+ if (retval < VRT_DECIMAL_MIN || retval > VRT_DECIMAL_MAX)
+ BAIL(err_fatnum);
return (retval);
}
@@ -343,7 +334,7 @@ VNUM_2bytes(const char *p, uintmax_t *r, uintmax_t rel)
if (p == NULL || *p == '\0')
return (err_miss_num);
- fval = SF_Parse_Number(&p, &errtxt);
+ fval = SF_Parse_Number(&p, 1, &errtxt);
if (errno)
return(errtxt);
if (fval < 0)
@@ -362,6 +353,28 @@ VNUM_2bytes(const char *p, uintmax_t *r, uintmax_t rel)
* cc -o foo -DNUM_C_TEST -I../.. -I../../include vnum.c vas.c vct.c -lm
*/
+static const struct test_sf_parse_int {
+ const char *input;
+ int maxdig;
+ int64_t retval;
+ int consumed;
+ int sign;
+ const char *errtxt;
+} test_sf_parse_int[] = {
+ { "1234", 3, 123, 3, 1, err_fatnum },
+ { "1234", 4, 1234, 4, 1, NULL },
+ { "1234", 5, 1234, 4, 1, NULL },
+ { "-", 5, 0, 1, -1, err_invalid_num },
+ { "-1234", 3, 123, 4, -1, err_fatnum },
+ { "-1234", 4, 1234, 5, -1, NULL },
+ { "-1234", 5, 1234, 5, -1, NULL },
+ { " -1234", 5, 1234, 6, -1, NULL },
+ { " -1234 ", 5, 1234, 7, -1, NULL },
+ { " -12 34 ", 5, 12, 5, -1, NULL },
+ { " - 12 34 ", 5, 0, 2, -1, err_invalid_num },
+ { NULL},
+};
+
static struct test_case {
const char *str;
uintmax_t rel;
@@ -460,11 +473,40 @@ main(int argc, char *argv[])
const char **p;
const char *e;
double d1, d2;
+ const struct test_sf_parse_int *tspi;
+ int64_t i64;
+ int sign, consumed;
+ const char *errtxt;
+ const char *input;
(void)argc;
setbuf(stdout, NULL);
setbuf(stderr, NULL);
+
+ for (tspi = test_sf_parse_int; tspi->input != NULL; tspi++) {
+ errtxt = "(unset)";
+ input = tspi->input;
+ i64 = sf_parse_int(&input, &errtxt, &sign, tspi->maxdig);
+ consumed = input - tspi->input;
+ if (i64 != tspi->retval ||
+ sign != tspi->sign ||
+ consumed != tspi->consumed ||
+ errtxt != tspi->errtxt) {
+ ec++;
+ printf("sf_parse_int(%s, maxdig=%d) failed\n",
+ tspi->input, tspi->maxdig);
+ printf(" retval\texpected %jd\tgot %jd\n",
+ (intmax_t)tspi->retval, (intmax_t)i64);
+ printf(" sign\texpected %d\tgot %d\n",
+ tspi->sign, sign);
+ printf(" consumed\texpected %d\tgot %d\n",
+ tspi->consumed, consumed);
+ printf(" errtxt\texpected %s\tgot %s\n",
+ tspi->errtxt, errtxt);
+ }
+ }
+
for (p = vec; *p != NULL; p++) {
e = *p;
d1 = VNUM(e + 1);
diff --git a/vmod/vmod_std_conversions.c b/vmod/vmod_std_conversions.c
index 9aaf9a8cf..cbf9c929a 100644
--- a/vmod/vmod_std_conversions.c
+++ b/vmod/vmod_std_conversions.c
@@ -168,7 +168,7 @@ vmod_integer(VRT_CTX, struct VARGS(integer) *a)
if (a->valid_s && a->s != NULL) {
p = a->s;
- r = SF_Parse_Number(&p, &errtxt);
+ r = SF_Parse_Number(&p, 1, &errtxt);
if (!errno && *p == '\0' && modf(r, &tmp) == 0.0)
return (r);
r = NAN;
@@ -267,7 +267,7 @@ vmod_real(VRT_CTX, struct VARGS(real) *a)
if (a->valid_s && a->s != NULL) {
p = a->s;
- r = SF_Parse_Decimal(&p, &errtxt);
+ r = SF_Parse_Decimal(&p, 1, &errtxt);
if (!errno && *p == '\0')
return (r);
}
More information about the varnish-commit
mailing list