diff options
Diffstat (limited to 'main/utils.c')
-rw-r--r-- | main/utils.c | 44 |
1 files changed, 30 insertions, 14 deletions
diff --git a/main/utils.c b/main/utils.c index d374e69bf..9e51dcde1 100644 --- a/main/utils.c +++ b/main/utils.c @@ -972,33 +972,47 @@ int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed) return -1; } -int ast_dynamic_str_thread_build_va(struct ast_dynamic_str **buf, size_t max_len, +/*! + * core handler for dynamic strings. + * This is not meant to be called directly, but rather through the + * various wrapper macros + * ast_dynamic_str_set(...) + * ast_dynamic_str_append(...) + * ast_dynamic_str_thread_set(...) + * ast_dynamic_str_thread_append(...) + */ +int __ast_dyn_str_helper(struct ast_dynamic_str **buf, size_t max_len, struct ast_threadstorage *ts, int append, const char *fmt, va_list ap) { int res, need; - int offset = (append && (*buf)->len) ? strlen((*buf)->str) : 0; - + int offset = (append && (*buf)->len) ? (*buf)->used : 0; + + if (max_len < 0) + max_len = (*buf)->len; /* don't exceed the allocated space */ + /* + * Ask vsnprintf how much space we need. Remember that vsnprintf + * does not count the final '\0' so we must add 1. + */ res = vsnprintf((*buf)->str + offset, (*buf)->len - offset, fmt, ap); need = res + offset + 1; - /* Check to see if there was not enough space in the string buffer to prepare - * the string. Also, if a maximum length is present, make sure the current - * length is less than the maximum before increasing the size. */ + /* + * If there is not enough space and we are below the max length, + * reallocate the buffer and return a message telling to retry. + */ if (need > (*buf)->len && (max_len == 0 || (*buf)->len < max_len) ) { - /* Set the new size of the string buffer to be the size needed - * to hold the resulting string (res) plus one byte for the - * terminating '\0'. If this size is greater than the max, set - * the new length to be the maximum allowed. */ - if (max_len && max_len < need) + if (max_len && max_len < need) /* truncate as needed */ need = max_len; + /* We can only realloc malloc'ed space. */ + if ((*buf)->type != DS_MALLOC) + return AST_DYNSTR_BUILD_FAILED; *buf = ast_realloc(*buf, need + sizeof(struct ast_dynamic_str)); - if (*buf == NULL) + if (*buf == NULL) /* XXX watch out, we leak memory here */ return AST_DYNSTR_BUILD_FAILED; (*buf)->len = need; - /* Truncate the partial write. */ - (*buf)->str[offset] = '\0'; + (*buf)->str[offset] = '\0'; /* Truncate the partial write. */ if (ts) pthread_setspecific(ts->key, *buf); @@ -1007,6 +1021,8 @@ int ast_dynamic_str_thread_build_va(struct ast_dynamic_str **buf, size_t max_len * vsnprintf() again. */ return AST_DYNSTR_BUILD_RETRY; } + /* update space used, keep in mind the truncation */ + (*buf)->used = (res + offset > (*buf)->len) ? (*buf)->len : res + offset; return res; } |