Skip to content

Commit

Permalink
Fully implement and test non-strict mode SF_Parse()
Browse files Browse the repository at this point in the history
  • Loading branch information
bsdphk committed Jun 2, 2021
1 parent efdca94 commit 05e10ee
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 34 deletions.
108 changes: 95 additions & 13 deletions lib/libvarnish/vnum.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,15 @@
#include "vas.h"
#include "vct.h"

static const char err_miss_num[] = "Missing number";
static const char err_fatnum[] = "Too many digits";
/* The distinction between these two is used internally */
static const char err_invalid_num[] = "Invalid number";
static const char err_no_digits[] = "Invalid number";

static const char err_fatnum[] = "Too many digits";

static const char err_unknown_bytes[] =
"Unknown BYTES unit of measurement ([KMGTP][B])";

static const char err_fractional_bytes[] = "Fractional BYTES not allowed";

#define BAIL(txt) \
Expand Down Expand Up @@ -84,7 +88,7 @@ sf_parse_int(const char **ipp, const char **errtxt, int *sign, int maxdig)
retval += *(*ipp)++ - 0x30;
}
if (ndig == 0)
BAIL(*sign < 0 ? err_invalid_num : err_miss_num);
BAIL(err_no_digits);
while (vct_isows(*(*ipp)))
(*ipp)++;
return (retval);
Expand All @@ -109,18 +113,24 @@ SF_Parse_Number(const char **ipp, int strict, const char **errtxt)
retval = (double)sf_parse_int(ipp, errtxt, &sign, 15);
if (strict && errno)
return (0);
if (*(*ipp) != '.')
return (retval * sign);
if (retval < VRT_DECIMAL_MIN || retval > VRT_DECIMAL_MAX)
BAIL(err_fatnum);
if (*errtxt == err_no_digits && (!vct_isdigit((*ipp)[1])))
BAIL(err_no_digits);
*errtxt = NULL;
errno = 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;
if (!vct_isdigit(*(*ipp)))
break;
retval += scale * (*(*ipp)++ - 0x30);
}
if (strict && ndig == 0)
BAIL(err_invalid_num);
if (strict && vct_isdigit(*(*ipp)))
BAIL(err_fatnum);
while (vct_isdigit(*(*ipp)))
Expand Down Expand Up @@ -332,7 +342,7 @@ VNUM_2bytes(const char *p, uintmax_t *r, uintmax_t rel)
const char *errtxt;

if (p == NULL || *p == '\0')
return (err_miss_num);
return (err_invalid_num);

fval = SF_Parse_Number(&p, 1, &errtxt);
if (errno)
Expand Down Expand Up @@ -364,14 +374,50 @@ static const struct 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 },
{ "-", 5, 0, 1, -1, err_no_digits },
{ " ", 5, 0, 2, 1, err_no_digits },
{ "-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 },
{ " - 12 34 ", 5, 0, 2, -1, err_no_digits },
{ NULL},
};

static const struct test_sf_parse_number {
const char *input;
int strict;
double retval;
int consumed;
const char *errtxt;
} test_sf_parse_number[] = {
{ "1234", 1, 1234.000, 4, NULL },
{ " 1234", 1, 1234.000, 5, NULL },
{ " 1234 ", 1, 1234.000, 6, NULL },
{ " 1234. ", 1, 1234.000, 6, err_invalid_num },
{ " 123456789012.0 ", 1, 123456789012.000, 16, NULL },
{ " 1234567890123.0 ", 1, 1234567890123.000, 14, err_fatnum },
{ " 123456789012.123 ", 1, 123456789012.123, 18, NULL },
{ " 123456789012.1234 ",1, 123456789012.123, 17, err_fatnum },
{ " -0.123456 ", 1, .123, 7, err_fatnum },
{ " -.123456 ", 1, 0., 2, err_no_digits },
{ " .123456 ", 1, 0., 1, err_no_digits },
{ " 0. ", 1, 0., 3, err_invalid_num },
{ " .0 ", 1, 0., 1, err_no_digits },

{ " 123456789012.1234 ",0, 123456789012.123, 19, NULL },
{ " -0.123456 ", 0, -.123, 11, NULL },
{ " -.123456 ", 0, -.123, 10, NULL },
{ " .123456 ", 0, .123, 9, NULL },
{ " 0. ", 0, 0., 4, NULL },
{ " .0 ", 0, 0., 4, NULL },
{ " -0. ", 0, -0., 5, NULL },
{ " -.0 ", 0, -0., 5, NULL },
{ " - ", 0, -0., 2, err_no_digits },
{ " -. ", 0, 0., 2, err_no_digits },
{ " . ", 0, 0., 1, err_no_digits },
{ NULL},
};

Expand Down Expand Up @@ -425,12 +471,12 @@ static struct test_case {
{ "3%", (uintmax_t)1024, (uintmax_t)30 },

/* Check the error checks */
{ "", 0, 0, err_miss_num },
{ "", 0, 0, err_invalid_num },
{ "-1", 0, 0, err_invalid_num },
{ "1.3", 0, 0, err_fractional_bytes},
{ "1.5011%", 0, 0, err_fatnum },
{ "-", 0, 0, err_invalid_num },
{ "m", 0, 0, err_miss_num },
{ "-", 0, 0, err_no_digits },
{ "m", 0, 0, err_no_digits },
{ "4%", 0, 0, err_unknown_bytes },
{ "3*", 0, 0, err_unknown_bytes },

Expand Down Expand Up @@ -474,10 +520,14 @@ main(int argc, char *argv[])
const char *e;
double d1, d2;
const struct test_sf_parse_int *tspi;
const struct test_sf_parse_number *tspn;
int64_t i64;
volatile double dbl;
int sign, consumed;
const char *errtxt;
const char *input;
char buf1[30];
char buf2[30];

(void)argc;

Expand All @@ -502,11 +552,43 @@ main(int argc, char *argv[])
tspi->sign, sign);
printf(" consumed\texpected %d\tgot %d\n",
tspi->consumed, consumed);
printf(" errtxt\texpected %p\tgot %p\n",
tspi->errtxt, errtxt);
printf(" errtxt\texpected %s\tgot %s\n",
tspi->errtxt, errtxt);
}
}

for (tspn = test_sf_parse_number; tspn->input != NULL; tspn++) {
errtxt = "(unset)";
input = tspn->input;
dbl = SF_Parse_Number(&input, tspn->strict, &errtxt);
consumed = input - tspn->input;
bprintf(buf1, "%.4f", dbl);
bprintf(buf2, "%.4f", tspn->retval);
if (strcmp(buf1, buf2) ||
consumed != tspn->consumed ||
errtxt != tspn->errtxt) {
ec++;
printf("sf_parse_number(%s, strict=%d) failed\n",
tspn->input, tspn->strict);
printf(" retval\texpected %.4f\tgot %.4f\t(%e)\n",
tspn->retval, dbl, dbl - tspn->retval);
printf(" retval\texpected %a\tgot %a\n",
tspn->retval, dbl);
printf(" retval\texpected %s\tgot %s\n",
buf2, buf1);
printf(" retval\tdelta %e\n",
dbl - tspn->retval);
printf(" consumed\texpected %d\tgot %d\n",
tspn->consumed, consumed);
printf(" errtxt\texpected %p\tgot %p\n",
tspn->errtxt, errtxt);
printf(" errtxt\texpected %s\tgot %s\n",
tspn->errtxt, errtxt);
}
}

for (p = vec; *p != NULL; p++) {
e = *p;
d1 = VNUM(e + 1);
Expand Down
25 changes: 6 additions & 19 deletions lib/libvarnishapi/vsl_query.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,7 @@ vslq_test_rec(const struct vex *vex, const struct VSLC_ptr *rec)
const struct vex_rhs *rhs;
long long lhs_int = 0;
double lhs_float = 0.;
const char *b, *e, *q, *t;
char *p;
const char *b, *e, *q;
int i, dq;

AN(vex);
Expand Down Expand Up @@ -208,25 +207,13 @@ vslq_test_rec(const struct vex *vex, const struct VSLC_ptr *rec)
return (0);
switch (rhs->type) {
case VEX_INT:
lhs_int = strtoll(b, &p, 0);
if (*p == '.' || *p == 'e') {
t = ""; /* assume valid float */
lhs_float = VNUMpfx(b, &q);
if (isnan(lhs_float))
return (0);
if (q != NULL)
t = (q > p) ? q - 1 : q;
p = TRUST_ME(t);
lhs_int = (long long)lhs_float;
}
if (*p != '\0' && !isspace(*p))
return (0); /* Can't parse - no match */
lhs_int = (long long)SF_Parse_Number(&b, 0, &q);
if (errno)
return (0);
break;
case VEX_FLOAT:
lhs_float = VNUMpfx(b, &q);
if (isnan(lhs_float))
return (0);
if (q != NULL && q > b && !isspace(q[-1]))
lhs_float = SF_Parse_Decimal(&b, 0, &q);
if (errno)
return (0);
break;
default:
Expand Down
4 changes: 2 additions & 2 deletions vmod/vmod_std_conversions.c
Original file line number Diff line number Diff line change
Expand Up @@ -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, 1, &errtxt);
r = SF_Parse_Number(&p, 0, &errtxt);
if (!errno && *p == '\0' && modf(r, &tmp) == 0.0)
return (r);
r = NAN;
Expand Down Expand Up @@ -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, 1, &errtxt);
r = SF_Parse_Decimal(&p, 0, &errtxt);
if (!errno && *p == '\0')
return (r);
}
Expand Down

0 comments on commit 05e10ee

Please sign in to comment.