diff --git a/docs/c-api/util.h/intro.md b/docs/c-api/util.h/intro.md index 62f2f5e6..99d4e407 100644 --- a/docs/c-api/util.h/intro.md +++ b/docs/c-api/util.h/intro.md @@ -3,8 +3,6 @@ title: "Utility API" symbol_kind: "intro" decl_name: "util.h" items: - - { name: mg_asprintf.md } - - { name: mg_avprintf.md } - { name: mg_base64_decode.md } - { name: mg_base64_encode.md } - { name: mg_basic_auth_header.md } diff --git a/docs/c-api/util.h/mg_asprintf.md b/docs/c-api/util.h/mg_asprintf.md deleted file mode 100644 index 10dd1746..00000000 --- a/docs/c-api/util.h/mg_asprintf.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: "mg_asprintf()" -decl_name: "mg_asprintf" -symbol_kind: "func" -signature: | - int mg_asprintf(char **buf, size_t size, const char *fmt, ...); ---- - -Prints message to the buffer. If the buffer is large enough to hold the -message, it returns buffer. If buffer is to small, it allocates a large -enough buffer on heap and returns allocated buffer. -This is a supposed use case: - - char buf[5], *p = buf; - mg_avprintf(&p, sizeof(buf), "%s", "hi there"); - use_p_somehow(p); - if (p != buf) { - free(p); - } - -The purpose of this is to avoid malloc-ing if generated strings are small. - diff --git a/docs/c-api/util.h/mg_avprintf.md b/docs/c-api/util.h/mg_avprintf.md deleted file mode 100644 index aff55db0..00000000 --- a/docs/c-api/util.h/mg_avprintf.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: "mg_avprintf()" -decl_name: "mg_avprintf" -symbol_kind: "func" -signature: | - int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap); ---- - -Same as mg_asprintf, but takes varargs list. - diff --git a/mongoose.c b/mongoose.c index c038df1a..236d5b27 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1480,6 +1480,14 @@ void cs_hmac_sha1(const unsigned char *key, size_t keylen, #define C_DISABLE_BUILTIN_SNPRINTF 0 #endif +#ifndef MG_MALLOC +#define MG_MALLOC malloc +#endif + +#ifndef MG_FREE +#define MG_FREE free +#endif + size_t c_strnlen(const char *s, size_t maxlen) { size_t l = 0; for (; l < maxlen && s[l] != '\0'; l++) { @@ -1812,6 +1820,51 @@ int mg_casecmp(const char *s1, const char *s2) { return mg_ncasecmp(s1, s2, (size_t) ~0); } +int mg_asprintf(char **buf, size_t size, const char *fmt, ...) { + int ret; + va_list ap; + va_start(ap, fmt); + ret = mg_avprintf(buf, size, fmt, ap); + va_end(ap); + return ret; +} + +int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) { + va_list ap_copy; + int len; + + va_copy(ap_copy, ap); + len = vsnprintf(*buf, size, fmt, ap_copy); + va_end(ap_copy); + + if (len < 0) { + /* eCos and Windows are not standard-compliant and return -1 when + * the buffer is too small. Keep allocating larger buffers until we + * succeed or out of memory. */ + *buf = NULL; /* LCOV_EXCL_START */ + while (len < 0) { + MG_FREE(*buf); + size *= 2; + if ((*buf = (char *) MG_MALLOC(size)) == NULL) break; + va_copy(ap_copy, ap); + len = vsnprintf(*buf, size, fmt, ap_copy); + va_end(ap_copy); + } + /* LCOV_EXCL_STOP */ + } else if (len >= (int) size) { + /* Standard-compliant code path. Allocate a buffer that is large enough. */ + if ((*buf = (char *) MG_MALLOC(len + 1)) == NULL) { + len = -1; /* LCOV_EXCL_LINE */ + } else { /* LCOV_EXCL_LINE */ + va_copy(ap_copy, ap); + len = vsnprintf(*buf, len + 1, fmt, ap_copy); + va_end(ap_copy); + } + } + + return len; +} + #endif /* EXCLUDE_COMMON */ #ifdef MG_MODULE_LINES #line 1 "mongoose/src/tun.h" @@ -9123,51 +9176,6 @@ void mg_hexdump_connection(struct mg_connection *nc, const char *path, } #endif -int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) { - va_list ap_copy; - int len; - - va_copy(ap_copy, ap); - len = vsnprintf(*buf, size, fmt, ap_copy); - va_end(ap_copy); - - if (len < 0) { - /* eCos and Windows are not standard-compliant and return -1 when - * the buffer is too small. Keep allocating larger buffers until we - * succeed or out of memory. */ - *buf = NULL; /* LCOV_EXCL_START */ - while (len < 0) { - MG_FREE(*buf); - size *= 2; - if ((*buf = (char *) MG_MALLOC(size)) == NULL) break; - va_copy(ap_copy, ap); - len = vsnprintf(*buf, size, fmt, ap_copy); - va_end(ap_copy); - } - /* LCOV_EXCL_STOP */ - } else if (len >= (int) size) { - /* Standard-compliant code path. Allocate a buffer that is large enough. */ - if ((*buf = (char *) MG_MALLOC(len + 1)) == NULL) { - len = -1; /* LCOV_EXCL_LINE */ - } else { /* LCOV_EXCL_LINE */ - va_copy(ap_copy, ap); - len = vsnprintf(*buf, len + 1, fmt, ap_copy); - va_end(ap_copy); - } - } - - return len; -} - -int mg_asprintf(char **buf, size_t size, const char *fmt, ...) { - int ret; - va_list ap; - va_start(ap, fmt); - ret = mg_avprintf(buf, size, fmt, ap); - va_end(ap); - return ret; -} - int mg_is_big_endian(void) { static const int n = 1; /* TODO(mkm) use compiletime check with 4-byte char literal */ diff --git a/mongoose.h b/mongoose.h index 57d13eed..4a6c13b6 100644 --- a/mongoose.h +++ b/mongoose.h @@ -1869,6 +1869,26 @@ int mg_ncasecmp(const char *s1, const char *s2, size_t len); */ int mg_casecmp(const char *s1, const char *s2); +/* + * Prints message to the buffer. If the buffer is large enough to hold the + * message, it returns buffer. If buffer is to small, it allocates a large + * enough buffer on heap and returns allocated buffer. + * This is a supposed use case: + * + * char buf[5], *p = buf; + * mg_avprintf(&p, sizeof(buf), "%s", "hi there"); + * use_p_somehow(p); + * if (p != buf) { + * free(p); + * } + * + * The purpose of this is to avoid malloc-ing if generated strings are small. + */ +int mg_asprintf(char **buf, size_t size, const char *fmt, ...); + +/* Same as mg_asprintf, but takes varargs list. */ +int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap); + #ifdef __cplusplus } #endif @@ -3763,26 +3783,6 @@ void mg_hexdump_connection(struct mg_connection *nc, const char *path, const void *buf, int num_bytes, int ev); #endif -/* - * Prints message to the buffer. If the buffer is large enough to hold the - * message, it returns buffer. If buffer is to small, it allocates a large - * enough buffer on heap and returns allocated buffer. - * This is a supposed use case: - * - * char buf[5], *p = buf; - * mg_avprintf(&p, sizeof(buf), "%s", "hi there"); - * use_p_somehow(p); - * if (p != buf) { - * free(p); - * } - * - * The purpose of this is to avoid malloc-ing if generated strings are small. - */ -int mg_asprintf(char **buf, size_t size, const char *fmt, ...); - -/* Same as mg_asprintf, but takes varargs list. */ -int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap); - /* * Returns true if target platform is big endian. */