Merge pull request #2954 from cesanta/dbl
Some checks are pending
Build and test - essentials / linux ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }} (clang++, , mip_test) (push) Waiting to run
Build and test - essentials / linux ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }} (clang++, , test) (push) Waiting to run
Build and test - essentials / linux ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }} (clang++, BUILTIN, mip_test) (push) Waiting to run
Build and test - essentials / linux ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }} (clang++, BUILTIN, test) (push) Waiting to run
Build and test - essentials / linux ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }} (gcc, , mip_test) (push) Waiting to run
Build and test - essentials / linux ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }} (gcc, , test) (push) Waiting to run
Build and test - essentials / linux ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }} (gcc, BUILTIN, mip_test) (push) Waiting to run
Build and test - essentials / linux ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }} (gcc, BUILTIN, test) (push) Waiting to run
Build and test - essentials / s390 (push) Waiting to run
Build and test - essentials / armhf (push) Waiting to run
Build and test - essentials / unamalgamated-mg_prefix (push) Waiting to run
Build and test - essentials / macos SSL=${{ matrix.ssl }} () (push) Waiting to run
Build and test - essentials / macos SSL=${{ matrix.ssl }} (BUILTIN) (push) Waiting to run
Build and test - essentials / windows ${{ matrix.target }} (mingw++) (push) Waiting to run
Build and test - essentials / windows ${{ matrix.target }} (vc22) (push) Waiting to run
Build and test - essentials / windows ${{ matrix.target }} (vc98) (push) Waiting to run
Build and test - essentials / arm (push) Waiting to run
Build and test - essentials / riscv (push) Waiting to run
Build and test - essentials / examples (push) Waiting to run
Build and test - essentials / examples_win (push) Waiting to run
Build and test - essentials / examples_mac (push) Waiting to run
Build and test - essentials / refprojs (push) Waiting to run
Build and test - essentials / refprojs_win (push) Waiting to run
Build and test - essentials / refprojs_mac (push) Waiting to run
Build and test - essentials / tutorials (push) Waiting to run
Build and test - essentials / tutorials_win (push) Waiting to run
Build and test - essentials / tutorials_mac (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:nxp/frdm-mcxn947-make-baremetal-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:nxp/frdm-mcxn947-make-freertos-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:nxp/rt1020-evk-make-baremetal-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:nxp/rt1060-evk-make-baremetal-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:nxp/rt1170-evk-make-baremetal-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:stm32/nucleo-f429zi-make-baremetal-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:stm32/nucleo-f429zi-make-freertos-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:stm32/nucleo-f746zg-make-baremetal-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:stm32/nucleo-f746zg-make-freertos-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:stm32/nucleo-h563zi-make-baremetal-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:stm32/nucleo-h563zi-make-freertos-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:stm32/nucleo-h723zg-make-baremetal-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:stm32/nucleo-h723zg-make-freertos-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:stm32/nucleo-h743zi-make-baremetal-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:stm32/nucleo-h743zi-make-freertos-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:stm32/stm32h573i-dk-make-baremetal-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:stm32/stm32h573i-dk-make-freertos-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:ti/ek-tm4c1294xl-make-baremetal-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:ti/ek-tm4c1294xl-make-freertos-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:esp32/uart-bridge]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:esp8266/http-client-server]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:infineon/infineon-xmc4700_4800-lwip-rtx-rtos]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:stm32/nucleo-g031-make-baremetal-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:esp32/device-dashboard]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:infineon/infineon-xmc7200]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:microchip/same54-xpro/device-dashboard]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:nxp/rt1020-evk-make-freertos-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:nxp/rt1060-evk-make-freertos-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:nxp/rt1170-evk-make-freertos-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:pico-sdk/pico-rndis-dashboard]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:pico-sdk/pico-w]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:pico-sdk/w5500-evb-pico2-picosdk-baremetal-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:renesas/ek-ra6m4-make-baremetal-builtin]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:stm32/nucleo-f746zg-make-baremetal-builtin-cmsis_driver]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:stm32/nucleo-f746zg-make-freertos-tcp]) (push) Waiting to run
Build and test - essentials / ${{ matrix.example.path }} (map[path:pico-sdk/pico-rndis-device]) (push) Waiting to run
Build and test - essentials / cube_examples (push) Waiting to run
Build and test - essentials / test_f7 (push) Waiting to run
Build and test - essentials / test_f4 (push) Waiting to run
Build and test - essentials / test_h743 (push) Waiting to run
Build and test - essentials / test_h723 (push) Waiting to run
Build and test - essentials / test_h5 (push) Waiting to run
Build and test - essentials / test_rt1020 (push) Waiting to run
Build and test - essentials / test_rt1060 (push) Waiting to run
Build and test - essentials / test_rt1170 (push) Waiting to run
Build and test - essentials / test_ra6m4 (push) Waiting to run
Build and test - essentials / test_tm4c (push) Waiting to run
Build and test - essentials / test_same54 (push) Waiting to run
Build and test - essentials / test_pico_w5500 (push) Waiting to run

Fix dbl printing
This commit is contained in:
Sergio R. Caprile 2024-11-19 16:20:30 -03:00 committed by GitHub
commit 53ec9adb1b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 159 additions and 58 deletions

View File

@ -550,28 +550,36 @@ static size_t mg_dtoa(char *dst, size_t dstlen, double d, int width, bool tz) {
// Round // Round
saved = d; saved = d;
if (tz) {
mul = 1.0; mul = 1.0;
while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0; while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0;
} else {
mul = 0.1;
}
while (d <= 1.0 && d / mul <= 1.0) mul /= 10.0; while (d <= 1.0 && d / mul <= 1.0) mul /= 10.0;
for (i = 0, t = mul * 5; i < width; i++) t /= 10.0; for (i = 0, t = mul * 5; i < width; i++) t /= 10.0;
d += t; d += t;
// Calculate exponent, and 'mul' for scientific representation // Calculate exponent, and 'mul' for scientific representation
mul = 1.0; mul = 1.0;
while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0, e++; while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0, e++;
while (d < 1.0 && d / mul < 1.0) mul /= 10.0, e--; while (d < 1.0 && d / mul < 1.0) mul /= 10.0, e--;
// printf(" --> %g %d %g %g\n", saved, e, t, mul); // printf(" --> %g %d %g %g\n", saved, e, t, mul);
if (e >= width && width > 1) { if (tz && e >= width && width > 1) {
n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz); n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz);
// printf(" --> %.*g %d [%.*s]\n", 10, d / t, e, n, buf); // printf(" --> %.*g %d [%.*s]\n", 10, d / t, e, n, buf);
n += addexp(buf + s + n, e, '+'); n += addexp(buf + s + n, e, '+');
return mg_snprintf(dst, dstlen, "%.*s", n, buf); return mg_snprintf(dst, dstlen, "%.*s", n, buf);
} else if (e <= -width && width > 1) { } else if (tz && e <= -width && width > 1) {
n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz); n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz);
// printf(" --> %.*g %d [%.*s]\n", 10, d / mul, e, n, buf); // printf(" --> %.*g %d [%.*s]\n", 10, d / mul, e, n, buf);
n += addexp(buf + s + n, -e, '-'); n += addexp(buf + s + n, -e, '-');
return mg_snprintf(dst, dstlen, "%.*s", n, buf); return mg_snprintf(dst, dstlen, "%.*s", n, buf);
} else { } else {
int targ_width = width;
for (i = 0, t = mul; t >= 1.0 && s + n < (int) sizeof(buf); i++) { for (i = 0, t = mul; t >= 1.0 && s + n < (int) sizeof(buf); i++) {
int ch = (int) (d / t); int ch = (int) (d / t);
if (n > 0 || ch > 0) buf[s + n++] = (char) (ch + '0'); if (n > 0 || ch > 0) buf[s + n++] = (char) (ch + '0');
@ -583,15 +591,17 @@ static size_t mg_dtoa(char *dst, size_t dstlen, double d, int width, bool tz) {
while (t >= 1.0 && n + s < (int) sizeof(buf)) buf[n++] = '0', t /= 10.0; while (t >= 1.0 && n + s < (int) sizeof(buf)) buf[n++] = '0', t /= 10.0;
if (s + n < (int) sizeof(buf)) buf[n + s++] = '.'; if (s + n < (int) sizeof(buf)) buf[n + s++] = '.';
// printf(" 1--> [%g] -> [%.*s]\n", saved, s + n, buf); // printf(" 1--> [%g] -> [%.*s]\n", saved, s + n, buf);
for (i = 0, t = 0.1; s + n < (int) sizeof(buf) && n < width; i++) { if (!tz && n > 0) targ_width = width + n;
for (i = 0, t = 0.1; s + n < (int) sizeof(buf) && n < targ_width; i++) {
int ch = (int) (d / t); int ch = (int) (d / t);
buf[s + n++] = (char) (ch + '0'); buf[s + n++] = (char) (ch + '0');
d -= ch * t; d -= ch * t;
t /= 10.0; t /= 10.0;
} }
} }
while (tz && n > 0 && buf[s + n - 1] == '0') n--; // Trim trailing zeroes while (tz && n > 0 && buf[s + n - 1] == '0') n--; // Trim trailing zeroes
if (n > 0 && buf[s + n - 1] == '.') n--; // Trim trailing dot if (tz && n > 0 && buf[s + n - 1] == '.') n--; // Trim trailing dot
n += s; n += s;
if (n >= (int) sizeof(buf)) n = (int) sizeof(buf) - 1; if (n >= (int) sizeof(buf)) n = (int) sizeof(buf) - 1;
buf[n] = '\0'; buf[n] = '\0';

View File

@ -48,28 +48,36 @@ static size_t mg_dtoa(char *dst, size_t dstlen, double d, int width, bool tz) {
// Round // Round
saved = d; saved = d;
if (tz) {
mul = 1.0; mul = 1.0;
while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0; while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0;
} else {
mul = 0.1;
}
while (d <= 1.0 && d / mul <= 1.0) mul /= 10.0; while (d <= 1.0 && d / mul <= 1.0) mul /= 10.0;
for (i = 0, t = mul * 5; i < width; i++) t /= 10.0; for (i = 0, t = mul * 5; i < width; i++) t /= 10.0;
d += t; d += t;
// Calculate exponent, and 'mul' for scientific representation // Calculate exponent, and 'mul' for scientific representation
mul = 1.0; mul = 1.0;
while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0, e++; while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0, e++;
while (d < 1.0 && d / mul < 1.0) mul /= 10.0, e--; while (d < 1.0 && d / mul < 1.0) mul /= 10.0, e--;
// printf(" --> %g %d %g %g\n", saved, e, t, mul); // printf(" --> %g %d %g %g\n", saved, e, t, mul);
if (e >= width && width > 1) { if (tz && e >= width && width > 1) {
n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz); n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz);
// printf(" --> %.*g %d [%.*s]\n", 10, d / t, e, n, buf); // printf(" --> %.*g %d [%.*s]\n", 10, d / t, e, n, buf);
n += addexp(buf + s + n, e, '+'); n += addexp(buf + s + n, e, '+');
return mg_snprintf(dst, dstlen, "%.*s", n, buf); return mg_snprintf(dst, dstlen, "%.*s", n, buf);
} else if (e <= -width && width > 1) { } else if (tz && e <= -width && width > 1) {
n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz); n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz);
// printf(" --> %.*g %d [%.*s]\n", 10, d / mul, e, n, buf); // printf(" --> %.*g %d [%.*s]\n", 10, d / mul, e, n, buf);
n += addexp(buf + s + n, -e, '-'); n += addexp(buf + s + n, -e, '-');
return mg_snprintf(dst, dstlen, "%.*s", n, buf); return mg_snprintf(dst, dstlen, "%.*s", n, buf);
} else { } else {
int targ_width = width;
for (i = 0, t = mul; t >= 1.0 && s + n < (int) sizeof(buf); i++) { for (i = 0, t = mul; t >= 1.0 && s + n < (int) sizeof(buf); i++) {
int ch = (int) (d / t); int ch = (int) (d / t);
if (n > 0 || ch > 0) buf[s + n++] = (char) (ch + '0'); if (n > 0 || ch > 0) buf[s + n++] = (char) (ch + '0');
@ -81,15 +89,17 @@ static size_t mg_dtoa(char *dst, size_t dstlen, double d, int width, bool tz) {
while (t >= 1.0 && n + s < (int) sizeof(buf)) buf[n++] = '0', t /= 10.0; while (t >= 1.0 && n + s < (int) sizeof(buf)) buf[n++] = '0', t /= 10.0;
if (s + n < (int) sizeof(buf)) buf[n + s++] = '.'; if (s + n < (int) sizeof(buf)) buf[n + s++] = '.';
// printf(" 1--> [%g] -> [%.*s]\n", saved, s + n, buf); // printf(" 1--> [%g] -> [%.*s]\n", saved, s + n, buf);
for (i = 0, t = 0.1; s + n < (int) sizeof(buf) && n < width; i++) { if (!tz && n > 0) targ_width = width + n;
for (i = 0, t = 0.1; s + n < (int) sizeof(buf) && n < targ_width; i++) {
int ch = (int) (d / t); int ch = (int) (d / t);
buf[s + n++] = (char) (ch + '0'); buf[s + n++] = (char) (ch + '0');
d -= ch * t; d -= ch * t;
t /= 10.0; t /= 10.0;
} }
} }
while (tz && n > 0 && buf[s + n - 1] == '0') n--; // Trim trailing zeroes while (tz && n > 0 && buf[s + n - 1] == '0') n--; // Trim trailing zeroes
if (n > 0 && buf[s + n - 1] == '.') n--; // Trim trailing dot if (tz && n > 0 && buf[s + n - 1] == '.') n--; // Trim trailing dot
n += s; n += s;
if (n >= (int) sizeof(buf)) n = (int) sizeof(buf) - 1; if (n >= (int) sizeof(buf)) n = (int) sizeof(buf) - 1;
buf[n] = '\0'; buf[n] = '\0';

View File

@ -882,8 +882,8 @@ static void fprcb(struct mg_connection *c, int ev, void *ev_data) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
int code = atoi(hm->uri.buf); int code = atoi(hm->uri.buf);
if (code == 200) { if (code == 200) {
snprintf(fd->buf + fd->len, FETCH_BUF_SIZE - (unsigned int) fd->len, "%.*s", (int) hm->message.len, snprintf(fd->buf + fd->len, FETCH_BUF_SIZE - (unsigned int) fd->len,
hm->message.buf); "%.*s", (int) hm->message.len, hm->message.buf);
fd->len += (int) hm->message.len; fd->len += (int) hm->message.len;
++fd->reqs; ++fd->reqs;
if (fd->reqs == 2) { if (fd->reqs == 2) {
@ -900,8 +900,8 @@ static void fprcb(struct mg_connection *c, int ev, void *ev_data) {
} }
} }
static int fpr(struct mg_mgr *mgr, char *buf, const char *url, static int fpr(struct mg_mgr *mgr, char *buf, const char *url, const char *fmt,
const char *fmt, ...) { ...) {
struct fpr_data fd = {buf, 0, 0, 0}; struct fpr_data fd = {buf, 0, 0, 0};
int i; int i;
struct mg_connection *c = NULL; struct mg_connection *c = NULL;
@ -941,12 +941,17 @@ static void test_http_server(void) {
ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\nA B\n\n") == 0); ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\nA B\n\n") == 0);
// Pipelined requests // Pipelined requests
ASSERT(fpr(&mgr, buf, url, "GET /foo/bar HTTP/1.1\n\nGET /foo/foobar HTTP/1.1\n\n") == 2); ASSERT(fpr(&mgr, buf, url,
"GET /foo/bar HTTP/1.1\n\nGET /foo/foobar HTTP/1.1\n\n") == 2);
// Pipelined requests with file requests other than the last one (see #2796) // Pipelined requests with file requests other than the last one (see #2796)
ASSERT(fpr(&mgr, buf, url, "GET /a.txt HTTP/1.1\n\nGET /a.txt HTTP/1.1\n\n") == 2); ASSERT(fpr(&mgr, buf, url,
ASSERT(fpr(&mgr, buf, url, "HEAD /a.txt HTTP/1.1\n\nGET /a.txt HTTP/1.1\n\n") == 2); "GET /a.txt HTTP/1.1\n\nGET /a.txt HTTP/1.1\n\n") == 2);
ASSERT(fpr(&mgr, buf, url,
"HEAD /a.txt HTTP/1.1\n\nGET /a.txt HTTP/1.1\n\n") == 2);
// Connection: close // Connection: close
ASSERT(fpr(&mgr, buf, url, "GET /foo/bar HTTP/1.1\nConnection: close\n\nGET /foo/foobar HTTP/1.1\n\n") == 1); ASSERT(fpr(&mgr, buf, url,
"GET /foo/bar HTTP/1.1\nConnection: close\n\nGET /foo/foobar "
"HTTP/1.1\n\n") == 1);
ASSERT(cmpbody(buf, "uri: bar") == 0); ASSERT(cmpbody(buf, "uri: bar") == 0);
// Responses with missing reason phrase must also work // Responses with missing reason phrase must also work
@ -1661,7 +1666,9 @@ static void test_http_parse(void) {
ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s)); ASSERT(mg_http_parse(s, strlen(s), &req) == (int) strlen(s));
ASSERT((v = mg_http_get_header(&req, "e")) != NULL); ASSERT((v = mg_http_get_header(&req, "e")) != NULL);
ASSERT(vcmp(*v, "5")); ASSERT(vcmp(*v, "5"));
ASSERT((v = mg_http_get_header(&req, "h")) == NULL); ASSERT((v = mg_http_get_header(&req, "g")) != NULL);
ASSERT(vcmp(*v, "7"));
ASSERT((v = mg_http_get_header(&req, "h")) == NULL); // MG_MAX_HTTP_HEADERS
} }
{ {
@ -2108,6 +2115,16 @@ static void test_str(void) {
if (!is_windows) ASSERT(strcmp(t1, t2) == 0); \ if (!is_windows) ASSERT(strcmp(t1, t2) == 0); \
} while (0) } while (0)
#define TESTDOUBLE_NOHOSTCHECK(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); \
} while (0)
TESTDOUBLE("%g", 0.0, "0"); TESTDOUBLE("%g", 0.0, "0");
TESTDOUBLE("%g", 0.123, "0.123"); TESTDOUBLE("%g", 0.123, "0.123");
TESTDOUBLE("%g", 0.00123, "0.00123"); TESTDOUBLE("%g", 0.00123, "0.00123");
@ -2127,8 +2144,18 @@ static void test_str(void) {
TESTDOUBLE("%g", 10000.0, "10000"); TESTDOUBLE("%g", 10000.0, "10000");
TESTDOUBLE("%g", 100000.0, "100000"); TESTDOUBLE("%g", 100000.0, "100000");
TESTDOUBLE("%g", 1000000.0, "1e+06"); TESTDOUBLE("%g", 1000000.0, "1e+06");
TESTDOUBLE("%f", 1000000.0, "1000000.000000");
TESTDOUBLE("%g", 10000000.0, "1e+07"); TESTDOUBLE("%g", 10000000.0, "1e+07");
TESTDOUBLE("%f", 10000000.0, "10000000.000000");
TESTDOUBLE("%g", 100000001.0, "1e+08"); TESTDOUBLE("%g", 100000001.0, "1e+08");
TESTDOUBLE("%g", 0.1, "0.1");
TESTDOUBLE("%g", 0.01, "0.01");
TESTDOUBLE("%g", 0.001, "0.001");
TESTDOUBLE("%g", 0.0001, "0.0001");
TESTDOUBLE_NOHOSTCHECK("%g", 0.00001, "0.00001"); // "1e-05"
TESTDOUBLE("%g", 0.000001, "1e-06");
TESTDOUBLE("%g", -0.0001, "-0.0001");
TESTDOUBLE_NOHOSTCHECK("%g", -0.00001, "-0.00001"); // "-1e-05"
TESTDOUBLE("%g", 10.5454, "10.5454"); TESTDOUBLE("%g", 10.5454, "10.5454");
TESTDOUBLE("%g", 999999.0, "999999"); TESTDOUBLE("%g", 999999.0, "999999");
TESTDOUBLE("%g", 9999999.0, "1e+07"); TESTDOUBLE("%g", 9999999.0, "1e+07");
@ -2150,14 +2177,35 @@ static void test_str(void) {
TESTDOUBLE("%.*f", DBLWIDTH(4, 0.14), "0.1400"); TESTDOUBLE("%.*f", DBLWIDTH(4, 0.14), "0.1400");
TESTDOUBLE("%.*f", DBLWIDTH(3, 0.14), "0.140"); TESTDOUBLE("%.*f", DBLWIDTH(3, 0.14), "0.140");
TESTDOUBLE("%.*f", DBLWIDTH(2, 0.14), "0.14"); TESTDOUBLE("%.*f", DBLWIDTH(2, 0.14), "0.14");
TESTDOUBLE("%.*f", DBLWIDTH(2, 25.14), "25.14");
TESTDOUBLE("%.*f", DBLWIDTH(1, 0.14), "0.1"); TESTDOUBLE("%.*f", DBLWIDTH(1, 0.14), "0.1");
TESTDOUBLE("%.*f", DBLWIDTH(1, 0.19), "0.2"); TESTDOUBLE("%.*f", DBLWIDTH(1, 0.19), "0.2");
TESTDOUBLE("%.*f", DBLWIDTH(1, 0.16), "0.2"); TESTDOUBLE("%.*f", DBLWIDTH(1, 0.16), "0.2");
//TESTDOUBLE("%.1f", 0.15, "0.1"); TESTDOUBLE_NOHOSTCHECK("%.1f", 0.15, "0.2");
//TESTDOUBLE("%.3f", 123.123456789, "123.123"); TESTDOUBLE("%.3f", 123.123456789, "123.123");
//TESTDOUBLE("%.4f", 123.123456789, "123.1235"); TESTDOUBLE("%.4f", 123.123456789, "123.1235");
//TESTDOUBLE("%.5f", 123.1234567, "123.12346"); TESTDOUBLE("%.5f", 123.1234567, "123.12346");
//TESTDOUBLE("%.*f", DBLWIDTH(1, 0.15), "0.1"); TESTDOUBLE_NOHOSTCHECK("%.*f", DBLWIDTH(1, 0.15), "0.2");
TESTDOUBLE("%.5f", 123.12345, "123.12345");
TESTDOUBLE("%.4f", 789.01234, "789.0123");
TESTDOUBLE("%2.3f", 1.23, "1.230");
TESTDOUBLE("%.1f", 1.5, "1.5");
TESTDOUBLE("%.3f", 500.0, "500.000");
TESTDOUBLE("%.1f", 1.15, "1.1");
TESTDOUBLE("%.1f", 0.155, "0.2");
TESTDOUBLE("%.1f", 1.155, "1.2");
TESTDOUBLE("%.1f", 0.155, "0.2");
TESTDOUBLE("%.2f", 0.015, "0.01");
TESTDOUBLE("%.2f", 0.0015, "0.00");
TESTDOUBLE("%.1f", 0.155, "0.2");
TESTDOUBLE("%.3f", 13.12505, "13.125");
TESTDOUBLE("%.3f", 15.1255, "15.126");
TESTDOUBLE("%.3f", 19.1255, "19.125");
TESTDOUBLE("%.4f", 100.15, "100.1500");
TESTDOUBLE("%.2f", 5.55, "5.55");
#ifndef _WIN32 #ifndef _WIN32
TESTDOUBLE("%g", (double) INFINITY, "inf"); TESTDOUBLE("%g", (double) INFINITY, "inf");
@ -2381,7 +2429,8 @@ static void test_util(void) {
ASSERT(mg_url_decode("&&&a=%", 6, buf, sizeof(buf), 0) < 0); ASSERT(mg_url_decode("&&&a=%", 6, buf, sizeof(buf), 0) < 0);
ASSERT(mg_url_decode("a=%1", 4, buf, sizeof(buf), 0) < 0); ASSERT(mg_url_decode("a=%1", 4, buf, sizeof(buf), 0) < 0);
ASSERT(mg_url_decode("a=%12", 5, buf, sizeof(buf), 0) == 3 && buf[2] == 0x12); ASSERT(mg_url_decode("a=%12", 5, buf, sizeof(buf), 0) == 3 && buf[2] == 0x12);
ASSERT(mg_url_decode("a=%123", 6, buf, sizeof(buf), 0) == 4 && buf[2] == 0x12 && buf[3] == '3'); ASSERT(mg_url_decode("a=%123", 6, buf, sizeof(buf), 0) == 4 &&
buf[2] == 0x12 && buf[3] == '3');
memset(a.ip, 0xaa, sizeof(a.ip)); memset(a.ip, 0xaa, sizeof(a.ip));
ASSERT(mg_aton(mg_str("::1%1"), &a) == true); ASSERT(mg_aton(mg_str("::1%1"), &a) == true);
@ -2439,64 +2488,94 @@ static void test_util(void) {
{ {
uint64_t val, max = (uint64_t) -1; uint64_t val, max = (uint64_t) -1;
ASSERT(mg_str_to_num(mg_str("0"), 10, &val, sizeof(uint64_t)) && val == 0); ASSERT(mg_str_to_num(mg_str("0"), 10, &val, sizeof(uint64_t)) && val == 0);
ASSERT(mg_str_to_num(mg_str("123"), 10, &val, sizeof(uint64_t)) && val == 123); ASSERT(mg_str_to_num(mg_str("123"), 10, &val, sizeof(uint64_t)) &&
val == 123);
ASSERT(mg_str_to_num(mg_str(" 123"), 10, &val, sizeof(uint64_t)) == false); ASSERT(mg_str_to_num(mg_str(" 123"), 10, &val, sizeof(uint64_t)) == false);
ASSERT(mg_str_to_num(mg_str("123 "), 10, &val, sizeof(uint64_t)) == false); ASSERT(mg_str_to_num(mg_str("123 "), 10, &val, sizeof(uint64_t)) == false);
ASSERT(mg_str_to_num(mg_str(""), 10, &val, sizeof(uint64_t)) == false); ASSERT(mg_str_to_num(mg_str(""), 10, &val, sizeof(uint64_t)) == false);
ASSERT(mg_str_to_num(mg_str(" 123x"), 10, &val, sizeof(uint64_t)) == false); ASSERT(mg_str_to_num(mg_str(" 123x"), 10, &val, sizeof(uint64_t)) == false);
ASSERT(mg_str_to_num(mg_str("-"), 10, &val, sizeof(uint64_t)) == false); ASSERT(mg_str_to_num(mg_str("-"), 10, &val, sizeof(uint64_t)) == false);
mg_snprintf(buf, sizeof(buf), "%llu", max); mg_snprintf(buf, sizeof(buf), "%llu", max);
ASSERT(mg_str_to_num(mg_str(buf), 10, &val, sizeof(uint64_t)) && val == max); ASSERT(mg_str_to_num(mg_str(buf), 10, &val, sizeof(uint64_t)) &&
val == max);
ASSERT(mg_str_to_num(mg_str("0"), 2, &val, sizeof(uint64_t)) && val == 0); ASSERT(mg_str_to_num(mg_str("0"), 2, &val, sizeof(uint64_t)) && val == 0);
ASSERT(mg_str_to_num(mg_str("1"), 2, &val, sizeof(uint64_t)) && val == 1); ASSERT(mg_str_to_num(mg_str("1"), 2, &val, sizeof(uint64_t)) && val == 1);
ASSERT(mg_str_to_num(mg_str("0123"), 2, &val, sizeof(uint64_t)) == false); ASSERT(mg_str_to_num(mg_str("0123"), 2, &val, sizeof(uint64_t)) == false);
ASSERT(mg_str_to_num(mg_str("123"), 2, &val, sizeof(uint64_t)) == false); ASSERT(mg_str_to_num(mg_str("123"), 2, &val, sizeof(uint64_t)) == false);
ASSERT(mg_str_to_num(mg_str("01111011"), 2, &val, sizeof(uint64_t)) && val == 123); ASSERT(mg_str_to_num(mg_str("01111011"), 2, &val, sizeof(uint64_t)) &&
ASSERT(mg_str_to_num(mg_str("1111111111111111111111111111111111111111111111111111111111111111"), 2, &val, sizeof(uint64_t)) && val == max); val == 123);
ASSERT(mg_str_to_num(mg_str("1111111111111111111111111111111111111111111111"
"111111111111111111"),
2, &val, sizeof(uint64_t)) &&
val == max);
ASSERT(mg_str_to_num(mg_str("0"), 16, &val, sizeof(uint64_t)) && val == 0); ASSERT(mg_str_to_num(mg_str("0"), 16, &val, sizeof(uint64_t)) && val == 0);
ASSERT(mg_str_to_num(mg_str("123"), 16, &val, sizeof(uint64_t)) && val == 0x123); ASSERT(mg_str_to_num(mg_str("123"), 16, &val, sizeof(uint64_t)) &&
ASSERT(mg_str_to_num(mg_str("def"), 16, &val, sizeof(uint64_t)) && val == 0xdef); val == 0x123);
ASSERT(mg_str_to_num(mg_str("def"), 16, &val, sizeof(uint64_t)) &&
val == 0xdef);
ASSERT(mg_str_to_num(mg_str("defg"), 16, &val, sizeof(uint64_t)) == false); ASSERT(mg_str_to_num(mg_str("defg"), 16, &val, sizeof(uint64_t)) == false);
mg_snprintf(buf, sizeof(buf), "%llx", max); mg_snprintf(buf, sizeof(buf), "%llx", max);
ASSERT(mg_str_to_num(mg_str(buf), 16, &val, sizeof(uint64_t)) && val == max); ASSERT(mg_str_to_num(mg_str(buf), 16, &val, sizeof(uint64_t)) &&
ASSERT(mg_str_to_num(mg_str("0x123"), 0, &val, sizeof(uint64_t)) && val == 0x123); val == max);
ASSERT(mg_str_to_num(mg_str("0x123"), 0, &val, sizeof(uint64_t)) &&
val == 0x123);
ASSERT(mg_str_to_num(mg_str("0b123"), 0, &val, sizeof(uint64_t)) == false); ASSERT(mg_str_to_num(mg_str("0b123"), 0, &val, sizeof(uint64_t)) == false);
ASSERT(mg_str_to_num(mg_str("0c123"), 0, &val, sizeof(uint64_t)) == false); ASSERT(mg_str_to_num(mg_str("0c123"), 0, &val, sizeof(uint64_t)) == false);
ASSERT(mg_str_to_num(mg_str("0b101"), 0, &val, sizeof(uint64_t)) && val == 5); ASSERT(mg_str_to_num(mg_str("0b101"), 0, &val, sizeof(uint64_t)) &&
ASSERT(mg_str_to_num(mg_str("0123"), 0, &val, sizeof(uint64_t)) && val == 123); val == 5);
ASSERT(mg_str_to_num(mg_str("0123"), 0, &val, sizeof(uint64_t)) &&
val == 123);
} }
{ {
uint32_t val, max = (uint32_t) -1; uint32_t val, max = (uint32_t) -1;
ASSERT(mg_str_to_num(mg_str("123"), 10, &val, sizeof(uint32_t)) && val == 123); ASSERT(mg_str_to_num(mg_str("123"), 10, &val, sizeof(uint32_t)) &&
val == 123);
mg_snprintf(buf, sizeof(buf), "%lu", (unsigned long) max); mg_snprintf(buf, sizeof(buf), "%lu", (unsigned long) max);
ASSERT(strcmp(buf, "4294967295") == 0); ASSERT(strcmp(buf, "4294967295") == 0);
ASSERT(mg_str_to_num(mg_str(buf), 10, &val, sizeof(uint32_t)) && val == max); ASSERT(mg_str_to_num(mg_str(buf), 10, &val, sizeof(uint32_t)) &&
ASSERT(mg_str_to_num(mg_str("01111011"), 2, &val, sizeof(uint32_t)) && val == 123); val == max);
ASSERT(mg_str_to_num(mg_str("11111111111111111111111111111111"), 2, &val, sizeof(uint32_t)) && val == max); ASSERT(mg_str_to_num(mg_str("01111011"), 2, &val, sizeof(uint32_t)) &&
val == 123);
ASSERT(mg_str_to_num(mg_str("11111111111111111111111111111111"), 2, &val,
sizeof(uint32_t)) &&
val == max);
ASSERT(mg_str_to_num(mg_str("0"), 16, &val, sizeof(uint32_t)) && val == 0); ASSERT(mg_str_to_num(mg_str("0"), 16, &val, sizeof(uint32_t)) && val == 0);
ASSERT(mg_str_to_num(mg_str("123"), 16, &val, sizeof(uint32_t)) && val == 0x123); ASSERT(mg_str_to_num(mg_str("123"), 16, &val, sizeof(uint32_t)) &&
val == 0x123);
mg_snprintf(buf, sizeof(buf), "%lx", max); mg_snprintf(buf, sizeof(buf), "%lx", max);
ASSERT(mg_str_to_num(mg_str(buf), 16, &val, sizeof(uint32_t)) && val == max); ASSERT(mg_str_to_num(mg_str(buf), 16, &val, sizeof(uint32_t)) &&
val == max);
} }
{ {
uint16_t val, max = (uint16_t) -1; uint16_t val, max = (uint16_t) -1;
ASSERT(mg_str_to_num(mg_str("123"), 10, &val, sizeof(uint16_t)) && val == 123); ASSERT(mg_str_to_num(mg_str("123"), 10, &val, sizeof(uint16_t)) &&
val == 123);
mg_snprintf(buf, sizeof(buf), "%u", max); mg_snprintf(buf, sizeof(buf), "%u", max);
ASSERT(mg_str_to_num(mg_str(buf), 10, &val, sizeof(uint16_t)) && val == max); ASSERT(mg_str_to_num(mg_str(buf), 10, &val, sizeof(uint16_t)) &&
ASSERT(mg_str_to_num(mg_str("01111011"), 2, &val, sizeof(uint16_t)) && val == 123); val == max);
ASSERT(mg_str_to_num(mg_str("1111111111111111"), 2, &val, sizeof(uint16_t)) && val == max); ASSERT(mg_str_to_num(mg_str("01111011"), 2, &val, sizeof(uint16_t)) &&
ASSERT(mg_str_to_num(mg_str("123"), 16, &val, sizeof(uint16_t)) && val == 0x123); val == 123);
ASSERT(
mg_str_to_num(mg_str("1111111111111111"), 2, &val, sizeof(uint16_t)) &&
val == max);
ASSERT(mg_str_to_num(mg_str("123"), 16, &val, sizeof(uint16_t)) &&
val == 0x123);
mg_snprintf(buf, sizeof(buf), "%x", max); mg_snprintf(buf, sizeof(buf), "%x", max);
ASSERT(mg_str_to_num(mg_str(buf), 16, &val, sizeof(uint16_t)) && val == max); ASSERT(mg_str_to_num(mg_str(buf), 16, &val, sizeof(uint16_t)) &&
val == max);
} }
{ {
uint8_t val, max = (uint8_t) -1; uint8_t val, max = (uint8_t) -1;
ASSERT(mg_str_to_num(mg_str("123"), 10, &val, sizeof(uint8_t)) && val == 123); ASSERT(mg_str_to_num(mg_str("123"), 10, &val, sizeof(uint8_t)) &&
val == 123);
mg_snprintf(buf, sizeof(buf), "%u", max); mg_snprintf(buf, sizeof(buf), "%u", max);
ASSERT(mg_str_to_num(mg_str(buf), 10, &val, sizeof(uint8_t)) && val == max); ASSERT(mg_str_to_num(mg_str(buf), 10, &val, sizeof(uint8_t)) && val == max);
ASSERT(mg_str_to_num(mg_str("01111011"), 2, &val, sizeof(uint8_t)) && val == 123); ASSERT(mg_str_to_num(mg_str("01111011"), 2, &val, sizeof(uint8_t)) &&
ASSERT(mg_str_to_num(mg_str("11111111"), 2, &val, sizeof(uint8_t)) && val == max); val == 123);
ASSERT(mg_str_to_num(mg_str("12"), 16, &val, sizeof(uint8_t)) && val == 0x12); ASSERT(mg_str_to_num(mg_str("11111111"), 2, &val, sizeof(uint8_t)) &&
val == max);
ASSERT(mg_str_to_num(mg_str("12"), 16, &val, sizeof(uint8_t)) &&
val == 0x12);
mg_snprintf(buf, sizeof(buf), "%x", max); mg_snprintf(buf, sizeof(buf), "%x", max);
ASSERT(mg_str_to_num(mg_str(buf), 16, &val, sizeof(uint8_t)) && val == max); ASSERT(mg_str_to_num(mg_str(buf), 16, &val, sizeof(uint8_t)) && val == max);
} }
@ -3100,10 +3179,12 @@ static void test_json(void) {
{ {
char to[4], expect[4] = {0, 0, 0, 0}; char to[4], expect[4] = {0, 0, 0, 0};
memset(to, 0, sizeof(to)); memset(to, 0, sizeof(to));
ASSERT(mg_json_unescape(mg_str("\\u0000"), to, 4) && memcmp(to, expect, 4) == 0); ASSERT(mg_json_unescape(mg_str("\\u0000"), to, 4) &&
memcmp(to, expect, 4) == 0);
to[0] = 0; to[0] = 0;
expect[0] = (char) 0xff; expect[0] = (char) 0xff;
ASSERT(mg_json_unescape(mg_str("\\u00ff"), to, 4) && memcmp(to, expect, 4) == 0); ASSERT(mg_json_unescape(mg_str("\\u00ff"), to, 4) &&
memcmp(to, expect, 4) == 0);
ASSERT(!mg_json_unescape(mg_str("\\u0100"), to, 4)); ASSERT(!mg_json_unescape(mg_str("\\u0100"), to, 4));
ASSERT(!mg_json_unescape(mg_str("\\u1000"), to, 4)); ASSERT(!mg_json_unescape(mg_str("\\u1000"), to, 4));
} }