[master] 9b2e63c Inspired by Dridi Boukelmoune's submission, add a locale-independent VNUM() function which converts (all of!) a string to a floating point number.
Poul-Henning Kamp
phk at FreeBSD.org
Mon Feb 23 22:48:37 CET 2015
commit 9b2e63c9e9eb189eae1a455a27036009aee1b25a
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date: Mon Feb 23 21:45:44 2015 +0000
Inspired by Dridi Boukelmoune's submission, add a locale-independent
VNUM() function which converts (all of!) a string to a floating point
number.
I didn't use Dridi's version, because I wanted slightly different
semantics (the NAN return) and I happen to be partial to the %e format,
which his version did not support.
diff --git a/lib/libvarnish/vnum.c b/lib/libvarnish/vnum.c
index 7c27821..98451b3 100644
--- a/lib/libvarnish/vnum.c
+++ b/lib/libvarnish/vnum.c
@@ -30,6 +30,7 @@
#include "config.h"
+#include <ctype.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
@@ -42,6 +43,55 @@ 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";
+/**********************************************************************
+ * Convert (all of!) a string to a floating point number, and if we can
+ * not, return NAN.
+ */
+
+double
+VNUM(const char *p)
+{
+ intmax_t m = 0, ee = 0;
+ double ms = 1.0;
+ double es = 1.0, e = 1.0, ne = 0.0;
+
+ while (isspace(*p))
+ p++;
+
+ if (*p == '-' || *p == '+')
+ ms = (*p++ == '-' ? -1.0 : 1.0);
+
+ for (; *p != '\0'; p++) {
+ if (isdigit(*p)) {
+ m = m * 10 + *p - '0';
+ e = ne;
+ if (e)
+ ne = e - 1.0;
+ } else if (*p == '.' && ne == 0.0) {
+ ne = -1.0;
+ } else
+ break;
+ }
+ if (e > 0.0)
+ return(nan("")); // No digits
+ if (*p == 'e' || *p == 'E') {
+ p++;
+ if (*p == '-' || *p == '+')
+ es = (*p++ == '-' ? -1.0 : 1.0);
+ if (!isdigit(*p))
+ return (nan(""));
+ for (; isdigit(*p); p++)
+ ee = ee * 10 + *p - '0';
+ }
+ while (isspace(*p))
+ p++;
+ if (*p != '\0')
+ return (nan(""));
+ return (ms * m * pow(10., e + es * ee));
+}
+
+/**********************************************************************/
+
const char *
VNUM_2bytes(const char *p, uintmax_t *r, uintmax_t rel)
{
@@ -164,16 +214,65 @@ static struct test_case {
{ 0, 0, 0 },
};
+const char *vec[] = {
+ " 1",
+ " 12",
+ " 12.",
+ " 12.3",
+ " 12.34",
+ " 12.34e-3",
+ " 12.34e3",
+ " 12.34e+3",
+ " +12.34e-3",
+ " -12.34e3",
+ "N.",
+ "N.12.",
+ "N12..",
+ "N12.,",
+ "N12e,",
+ "N12e+,",
+ "N12ee,",
+ "N1..2",
+ "NA",
+ "N1A",
+ "Ne-3",
+ NULL
+};
+
int
main(int argc, char *argv[])
{
+ int ec = 0;
struct test_case *tc;
uintmax_t val;
- int ec;
+ const char **p;
const char *e;
+ double d1, d2;
(void)argc;
- for (ec = 0, tc = test_cases; tc->str; ++tc) {
+
+ for (p = vec; *p != NULL; p++) {
+ e = *p;
+ d1 = VNUM(e + 1);
+ if (*e == 'N') {
+ if (!isnan(d1)) {
+ ec++;
+ printf("VNUM(%s) not NAN (%g)\n", e + 1, d1);
+ }
+ } else {
+ d2 = atof(e + 1);
+ if (isnan(d1)) {
+ printf("VNUM(%s) is NAN (%g)\n", e + 1, d1);
+ ec++;
+ } else if (fabs((d1 - d2) / d2) > 1e-15) {
+ printf("VNUM(%s) differs from atof() (%g)\n",
+ e + 1, d1);
+ ec++;
+ }
+ }
+ }
+
+ for (tc = test_cases; tc->str; ++tc) {
e = VNUM_2bytes(tc->str, &val, tc->rel);
if (e != tc->err) {
printf("%s: VNUM_2bytes(\"%s\", %ju) (%s) != (%s)\n",
More information about the varnish-commit
mailing list