mirror of https://github.com/arendst/Tasmota.git
Extend ext_vsnprintf to auto-malloc buffer
This commit is contained in:
parent
6504b7be54
commit
6951c5aee5
|
@ -202,6 +202,8 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
* snprintf extended
|
* 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)
|
// 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 char ext_invalid_mem[] PROGMEM = "<--INVALID-->";
|
||||||
const uint32_t min_valid_ptr = 0x3F000000; // addresses below this line are 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_list va_cpy;
|
||||||
va_copy(va_cpy, va);
|
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 == '*') {
|
if (*fmt == '*') {
|
||||||
decimals = va_arg(va, int32_t); // skip width argument as int
|
decimals = va_arg(va, int32_t); // skip width argument as int
|
||||||
decimals_ptr = va_cur_ptr4(va, int32_t); // pointer to value on stack
|
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++;
|
fmt++;
|
||||||
// Serial.printf("> decimals=%d, decimals_ptr=0x%08X\n", decimals, decimals_ptr);
|
// 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();
|
// 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);
|
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;
|
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_list va;
|
||||||
va_start(va, fmt);
|
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);
|
va_end(va);
|
||||||
return ret;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -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_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, ...);
|
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);
|
char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, char inbetween);
|
||||||
|
|
||||||
|
|
|
@ -703,25 +703,28 @@ void WSContentFlush(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _WSContentSendBuffer(void) {
|
void _WSContentSendBuffer(const char * content = nullptr) {
|
||||||
int len = strlen(TasmotaGlobal.mqtt_data);
|
if (content == nullptr) {
|
||||||
|
content = TasmotaGlobal.mqtt_data;
|
||||||
|
}
|
||||||
|
int len = strlen(content);
|
||||||
|
|
||||||
if (0 == len) { // No content
|
if (0 == len) { // No content
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (len == sizeof(TasmotaGlobal.mqtt_data)) {
|
// else if (len == sizeof(TasmotaGlobal.mqtt_data)) {
|
||||||
AddLog(LOG_LEVEL_INFO, PSTR("HTP: Content too large"));
|
// AddLog(LOG_LEVEL_INFO, PSTR("HTP: Content too large"));
|
||||||
}
|
// }
|
||||||
else if (len < CHUNKED_BUFFER_SIZE) { // Append chunk buffer with small content
|
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();
|
len = Web.chunk_buffer.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len >= CHUNKED_BUFFER_SIZE) { // Either content or chunk buffer is oversize
|
if (len >= CHUNKED_BUFFER_SIZE) { // Either content or chunk buffer is oversize
|
||||||
WSContentFlush(); // Send chunk buffer before possible content oversize
|
WSContentFlush(); // Send chunk buffer before possible content oversize
|
||||||
}
|
}
|
||||||
if (strlen(TasmotaGlobal.mqtt_data) >= CHUNKED_BUFFER_SIZE) { // Content is oversize
|
if (strlen(content) >= CHUNKED_BUFFER_SIZE) { // Content is oversize
|
||||||
_WSContentSend(TasmotaGlobal.mqtt_data); // Send content
|
_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
|
// This uses char strings. Be aware of sending %% if % is needed
|
||||||
va_list arg;
|
va_list arg;
|
||||||
va_start(arg, formatP);
|
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);
|
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] != '.') {
|
if (D_DECIMAL_SEPARATOR[0] != '.') {
|
||||||
for (uint32_t i = 0; i < len; i++) {
|
for (uint32_t i = 0; i < len; i++) {
|
||||||
if ('.' == TasmotaGlobal.mqtt_data[i]) {
|
if ('.' == content[i]) {
|
||||||
TasmotaGlobal.mqtt_data[i] = D_DECIMAL_SEPARATOR[0];
|
content[i] = D_DECIMAL_SEPARATOR[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_WSContentSendBuffer();
|
_WSContentSendBuffer(content);
|
||||||
|
free(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WSContentStart_P(const char* title, bool auth)
|
void WSContentStart_P(const char* title, bool auth)
|
||||||
|
|
Loading…
Reference in New Issue