diff --git a/lib/default/Ext-printf/src/ext_printf.cpp b/lib/default/Ext-printf/src/ext_printf.cpp index 243c7b4b4..cb2e4d0d8 100644 --- a/lib/default/Ext-printf/src/ext_printf.cpp +++ b/lib/default/Ext-printf/src/ext_printf.cpp @@ -202,6 +202,8 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c /*********************************************************************************************\ * snprintf extended * + * New: if the provided buffer is nullptr, a buffer is allocated on the heap (malloc) + * and returned as a pointer instead of the length of the output (needs casting) \*********************************************************************************************/ // get a fresh malloc allocated string based on the current pointer (can be in PROGMEM) @@ -216,7 +218,7 @@ char * copyStr(const char * str) { const char ext_invalid_mem[] PROGMEM = "<--INVALID-->"; const uint32_t min_valid_ptr = 0x3F000000; // addresses below this line are invalid -int32_t ext_vsnprintf_P(char * buf, size_t buf_len, const char * fmt_P, va_list va) { +int32_t ext_vsnprintf_P(char * out_buf, size_t buf_len, const char * fmt_P, va_list va) { va_list va_cpy; va_copy(va_cpy, va); @@ -242,7 +244,6 @@ int32_t ext_vsnprintf_P(char * buf, size_t buf_len, const char * fmt_P, va_list if (*fmt == '*') { decimals = va_arg(va, int32_t); // skip width argument as int decimals_ptr = va_cur_ptr4(va, int32_t); // pointer to value on stack - const char ** cur_val_ptr = va_cur_ptr4(va, const char*); // pointer to value on stack fmt++; // Serial.printf("> decimals=%d, decimals_ptr=0x%08X\n", decimals, decimals_ptr); } @@ -390,7 +391,24 @@ int32_t ext_vsnprintf_P(char * buf, size_t buf_len, const char * fmt_P, va_list } } // Serial.printf("> format_final=%s\n", fmt_cpy); Serial.flush(); - int32_t ret = vsnprintf_P(buf, buf_len, fmt_cpy, va_cpy); + int32_t ret = 0; // return 0 if unsuccessful + if (out_buf != nullptr) { + ret = vsnprintf_P(out_buf, buf_len, fmt_cpy, va_cpy); + } else { + // if there is no output buffer, we allocate one on the heap + // first we do a dry-run to know the target size + char dummy[2]; + int32_t target_len = vsnprintf_P(dummy, 1, fmt_cpy, va_cpy); + if (target_len >= 0) { + // successful + char * allocated_buf = (char*) malloc(target_len + 1); + if (allocated_buf != nullptr) { + allocated_buf[0] = 0; // default to empty string + vsnprintf_P(allocated_buf, target_len + 1, fmt_cpy, va_cpy); + ret = (int32_t) allocated_buf; + } + } + } va_end(va_cpy); @@ -403,11 +421,25 @@ int32_t ext_vsnprintf_P(char * buf, size_t buf_len, const char * fmt_P, va_list return ret; } -int32_t ext_snprintf_P(char * buf, size_t buf_len, const char * fmt, ...) { +char * ext_vsnprintf_malloc_P(const char * fmt_P, va_list va) { + int32_t ret = ext_vsnprintf_P(nullptr, 0, fmt_P, va); + return (char*) ret; +} + +int32_t ext_snprintf_P(char * out_buf, size_t buf_len, const char * fmt, ...) { va_list va; va_start(va, fmt); - int32_t ret = ext_vsnprintf_P(buf, buf_len, fmt, va); + int32_t ret = ext_vsnprintf_P(out_buf, buf_len, fmt, va); va_end(va); return ret; } + +char * ext_snprintf_malloc_P(const char * fmt, ...) { + va_list va; + va_start(va, fmt); + + int32_t ret = ext_vsnprintf_P(nullptr, 0, fmt, va); + va_end(va); + return (char*) ret; +} diff --git a/lib/default/Ext-printf/src/ext_printf.h b/lib/default/Ext-printf/src/ext_printf.h index 82313cfc7..b3b8585ee 100644 --- a/lib/default/Ext-printf/src/ext_printf.h +++ b/lib/default/Ext-printf/src/ext_printf.h @@ -26,6 +26,8 @@ int32_t ext_vsnprintf_P(char * buf, size_t buf_len, const char * fmt_P, va_list va); int32_t ext_snprintf_P(char * buf, size_t buf_len, const char * fmt, ...); +char * ext_snprintf_malloc_P(const char * fmt, ...); +char * ext_vsnprintf_malloc_P(const char * fmt_P, va_list va); char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, char inbetween); diff --git a/tasmota/xdrv_01_webserver.ino b/tasmota/xdrv_01_webserver.ino index 1ab1f8973..ae0891930 100644 --- a/tasmota/xdrv_01_webserver.ino +++ b/tasmota/xdrv_01_webserver.ino @@ -703,25 +703,28 @@ void WSContentFlush(void) { } } -void _WSContentSendBuffer(void) { - int len = strlen(TasmotaGlobal.mqtt_data); +void _WSContentSendBuffer(const char * content = nullptr) { + if (content == nullptr) { + content = TasmotaGlobal.mqtt_data; + } + int len = strlen(content); if (0 == len) { // No content return; } - else if (len == sizeof(TasmotaGlobal.mqtt_data)) { - AddLog(LOG_LEVEL_INFO, PSTR("HTP: Content too large")); - } + // else if (len == sizeof(TasmotaGlobal.mqtt_data)) { + // AddLog(LOG_LEVEL_INFO, PSTR("HTP: Content too large")); + // } else if (len < CHUNKED_BUFFER_SIZE) { // Append chunk buffer with small content - Web.chunk_buffer += TasmotaGlobal.mqtt_data; + Web.chunk_buffer += content; len = Web.chunk_buffer.length(); } if (len >= CHUNKED_BUFFER_SIZE) { // Either content or chunk buffer is oversize WSContentFlush(); // Send chunk buffer before possible content oversize } - if (strlen(TasmotaGlobal.mqtt_data) >= CHUNKED_BUFFER_SIZE) { // Content is oversize - _WSContentSend(TasmotaGlobal.mqtt_data); // Send content + if (strlen(content) >= CHUNKED_BUFFER_SIZE) { // Content is oversize + _WSContentSend(content); // Send content } } @@ -753,25 +756,21 @@ void WSContentSend_PD(const char* formatP, ...) // Content send snprintf_P ch // This uses char strings. Be aware of sending %% if % is needed va_list arg; va_start(arg, formatP); - int len = ext_vsnprintf_P(TasmotaGlobal.mqtt_data, sizeof(TasmotaGlobal.mqtt_data), formatP, arg); + char * content = ext_vsnprintf_malloc_P(formatP, arg); + if (content == nullptr) { return; } // avoid crash + size_t len = strlen(content); va_end(arg); -#ifdef DEBUG_TASMOTA_CORE - if (len > (sizeof(TasmotaGlobal.mqtt_data) -1)) { - TasmotaGlobal.mqtt_data[33] = '\0'; - DEBUG_CORE_LOG(PSTR("ERROR: WSContentSend_PD size %d > mqtt_data size %d. Start of data [%s...]"), len, sizeof(TasmotaGlobal.mqtt_data), TasmotaGlobal.mqtt_data); - } -#endif - if (D_DECIMAL_SEPARATOR[0] != '.') { for (uint32_t i = 0; i < len; i++) { - if ('.' == TasmotaGlobal.mqtt_data[i]) { - TasmotaGlobal.mqtt_data[i] = D_DECIMAL_SEPARATOR[0]; + if ('.' == content[i]) { + content[i] = D_DECIMAL_SEPARATOR[0]; } } } - _WSContentSendBuffer(); + _WSContentSendBuffer(content); + free(content); } void WSContentStart_P(const char* title, bool auth)