[master] f543c06b5 Overhaul and unify handling of BYTES suffixes.

Poul-Henning Kamp phk at FreeBSD.org
Tue Jan 29 09:43:08 UTC 2019


commit f543c06b5e65b24e9d701adb0107877c92fb8728
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Tue Jan 29 09:38:35 2019 +0000

    Overhaul and unify handling of BYTES suffixes.
    
    Closes #2882

diff --git a/bin/varnishtest/tests/v00033.vtc b/bin/varnishtest/tests/v00033.vtc
index bbe21d1ee..fcd7e422b 100644
--- a/bin/varnishtest/tests/v00033.vtc
+++ b/bin/varnishtest/tests/v00033.vtc
@@ -43,7 +43,7 @@ varnish v1 -syntax 4.0 -errvcl {Expected BYTES unit (B, KB, MB...) got '"X"'} {
 		}
 	}
 }
-varnish v1 -syntax 4.0 -errvcl {Unknown BYTES unit 'X'.  Legal are 'B', 'KB', 'MB', 'GB' and 'TB'} {
+varnish v1 -syntax 4.0 -errvcl {Unknown BYTES unit 'X'} {
 	sub vcl_recv {
 		if (storage.Transient.free_space > 4 X) {
 		}
diff --git a/include/vnum.h b/include/vnum.h
index ae8a8e1f2..53da2a8e3 100644
--- a/include/vnum.h
+++ b/include/vnum.h
@@ -33,7 +33,11 @@ double VNUM(const char *p);
 double VNUMpfx(const char *p, const char **e);
 vtim_dur VNUM_duration_unit(vtim_dur r, const char *b, const char *e);
 vtim_dur VNUM_duration(const char *p);
+double 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);
 
 #define VNUM_LEGAL_DURATION \
 	"Legal duration units are 'ms', 's', 'm', 'h', 'd', 'w' and 'y'"
+
+#define VNUM_LEGAL_BYTES \
+	"Legal byte units are 'B', 'KB', 'MB', 'GB', 'TB' and 'PB'"
diff --git a/lib/libvarnish/vnum.c b/lib/libvarnish/vnum.c
index 99a81a8f5..43baa7da5 100644
--- a/lib/libvarnish/vnum.c
+++ b/lib/libvarnish/vnum.c
@@ -44,7 +44,6 @@
 
 static const char err_miss_num[] = "Missing number";
 static const char err_invalid_num[] = "Invalid number";
-static const char err_abs_req[] = "Absolute number required";
 static const char err_invalid_suff[] = "Invalid suffix";
 
 /**********************************************************************
@@ -114,7 +113,7 @@ VNUM(const char *p)
 vtim_dur
 VNUM_duration_unit(vtim_dur r, const char *b, const char *e)
 {
-	double sc = 1.0;
+	double sc;
 
 	if (e == NULL)
 		e = strchr(b, '\0');
@@ -126,6 +125,7 @@ VNUM_duration_unit(vtim_dur r, const char *b, const char *e)
 
 	switch (*b++) {
 	case 's':
+		sc = 1.0;
 		break;
 	case 'm':
 		if (b < e && *b == 's') {
@@ -178,6 +178,44 @@ VNUM_duration(const char *p)
 
 /**********************************************************************/
 
+double
+VNUM_bytes_unit(double r, const char *b, const char *e, uintmax_t rel)
+{
+	double sc = 1.0;
+
+	if (e == NULL)
+		e = strchr(b, '\0');
+
+	while (b < e && vct_issp(*b))
+		b++;
+	if (b == e)
+		return (nan(""));
+
+	if (rel != 0 && *b == '%') {
+		r *= rel * 0.01;
+		b++;
+	} else {
+		switch (*b) {
+		case 'k': case 'K': sc = exp2(10); b++; break;
+		case 'm': case 'M': sc = exp2(20); b++; break;
+		case 'g': case 'G': sc = exp2(30); b++; break;
+		case 't': case 'T': sc = exp2(40); b++; break;
+		case 'p': case 'P': sc = exp2(50); b++; break;
+		case 'b': case 'B':
+			break;
+		default:
+			return (nan(""));
+		}
+		if (b < e && (*b == 'b' || *b == 'B'))
+			b++;
+	}
+	while (b < e && vct_issp(*b))
+		b++;
+	if (b < e)
+		return (nan(""));
+	return (sc * r);
+}
+
 const char *
 VNUM_2bytes(const char *p, uintmax_t *r, uintmax_t rel)
 {
@@ -196,48 +234,9 @@ VNUM_2bytes(const char *p, uintmax_t *r, uintmax_t rel)
 		return (NULL);
 	}
 
-	if (end[0] == '%' && end[1] == '\0') {
-		if (rel == 0)
-			return (err_abs_req);
-		fval *= rel / 100.0;
-	} else {
-		/* accept a space before the multiplier */
-		if (end[0] == ' ' && end[1] != '\0')
-			++end;
-
-		switch (end[0]) {
-		case 'k': case 'K':
-			fval *= (uintmax_t)1 << 10;
-			++end;
-			break;
-		case 'm': case 'M':
-			fval *= (uintmax_t)1 << 20;
-			++end;
-			break;
-		case 'g': case 'G':
-			fval *= (uintmax_t)1 << 30;
-			++end;
-			break;
-		case 't': case 'T':
-			fval *= (uintmax_t)1 << 40;
-			++end;
-			break;
-		case 'p': case 'P':
-			fval *= (uintmax_t)1 << 50;
-			++end;
-			break;
-		default:
-			break;
-		}
-
-		/* [bB] is a generic suffix of no effect */
-		if (end[0] == 'b' || end[0] == 'B')
-			end++;
-
-		if (end[0] != '\0')
-			return (err_invalid_suff);
-	}
-
+	fval = VNUM_bytes_unit(fval, end, NULL, rel);
+	if (isnan(fval))
+		return (err_invalid_suff);
 	*r = (uintmax_t)round(fval);
 	return (NULL);
 }
@@ -279,11 +278,11 @@ static struct test_case {
 	{ "1T",			(uintmax_t)0,	(uintmax_t)1<<40 },
 	{ "1TB",		(uintmax_t)0,	(uintmax_t)1<<40 },
 	{ "1.3TB",		(uintmax_t)0,	(uintmax_t)1429365116109ULL },
-	{ "1.7TB",		(uintmax_t)0,	(uintmax_t)1869169767219ULL },
+	{ "1.7\tTB",		(uintmax_t)0,	(uintmax_t)1869169767219ULL },
 
 	{ "1125899906842624",	(uintmax_t)0,	(uintmax_t)1125899906842624ULL},
-	{ "1P",			(uintmax_t)0,	(uintmax_t)1125899906842624ULL},
-	{ "1PB",		(uintmax_t)0,	(uintmax_t)1125899906842624ULL},
+	{ "1P\t",		(uintmax_t)0,	(uintmax_t)1125899906842624ULL},
+	{ "1PB ",		(uintmax_t)0,	(uintmax_t)1125899906842624ULL},
 	{ "1.3 PB",		(uintmax_t)0,	(uintmax_t)1463669878895411ULL},
 
 	{ "1%",			(uintmax_t)1024,	(uintmax_t)10 },
@@ -293,7 +292,7 @@ static struct test_case {
 	/* Check the error checks */
 	{ "",			0,	0,	err_miss_num },
 	{ "m",			0,	0,	err_invalid_num },
-	{ "4%",			0,	0,	err_abs_req },
+	{ "4%",			0,	0,	err_invalid_suff },
 	{ "3*",			0,	0,	err_invalid_suff },
 
 	/* TODO: add more */
diff --git a/lib/libvcc/vcc_utils.c b/lib/libvcc/vcc_utils.c
index abe4f69b5..832e5357f 100644
--- a/lib/libvcc/vcc_utils.c
+++ b/lib/libvcc/vcc_utils.c
@@ -381,25 +381,14 @@ vcc_ByteVal(struct vcc *tl, double *d)
 		vcc_ErrWhere(tl, tl->t);
 		return;
 	}
-	if (vcc_IdIs(tl->t, "B"))
-		sc = 1.;
-	else if (vcc_IdIs(tl->t, "KB"))
-		sc = 1024.;
-	else if (vcc_IdIs(tl->t, "MB"))
-		sc = 1024. * 1024.;
-	else if (vcc_IdIs(tl->t, "GB"))
-		sc = 1024. * 1024. * 1024.;
-	else if (vcc_IdIs(tl->t, "TB"))
-		sc = 1024. * 1024. * 1024. * 1024.;
-	else {
+	sc = VNUM_bytes_unit(1.0, tl->t->b, tl->t->e, 0);
+	if (isnan(sc)) {
 		VSB_printf(tl->sb, "Unknown BYTES unit ");
 		vcc_ErrToken(tl, tl->t);
-		VSB_printf(tl->sb,
-		    ".  Legal are 'B', 'KB', 'MB', 'GB' and 'TB'\n");
+		VSB_printf(tl->sb, "\n%s\n", VNUM_LEGAL_BYTES);
 		vcc_ErrWhere(tl, tl->t);
 		return;
 	}
 	vcc_NextToken(tl);
 	*d = v * sc;
 }
-


More information about the varnish-commit mailing list