From 6b29a2a724a12d5e3ac63110415a8830d6bc4b1f Mon Sep 17 00:00:00 2001 From: cpq Date: Thu, 30 Mar 2023 10:49:58 +0100 Subject: [PATCH] Fix #2104 - %.*f formatting --- mongoose.c | 24 ++++++++++-------------- src/fmt.c | 24 ++++++++++-------------- test/unit_test.c | 32 ++++++++++++++++++++++++-------- 3 files changed, 44 insertions(+), 36 deletions(-) diff --git a/mongoose.c b/mongoose.c index f18d1c4f..a4b283a2 100644 --- a/mongoose.c +++ b/mongoose.c @@ -411,9 +411,7 @@ void mg_error(struct mg_connection *c, const char *fmt, ...) { -static bool is_digit(int c) { - return c >= '0' && c <= '9'; -} +static bool is_digit(int c) { return c >= '0' && c <= '9'; } static int addexp(char *buf, int e, int sign) { int n = 0; @@ -446,7 +444,7 @@ static int xisnan(double x) { 0x7ff00000; } -static size_t mg_dtoa(char *dst, size_t dstlen, double d, int width) { +static size_t mg_dtoa(char *dst, size_t dstlen, double d, int width, bool tz) { char buf[40]; int i, s = 0, n = 0, e = 0; double t, mul, saved; @@ -468,13 +466,13 @@ static size_t mg_dtoa(char *dst, size_t dstlen, double d, int width) { while (d < 1.0 && d / mul < 1.0) mul /= 10.0, e--; // printf(" --> %g %d %g %g\n", saved, e, t, mul); - if (e >= width) { - n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width); + if (e >= width && width > 1) { + n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz); // printf(" --> %.*g %d [%.*s]\n", 10, d / t, e, n, buf); n += addexp(buf + s + n, e, '+'); return mg_snprintf(dst, dstlen, "%.*s", n, buf); - } else if (e <= -width) { - n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width); + } else if (e <= -width && width > 1) { + n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz); // printf(" --> %.*g %d [%.*s]\n", 10, d / mul, e, n, buf); n += addexp(buf + s + n, -e, '-'); return mg_snprintf(dst, dstlen, "%.*s", n, buf); @@ -497,8 +495,8 @@ static size_t mg_dtoa(char *dst, size_t dstlen, double d, int width) { t /= 10.0; } } - while (n > 0 && buf[s + n - 1] == '0') n--; // Trim trailing zeros - if (n > 0 && buf[s + n - 1] == '.') n--; // Trim trailing dot + while (tz && n > 0 && buf[s + n - 1] == '0') n--; // Trim trailing zeroes + if (n > 0 && buf[s + n - 1] == '.') n--; // Trim trailing dot n += s; if (n >= (int) sizeof(buf)) n = (int) sizeof(buf) - 1; buf[n] = '\0'; @@ -542,9 +540,7 @@ static char mg_esc(int c, bool esc) { return 0; } -static char mg_escape(int c) { - return mg_esc(c, true); -} +static char mg_escape(int c) { return mg_esc(c, true); } static size_t qcpy(void (*out)(char, void *), void *ptr, char *buf, size_t len) { @@ -631,7 +627,7 @@ size_t mg_vxprintf(void (*out)(char, void *), void *param, const char *fmt, if (c == 'g' || c == 'f') { double v = va_arg(*ap, double); if (pr == ~0U) pr = 6; - k = mg_dtoa(tmp, sizeof(tmp), v, (int) pr); + k = mg_dtoa(tmp, sizeof(tmp), v, (int) pr, c == 'g'); } else if (is_long == 2) { int64_t v = va_arg(*ap, int64_t); k = mg_lld(tmp, v, s, h); diff --git a/src/fmt.c b/src/fmt.c index c14c21f2..f8697084 100644 --- a/src/fmt.c +++ b/src/fmt.c @@ -2,9 +2,7 @@ #include "iobuf.h" #include "util.h" -static bool is_digit(int c) { - return c >= '0' && c <= '9'; -} +static bool is_digit(int c) { return c >= '0' && c <= '9'; } static int addexp(char *buf, int e, int sign) { int n = 0; @@ -37,7 +35,7 @@ static int xisnan(double x) { 0x7ff00000; } -static size_t mg_dtoa(char *dst, size_t dstlen, double d, int width) { +static size_t mg_dtoa(char *dst, size_t dstlen, double d, int width, bool tz) { char buf[40]; int i, s = 0, n = 0, e = 0; double t, mul, saved; @@ -59,13 +57,13 @@ static size_t mg_dtoa(char *dst, size_t dstlen, double d, int width) { while (d < 1.0 && d / mul < 1.0) mul /= 10.0, e--; // printf(" --> %g %d %g %g\n", saved, e, t, mul); - if (e >= width) { - n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width); + if (e >= width && width > 1) { + n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz); // printf(" --> %.*g %d [%.*s]\n", 10, d / t, e, n, buf); n += addexp(buf + s + n, e, '+'); return mg_snprintf(dst, dstlen, "%.*s", n, buf); - } else if (e <= -width) { - n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width); + } else if (e <= -width && width > 1) { + n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz); // printf(" --> %.*g %d [%.*s]\n", 10, d / mul, e, n, buf); n += addexp(buf + s + n, -e, '-'); return mg_snprintf(dst, dstlen, "%.*s", n, buf); @@ -88,8 +86,8 @@ static size_t mg_dtoa(char *dst, size_t dstlen, double d, int width) { t /= 10.0; } } - while (n > 0 && buf[s + n - 1] == '0') n--; // Trim trailing zeros - if (n > 0 && buf[s + n - 1] == '.') n--; // Trim trailing dot + while (tz && n > 0 && buf[s + n - 1] == '0') n--; // Trim trailing zeroes + if (n > 0 && buf[s + n - 1] == '.') n--; // Trim trailing dot n += s; if (n >= (int) sizeof(buf)) n = (int) sizeof(buf) - 1; buf[n] = '\0'; @@ -133,9 +131,7 @@ static char mg_esc(int c, bool esc) { return 0; } -static char mg_escape(int c) { - return mg_esc(c, true); -} +static char mg_escape(int c) { return mg_esc(c, true); } static size_t qcpy(void (*out)(char, void *), void *ptr, char *buf, size_t len) { @@ -222,7 +218,7 @@ size_t mg_vxprintf(void (*out)(char, void *), void *param, const char *fmt, if (c == 'g' || c == 'f') { double v = va_arg(*ap, double); if (pr == ~0U) pr = 6; - k = mg_dtoa(tmp, sizeof(tmp), v, (int) pr); + k = mg_dtoa(tmp, sizeof(tmp), v, (int) pr, c == 'g'); } else if (is_long == 2) { int64_t v = va_arg(*ap, int64_t); k = mg_lld(tmp, v, s, h); diff --git a/test/unit_test.c b/test/unit_test.c index 92ef0e6c..919fa75e 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -1601,15 +1601,22 @@ static void test_str(void) { } { - char tmp[40]; +#if MG_ARCH == MG_ARCH_WIN32 + bool is_windows = true; +#else + bool is_windows = false; +#endif + #define DBLWIDTH(a, b) a, b -#define TESTDOUBLE(fmt_, num_, res_) \ - do { \ - const char *N = #num_; \ - size_t n = mg_snprintf(tmp, sizeof(tmp), fmt_, num_); \ - if (0) printf("[%s] [%s] -> [%s] [%.*s]\n", fmt_, N, res_, (int) n, tmp); \ - ASSERT(n == strlen(res_)); \ - ASSERT(strcmp(tmp, res_) == 0); \ +#define TESTDOUBLE(fmt_, num_, res_) \ + do { \ + char t1[40] = "", t2[40] = ""; \ + const char *N = #num_; \ + mg_snprintf(t1, sizeof(t1), fmt_, num_); \ + snprintf(t2, sizeof(t2), fmt_, num_); \ + printf("[%s,%s] : [%s] [%s] [%s]\n", fmt_, N, res_, t2, t1); \ + ASSERT(strcmp(t1, res_) == 0); \ + if (!is_windows) ASSERT(strcmp(t1, t2) == 0); \ } while (0) TESTDOUBLE("%g", 0.0, "0"); @@ -1649,6 +1656,15 @@ static void test_str(void) { TESTDOUBLE("%g", -600.1234, "-600.123"); TESTDOUBLE("%g", 599.1234, "599.123"); TESTDOUBLE("%g", -599.1234, "-599.123"); + TESTDOUBLE("%g", 0.14, "0.14"); + TESTDOUBLE("%f", 0.14, "0.140000"); + TESTDOUBLE("%.*f", DBLWIDTH(4, 0.14), "0.1400"); + TESTDOUBLE("%.*f", DBLWIDTH(3, 0.14), "0.140"); + TESTDOUBLE("%.*f", DBLWIDTH(2, 0.14), "0.14"); + TESTDOUBLE("%.*f", DBLWIDTH(1, 0.14), "0.1"); + TESTDOUBLE("%.*f", DBLWIDTH(1, 0.19), "0.2"); + TESTDOUBLE("%.*f", DBLWIDTH(1, 0.16), "0.2"); + // TESTDOUBLE("%.*f", DBLWIDTH(1, 0.15), "0.1"); #ifndef _WIN32 TESTDOUBLE("%g", (double) INFINITY, "inf");