From f2009ebd62a603c9096b3b6b300e55b78630b730 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Thu, 28 Jul 2022 10:18:17 +0100 Subject: [PATCH] Move mg_*printf* decls in fmt.h --- Makefile | 2 +- mongoose.c | 297 ++++++++++++++++++++++++------------------------ mongoose.h | 12 +- src/dbl.c | 135 ---------------------- src/event.c | 2 +- src/fmt.c | 145 ++++++++++++++++++++++- src/fmt.h | 22 ++++ src/fs.c | 2 +- src/fs_packed.c | 1 + src/http.c | 1 + src/json.c | 1 + src/log.c | 2 + src/net.c | 2 +- src/rpc.h | 1 + src/ssi.c | 2 +- src/str.c | 9 -- src/str.h | 17 --- src/ws.c | 1 + 18 files changed, 336 insertions(+), 318 deletions(-) delete mode 100644 src/dbl.c create mode 100644 src/fmt.h diff --git a/Makefile b/Makefile index 2fbec80e..5c62c54e 100644 --- a/Makefile +++ b/Makefile @@ -156,7 +156,7 @@ mongoose.c: Makefile $(wildcard src/*) $(wildcard mip/*.c) (cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/*.c mip/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@ mongoose.h: $(HDRS) Makefile - (cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/config.h src/str.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h mip/mip.h | sed -e 's,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@ + (cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/config.h src/str.h src/fmt.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h mip/mip.h | sed -e 's,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@ clean: rm -rf $(PROG) *.exe *.o *.dSYM unit_test* valgrind_unit_test* ut fuzzer *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb slow-unit* _CL_* infer-out data.txt crash-* test/packed_fs.c pack unpacked diff --git a/mongoose.c b/mongoose.c index bc9837aa..38002ca0 100644 --- a/mongoose.c +++ b/mongoose.c @@ -107,145 +107,6 @@ int mg_base64_decode(const char *src, int n, char *dst) { return len; } -#ifdef MG_ENABLE_LINES -#line 1 "src/dbl.c" -#endif - - -double mg_atod(const char *p, int len, int *numlen) { - double d = 0.0; - int i = 0, sign = 1; - - // Sign - if (i < len && *p == '-') { - sign = -1, i++; - } else if (i < len && *p == '+') { - i++; - } - - // Decimal - for (; i < len && p[i] >= '0' && p[i] <= '9'; i++) { - d *= 10.0; - d += p[i] - '0'; - } - d *= sign; - - // Fractional - if (i < len && p[i] == '.') { - double frac = 0.0, base = 0.1; - i++; - for (; i < len && p[i] >= '0' && p[i] <= '9'; i++) { - frac += base * (p[i] - '0'); - base /= 10.0; - } - d += frac * sign; - } - - // Exponential - if (i < len && (p[i] == 'e' || p[i] == 'E')) { - int j, exp = 0, minus = 0; - i++; - if (i < len && p[i] == '-') minus = 1, i++; - if (i < len && p[i] == '+') i++; - while (i < len && p[i] >= '0' && p[i] <= '9' && exp < 308) - exp = exp * 10 + (p[i++] - '0'); - if (minus) exp = -exp; - for (j = 0; j < exp; j++) d *= 10.0; - for (j = 0; j < -exp; j++) d /= 10.0; - } - - if (numlen != NULL) *numlen = i; - return d; -} - -static int addexp(char *buf, int e, int sign) { - int n = 0; - buf[n++] = 'e'; - buf[n++] = (char) sign; - if (e > 400) return 0; - if (e < 10) buf[n++] = '0'; - if (e >= 100) buf[n++] = (char) (e / 100 + '0'), e -= 100 * (e / 100); - if (e >= 10) buf[n++] = (char) (e / 10 + '0'), e -= 10 * (e / 10); - buf[n++] = (char) (e + '0'); - return n; -} - -static int xisinf(double x) { - union { - double f; - uint64_t u; - } ieee754 = {x}; - return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 && - ((unsigned) ieee754.u == 0); -} - -static int xisnan(double x) { - union { - double f; - uint64_t u; - } ieee754 = {x}; - return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) + - ((unsigned) ieee754.u != 0) > - 0x7ff00000; -} - -size_t mg_dtoa(char *dst, size_t dstlen, double d, int width) { - char buf[40]; - int i, s = 0, n = 0, e = 0; - double t, mul, saved; - if (d == 0.0) return mg_snprintf(dst, dstlen, "%s", "0"); - if (xisinf(d)) return mg_snprintf(dst, dstlen, "%s", d > 0 ? "inf" : "-inf"); - if (xisnan(d)) return mg_snprintf(dst, dstlen, "%s", "nan"); - if (d < 0.0) d = -d, buf[s++] = '-'; - - // Round - saved = d; - mul = 1.0; - while (d >= 10.0 && d / mul >= 10.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; - d += t; - // Calculate exponent, and 'mul' for scientific representation - mul = 1.0; - while (d >= 10.0 && d / mul >= 10.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); - - if (e >= width) { - n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width); - // 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); - // 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); - } else { - for (i = 0, t = mul; t >= 1.0 && s + n < (int) sizeof(buf); i++) { - int ch = (int) (d / t); - if (n > 0 || ch > 0) buf[s + n++] = (char) (ch + '0'); - d -= ch * t; - t /= 10.0; - } - // printf(" --> [%g] -> %g %g (%d) [%.*s]\n", saved, d, t, n, s + n, buf); - if (n == 0) buf[s++] = '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++] = '.'; - // printf(" 1--> [%g] -> [%.*s]\n", saved, s + n, buf); - for (i = 0, t = 0.1; s + n < (int) sizeof(buf) && n < width; i++) { - int ch = (int) (d / t); - buf[s + n++] = (char) (ch + '0'); - d -= ch * t; - 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 - buf[s + n] = '\0'; - return mg_snprintf(dst, dstlen, "%s", buf); -} - #ifdef MG_ENABLE_LINES #line 1 "src/dns.c" #endif @@ -583,6 +444,15 @@ size_t mg_asprintf(char **buf, size_t size, const char *fmt, ...) { return ret; } +size_t mg_snprintf(char *buf, size_t len, const char *fmt, ...) { + va_list ap; + size_t n; + va_start(ap, fmt); + n = mg_vsnprintf(buf, len, fmt, &ap); + va_end(ap); + return n; +} + char *mg_vmprintf(const char *fmt, va_list ap) { char *s = NULL; mg_vasprintf(&s, 0, fmt, ap); @@ -649,6 +519,140 @@ static bool is_digit(int c) { return c >= '0' && c <= '9'; } +double mg_atod(const char *p, int len, int *numlen) { + double d = 0.0; + int i = 0, sign = 1; + + // Sign + if (i < len && *p == '-') { + sign = -1, i++; + } else if (i < len && *p == '+') { + i++; + } + + // Decimal + for (; i < len && p[i] >= '0' && p[i] <= '9'; i++) { + d *= 10.0; + d += p[i] - '0'; + } + d *= sign; + + // Fractional + if (i < len && p[i] == '.') { + double frac = 0.0, base = 0.1; + i++; + for (; i < len && p[i] >= '0' && p[i] <= '9'; i++) { + frac += base * (p[i] - '0'); + base /= 10.0; + } + d += frac * sign; + } + + // Exponential + if (i < len && (p[i] == 'e' || p[i] == 'E')) { + int j, exp = 0, minus = 0; + i++; + if (i < len && p[i] == '-') minus = 1, i++; + if (i < len && p[i] == '+') i++; + while (i < len && p[i] >= '0' && p[i] <= '9' && exp < 308) + exp = exp * 10 + (p[i++] - '0'); + if (minus) exp = -exp; + for (j = 0; j < exp; j++) d *= 10.0; + for (j = 0; j < -exp; j++) d /= 10.0; + } + + if (numlen != NULL) *numlen = i; + return d; +} + +static int addexp(char *buf, int e, int sign) { + int n = 0; + buf[n++] = 'e'; + buf[n++] = (char) sign; + if (e > 400) return 0; + if (e < 10) buf[n++] = '0'; + if (e >= 100) buf[n++] = (char) (e / 100 + '0'), e -= 100 * (e / 100); + if (e >= 10) buf[n++] = (char) (e / 10 + '0'), e -= 10 * (e / 10); + buf[n++] = (char) (e + '0'); + return n; +} + +static int xisinf(double x) { + union { + double f; + uint64_t u; + } ieee754 = {x}; + return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 && + ((unsigned) ieee754.u == 0); +} + +static int xisnan(double x) { + union { + double f; + uint64_t u; + } ieee754 = {x}; + return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) + + ((unsigned) ieee754.u != 0) > + 0x7ff00000; +} + +size_t mg_dtoa(char *dst, size_t dstlen, double d, int width) { + char buf[40]; + int i, s = 0, n = 0, e = 0; + double t, mul, saved; + if (d == 0.0) return mg_snprintf(dst, dstlen, "%s", "0"); + if (xisinf(d)) return mg_snprintf(dst, dstlen, "%s", d > 0 ? "inf" : "-inf"); + if (xisnan(d)) return mg_snprintf(dst, dstlen, "%s", "nan"); + if (d < 0.0) d = -d, buf[s++] = '-'; + + // Round + saved = d; + mul = 1.0; + while (d >= 10.0 && d / mul >= 10.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; + d += t; + // Calculate exponent, and 'mul' for scientific representation + mul = 1.0; + while (d >= 10.0 && d / mul >= 10.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); + + if (e >= width) { + n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width); + // 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); + // 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); + } else { + for (i = 0, t = mul; t >= 1.0 && s + n < (int) sizeof(buf); i++) { + int ch = (int) (d / t); + if (n > 0 || ch > 0) buf[s + n++] = (char) (ch + '0'); + d -= ch * t; + t /= 10.0; + } + // printf(" --> [%g] -> %g %g (%d) [%.*s]\n", saved, d, t, n, s + n, buf); + if (n == 0) buf[s++] = '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++] = '.'; + // printf(" 1--> [%g] -> [%.*s]\n", saved, s + n, buf); + for (i = 0, t = 0.1; s + n < (int) sizeof(buf) && n < width; i++) { + int ch = (int) (d / t); + buf[s + n++] = (char) (ch + '0'); + d -= ch * t; + 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 + buf[s + n] = '\0'; + return mg_snprintf(dst, dstlen, "%s", buf); +} + size_t mg_lld(char *buf, int64_t val, bool is_signed, bool is_hex) { const char *letters = "0123456789abcdef"; uint64_t v = (uint64_t) val; @@ -1044,6 +1048,7 @@ struct mg_fs mg_fs_fat = {ff_stat, ff_list, ff_open, ff_close, ff_read, + struct packed_file { const char *data; size_t size; @@ -1424,6 +1429,7 @@ struct mg_fs mg_fs_posix = {p_stat, p_list, p_open, p_close, p_read, + // Multipart POST example: // --xyz // Content-Disposition: form-data; name="val" @@ -2437,6 +2443,7 @@ void mg_iobuf_free(struct mg_iobuf *io) { + static const char *escapeseq(int esc) { return esc ? "\b\f\n\r\t\\\"" : "bfnrt\\\""; } @@ -2696,6 +2703,8 @@ long mg_json_get_long(struct mg_str json, const char *path, long dflt) { + + static void default_logger(unsigned char c) { putchar(c); (void) c; @@ -4845,15 +4854,6 @@ bool mg_commalist(struct mg_str *s, struct mg_str *k, struct mg_str *v) { return mg_split(s, k, v, ','); } -size_t mg_snprintf(char *buf, size_t len, const char *fmt, ...) { - va_list ap; - size_t n; - va_start(ap, fmt); - n = mg_vsnprintf(buf, len, fmt, &ap); - va_end(ap); - return n; -} - char *mg_hex(const void *buf, size_t len, char *to) { const unsigned char *p = (const unsigned char *) buf; const char *hex = "0123456789abcdef"; @@ -5618,6 +5618,7 @@ uint64_t mg_millis(void) { + struct ws_msg { uint8_t flags; size_t header_len; diff --git a/mongoose.h b/mongoose.h index 89bea842..f918ccba 100644 --- a/mongoose.h +++ b/mongoose.h @@ -744,16 +744,21 @@ unsigned long mg_unhexn(const char *s, size_t len); int mg_check_ip_acl(struct mg_str acl, uint32_t remote_ip); int64_t mg_to64(struct mg_str str); uint64_t mg_tou64(struct mg_str str); -size_t mg_lld(char *buf, int64_t val, bool is_signed, bool is_hex); -double mg_atod(const char *buf, int len, int *numlen); -size_t mg_dtoa(char *buf, size_t len, double d, int width); char *mg_remove_double_dots(char *s); + + + + typedef void (*mg_pfn_t)(char, void *); // Custom putchar typedef size_t (*mg_pm_t)(mg_pfn_t, void *, va_list *); // %M printer void mg_pfn_realloc(char ch, void *param); // Print to malloced str void mg_pfn_iobuf(char ch, void *param); // Print to iobuf +size_t mg_lld(char *buf, int64_t val, bool is_signed, bool is_hex); +double mg_atod(const char *buf, int len, int *numlen); +size_t mg_dtoa(char *buf, size_t len, double d, int width); + size_t mg_vrprintf(void (*)(char, void *), void *, const char *fmt, va_list *); size_t mg_rprintf(void (*fn)(char, void *), void *, const char *fmt, ...); size_t mg_vsnprintf(char *buf, size_t len, const char *fmt, va_list *ap); @@ -1356,6 +1361,7 @@ char *mg_json_get_b64(struct mg_str json, const char *path, int *len); + // JSON-RPC request descriptor struct mg_rpc_req { struct mg_str frame; // Request, e.g. {"id":1,"method":"add","params":[1,2]} diff --git a/src/dbl.c b/src/dbl.c deleted file mode 100644 index 9e45dcec..00000000 --- a/src/dbl.c +++ /dev/null @@ -1,135 +0,0 @@ -#include "str.h" - -double mg_atod(const char *p, int len, int *numlen) { - double d = 0.0; - int i = 0, sign = 1; - - // Sign - if (i < len && *p == '-') { - sign = -1, i++; - } else if (i < len && *p == '+') { - i++; - } - - // Decimal - for (; i < len && p[i] >= '0' && p[i] <= '9'; i++) { - d *= 10.0; - d += p[i] - '0'; - } - d *= sign; - - // Fractional - if (i < len && p[i] == '.') { - double frac = 0.0, base = 0.1; - i++; - for (; i < len && p[i] >= '0' && p[i] <= '9'; i++) { - frac += base * (p[i] - '0'); - base /= 10.0; - } - d += frac * sign; - } - - // Exponential - if (i < len && (p[i] == 'e' || p[i] == 'E')) { - int j, exp = 0, minus = 0; - i++; - if (i < len && p[i] == '-') minus = 1, i++; - if (i < len && p[i] == '+') i++; - while (i < len && p[i] >= '0' && p[i] <= '9' && exp < 308) - exp = exp * 10 + (p[i++] - '0'); - if (minus) exp = -exp; - for (j = 0; j < exp; j++) d *= 10.0; - for (j = 0; j < -exp; j++) d /= 10.0; - } - - if (numlen != NULL) *numlen = i; - return d; -} - -static int addexp(char *buf, int e, int sign) { - int n = 0; - buf[n++] = 'e'; - buf[n++] = (char) sign; - if (e > 400) return 0; - if (e < 10) buf[n++] = '0'; - if (e >= 100) buf[n++] = (char) (e / 100 + '0'), e -= 100 * (e / 100); - if (e >= 10) buf[n++] = (char) (e / 10 + '0'), e -= 10 * (e / 10); - buf[n++] = (char) (e + '0'); - return n; -} - -static int xisinf(double x) { - union { - double f; - uint64_t u; - } ieee754 = {x}; - return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 && - ((unsigned) ieee754.u == 0); -} - -static int xisnan(double x) { - union { - double f; - uint64_t u; - } ieee754 = {x}; - return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) + - ((unsigned) ieee754.u != 0) > - 0x7ff00000; -} - -size_t mg_dtoa(char *dst, size_t dstlen, double d, int width) { - char buf[40]; - int i, s = 0, n = 0, e = 0; - double t, mul, saved; - if (d == 0.0) return mg_snprintf(dst, dstlen, "%s", "0"); - if (xisinf(d)) return mg_snprintf(dst, dstlen, "%s", d > 0 ? "inf" : "-inf"); - if (xisnan(d)) return mg_snprintf(dst, dstlen, "%s", "nan"); - if (d < 0.0) d = -d, buf[s++] = '-'; - - // Round - saved = d; - mul = 1.0; - while (d >= 10.0 && d / mul >= 10.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; - d += t; - // Calculate exponent, and 'mul' for scientific representation - mul = 1.0; - while (d >= 10.0 && d / mul >= 10.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); - - if (e >= width) { - n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width); - // 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); - // 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); - } else { - for (i = 0, t = mul; t >= 1.0 && s + n < (int) sizeof(buf); i++) { - int ch = (int) (d / t); - if (n > 0 || ch > 0) buf[s + n++] = (char) (ch + '0'); - d -= ch * t; - t /= 10.0; - } - // printf(" --> [%g] -> %g %g (%d) [%.*s]\n", saved, d, t, n, s + n, buf); - if (n == 0) buf[s++] = '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++] = '.'; - // printf(" 1--> [%g] -> [%.*s]\n", saved, s + n, buf); - for (i = 0, t = 0.1; s + n < (int) sizeof(buf) && n < width; i++) { - int ch = (int) (d / t); - buf[s + n++] = (char) (ch + '0'); - d -= ch * t; - 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 - buf[s + n] = '\0'; - return mg_snprintf(dst, dstlen, "%s", buf); -} diff --git a/src/event.c b/src/event.c index 0e5391b9..f8fefa23 100644 --- a/src/event.c +++ b/src/event.c @@ -1,7 +1,7 @@ #include "event.h" +#include "fmt.h" #include "log.h" #include "net.h" -#include "util.h" void mg_call(struct mg_connection *c, int ev, void *ev_data) { // Run user-defined handler first, in order to give it an ability diff --git a/src/fmt.c b/src/fmt.c index a3bc03c0..930d9d6f 100644 --- a/src/fmt.c +++ b/src/fmt.c @@ -1,5 +1,5 @@ +#include "fmt.h" #include "iobuf.h" -#include "str.h" size_t mg_vasprintf(char **buf, size_t size, const char *fmt, va_list ap) { va_list ap_copy; @@ -32,6 +32,15 @@ size_t mg_asprintf(char **buf, size_t size, const char *fmt, ...) { return ret; } +size_t mg_snprintf(char *buf, size_t len, const char *fmt, ...) { + va_list ap; + size_t n; + va_start(ap, fmt); + n = mg_vsnprintf(buf, len, fmt, &ap); + va_end(ap); + return n; +} + char *mg_vmprintf(const char *fmt, va_list ap) { char *s = NULL; mg_vasprintf(&s, 0, fmt, ap); @@ -98,6 +107,140 @@ static bool is_digit(int c) { return c >= '0' && c <= '9'; } +double mg_atod(const char *p, int len, int *numlen) { + double d = 0.0; + int i = 0, sign = 1; + + // Sign + if (i < len && *p == '-') { + sign = -1, i++; + } else if (i < len && *p == '+') { + i++; + } + + // Decimal + for (; i < len && p[i] >= '0' && p[i] <= '9'; i++) { + d *= 10.0; + d += p[i] - '0'; + } + d *= sign; + + // Fractional + if (i < len && p[i] == '.') { + double frac = 0.0, base = 0.1; + i++; + for (; i < len && p[i] >= '0' && p[i] <= '9'; i++) { + frac += base * (p[i] - '0'); + base /= 10.0; + } + d += frac * sign; + } + + // Exponential + if (i < len && (p[i] == 'e' || p[i] == 'E')) { + int j, exp = 0, minus = 0; + i++; + if (i < len && p[i] == '-') minus = 1, i++; + if (i < len && p[i] == '+') i++; + while (i < len && p[i] >= '0' && p[i] <= '9' && exp < 308) + exp = exp * 10 + (p[i++] - '0'); + if (minus) exp = -exp; + for (j = 0; j < exp; j++) d *= 10.0; + for (j = 0; j < -exp; j++) d /= 10.0; + } + + if (numlen != NULL) *numlen = i; + return d; +} + +static int addexp(char *buf, int e, int sign) { + int n = 0; + buf[n++] = 'e'; + buf[n++] = (char) sign; + if (e > 400) return 0; + if (e < 10) buf[n++] = '0'; + if (e >= 100) buf[n++] = (char) (e / 100 + '0'), e -= 100 * (e / 100); + if (e >= 10) buf[n++] = (char) (e / 10 + '0'), e -= 10 * (e / 10); + buf[n++] = (char) (e + '0'); + return n; +} + +static int xisinf(double x) { + union { + double f; + uint64_t u; + } ieee754 = {x}; + return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 && + ((unsigned) ieee754.u == 0); +} + +static int xisnan(double x) { + union { + double f; + uint64_t u; + } ieee754 = {x}; + return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) + + ((unsigned) ieee754.u != 0) > + 0x7ff00000; +} + +size_t mg_dtoa(char *dst, size_t dstlen, double d, int width) { + char buf[40]; + int i, s = 0, n = 0, e = 0; + double t, mul, saved; + if (d == 0.0) return mg_snprintf(dst, dstlen, "%s", "0"); + if (xisinf(d)) return mg_snprintf(dst, dstlen, "%s", d > 0 ? "inf" : "-inf"); + if (xisnan(d)) return mg_snprintf(dst, dstlen, "%s", "nan"); + if (d < 0.0) d = -d, buf[s++] = '-'; + + // Round + saved = d; + mul = 1.0; + while (d >= 10.0 && d / mul >= 10.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; + d += t; + // Calculate exponent, and 'mul' for scientific representation + mul = 1.0; + while (d >= 10.0 && d / mul >= 10.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); + + if (e >= width) { + n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width); + // 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); + // 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); + } else { + for (i = 0, t = mul; t >= 1.0 && s + n < (int) sizeof(buf); i++) { + int ch = (int) (d / t); + if (n > 0 || ch > 0) buf[s + n++] = (char) (ch + '0'); + d -= ch * t; + t /= 10.0; + } + // printf(" --> [%g] -> %g %g (%d) [%.*s]\n", saved, d, t, n, s + n, buf); + if (n == 0) buf[s++] = '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++] = '.'; + // printf(" 1--> [%g] -> [%.*s]\n", saved, s + n, buf); + for (i = 0, t = 0.1; s + n < (int) sizeof(buf) && n < width; i++) { + int ch = (int) (d / t); + buf[s + n++] = (char) (ch + '0'); + d -= ch * t; + 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 + buf[s + n] = '\0'; + return mg_snprintf(dst, dstlen, "%s", buf); +} + size_t mg_lld(char *buf, int64_t val, bool is_signed, bool is_hex) { const char *letters = "0123456789abcdef"; uint64_t v = (uint64_t) val; diff --git a/src/fmt.h b/src/fmt.h new file mode 100644 index 00000000..33f6ea1e --- /dev/null +++ b/src/fmt.h @@ -0,0 +1,22 @@ +#pragma once + +#include "arch.h" +#include "iobuf.h" + +typedef void (*mg_pfn_t)(char, void *); // Custom putchar +typedef size_t (*mg_pm_t)(mg_pfn_t, void *, va_list *); // %M printer +void mg_pfn_realloc(char ch, void *param); // Print to malloced str +void mg_pfn_iobuf(char ch, void *param); // Print to iobuf + +size_t mg_lld(char *buf, int64_t val, bool is_signed, bool is_hex); +double mg_atod(const char *buf, int len, int *numlen); +size_t mg_dtoa(char *buf, size_t len, double d, int width); + +size_t mg_vrprintf(void (*)(char, void *), void *, const char *fmt, va_list *); +size_t mg_rprintf(void (*fn)(char, void *), void *, const char *fmt, ...); +size_t mg_vsnprintf(char *buf, size_t len, const char *fmt, va_list *ap); +size_t mg_snprintf(char *, size_t, const char *fmt, ...); +size_t mg_asprintf(char **, size_t, const char *fmt, ...); +size_t mg_vasprintf(char **buf, size_t size, const char *fmt, va_list ap); +char *mg_mprintf(const char *fmt, ...); +char *mg_vmprintf(const char *fmt, va_list ap); diff --git a/src/fs.c b/src/fs.c index ad329f2b..0d5e070c 100644 --- a/src/fs.c +++ b/src/fs.c @@ -1,5 +1,5 @@ #include "fs.h" -#include "util.h" +#include "fmt.h" struct mg_fd *mg_fs_open(struct mg_fs *fs, const char *path, int flags) { struct mg_fd *fd = (struct mg_fd *) calloc(1, sizeof(*fd)); diff --git a/src/fs_packed.c b/src/fs_packed.c index 179666fb..195e9ae7 100644 --- a/src/fs_packed.c +++ b/src/fs_packed.c @@ -1,3 +1,4 @@ +#include "fmt.h" #include "fs.h" #include "str.h" diff --git a/src/http.c b/src/http.c index f5605fb4..f1033ca2 100644 --- a/src/http.c +++ b/src/http.c @@ -1,6 +1,7 @@ #include "http.h" #include "arch.h" #include "base64.h" +#include "fmt.h" #include "log.h" #include "net.h" #include "ssi.h" diff --git a/src/json.c b/src/json.c index 00d6f1da..28c45274 100644 --- a/src/json.c +++ b/src/json.c @@ -1,5 +1,6 @@ #include "json.h" #include "base64.h" +#include "fmt.h" static const char *escapeseq(int esc) { return esc ? "\b\f\n\r\t\\\"" : "bfnrt\\\""; diff --git a/src/log.c b/src/log.c index 48eb124f..0caca063 100644 --- a/src/log.c +++ b/src/log.c @@ -1,4 +1,6 @@ #include "log.h" +#include "fmt.h" +#include "str.h" #include "util.h" static void default_logger(unsigned char c) { diff --git a/src/net.c b/src/net.c index f3c0dd03..0330915b 100644 --- a/src/net.c +++ b/src/net.c @@ -1,9 +1,9 @@ #include "net.h" #include "dns.h" +#include "fmt.h" #include "log.h" #include "timer.h" #include "tls.h" -#include "util.h" size_t mg_vprintf(struct mg_connection *c, const char *fmt, va_list ap) { size_t old = c->send.len; diff --git a/src/rpc.h b/src/rpc.h index 2af75f93..b16ae7e4 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -1,4 +1,5 @@ #pragma once +#include "fmt.h" #include "json.h" // JSON-RPC request descriptor diff --git a/src/ssi.c b/src/ssi.c index 55c3085a..99215171 100644 --- a/src/ssi.c +++ b/src/ssi.c @@ -1,6 +1,6 @@ #include "ssi.h" +#include "fmt.h" #include "log.h" -#include "util.h" #ifndef MG_MAX_SSI_DEPTH #define MG_MAX_SSI_DEPTH 5 diff --git a/src/str.c b/src/str.c index b5aaaf19..329a067d 100644 --- a/src/str.c +++ b/src/str.c @@ -155,15 +155,6 @@ bool mg_commalist(struct mg_str *s, struct mg_str *k, struct mg_str *v) { return mg_split(s, k, v, ','); } -size_t mg_snprintf(char *buf, size_t len, const char *fmt, ...) { - va_list ap; - size_t n; - va_start(ap, fmt); - n = mg_vsnprintf(buf, len, fmt, &ap); - va_end(ap); - return n; -} - char *mg_hex(const void *buf, size_t len, char *to) { const unsigned char *p = (const unsigned char *) buf; const char *hex = "0123456789abcdef"; diff --git a/src/str.h b/src/str.h index 883f2f36..597d2ad7 100644 --- a/src/str.h +++ b/src/str.h @@ -37,21 +37,4 @@ unsigned long mg_unhexn(const char *s, size_t len); int mg_check_ip_acl(struct mg_str acl, uint32_t remote_ip); int64_t mg_to64(struct mg_str str); uint64_t mg_tou64(struct mg_str str); -size_t mg_lld(char *buf, int64_t val, bool is_signed, bool is_hex); -double mg_atod(const char *buf, int len, int *numlen); -size_t mg_dtoa(char *buf, size_t len, double d, int width); char *mg_remove_double_dots(char *s); - -typedef void (*mg_pfn_t)(char, void *); // Custom putchar -typedef size_t (*mg_pm_t)(mg_pfn_t, void *, va_list *); // %M printer -void mg_pfn_realloc(char ch, void *param); // Print to malloced str -void mg_pfn_iobuf(char ch, void *param); // Print to iobuf - -size_t mg_vrprintf(void (*)(char, void *), void *, const char *fmt, va_list *); -size_t mg_rprintf(void (*fn)(char, void *), void *, const char *fmt, ...); -size_t mg_vsnprintf(char *buf, size_t len, const char *fmt, va_list *ap); -size_t mg_snprintf(char *, size_t, const char *fmt, ...); -size_t mg_asprintf(char **, size_t, const char *fmt, ...); -size_t mg_vasprintf(char **buf, size_t size, const char *fmt, va_list ap); -char *mg_mprintf(const char *fmt, ...); -char *mg_vmprintf(const char *fmt, va_list ap); diff --git a/src/ws.c b/src/ws.c index 243652b5..6099d2b5 100644 --- a/src/ws.c +++ b/src/ws.c @@ -1,6 +1,7 @@ #include "ws.h" #include "base64.h" +#include "fmt.h" #include "http.h" #include "log.h" #include "sha1.h"