diff options
-rw-r--r-- | include/asterisk/stringfields.h | 12 | ||||
-rw-r--r-- | main/utils.c | 56 |
2 files changed, 44 insertions, 24 deletions
diff --git a/include/asterisk/stringfields.h b/include/asterisk/stringfields.h index ded54a47e..9c48bfda2 100644 --- a/include/asterisk/stringfields.h +++ b/include/asterisk/stringfields.h @@ -183,7 +183,7 @@ ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr */ void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, - const ast_string_field *ptr, const char *format, ...) __attribute__((format(printf, 4, 5))); + ast_string_field *ptr, const char *format, ...) __attribute__((format(printf, 4, 5))); /*! \internal @@ -198,7 +198,7 @@ void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr, */ void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, - const ast_string_field *ptr, const char *format, va_list a1, va_list a2) __attribute__((format(printf, 4, 0))); + ast_string_field *ptr, const char *format, va_list a1, va_list a2) __attribute__((format(printf, 4, 0))); /*! \brief Declare a string field @@ -287,7 +287,7 @@ int __ast_string_field_init(struct ast_string_field_mgr *mgr, \return nothing */ #define ast_string_field_ptr_build(x, ptr, fmt, args...) \ - __ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, ptr, fmt, args) + __ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) ptr, fmt, args) /*! \brief Set a field to a complex (built) value @@ -298,7 +298,7 @@ int __ast_string_field_init(struct ast_string_field_mgr *mgr, \return nothing */ #define ast_string_field_build(x, field, fmt, args...) \ - __ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, &(x)->field, fmt, args) + __ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) &(x)->field, fmt, args) /*! \brief Set a field to a complex (built) value with prebuilt va_lists. @@ -310,7 +310,7 @@ int __ast_string_field_init(struct ast_string_field_mgr *mgr, \return nothing */ #define ast_string_field_ptr_build_va(x, ptr, fmt, args1, args2) \ - __ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, ptr, fmt, args1, args2) + __ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) ptr, fmt, args1, args2) /*! \brief Set a field to a complex (built) value @@ -322,6 +322,6 @@ int __ast_string_field_init(struct ast_string_field_mgr *mgr, \return nothing */ #define ast_string_field_build_va(x, field, fmt, args1, args2) \ - __ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, &(x)->field, fmt, args1, args2) + __ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) &(x)->field, fmt, args1, args2) #endif /* _ASTERISK_STRINGFIELDS_H */ diff --git a/main/utils.c b/main/utils.c index 61638f9e4..3a5028979 100644 --- a/main/utils.c +++ b/main/utils.c @@ -1587,38 +1587,58 @@ int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr, size_t needed, void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, - const ast_string_field *ptr, const char *format, va_list ap1, va_list ap2) + ast_string_field *ptr, const char *format, va_list ap1, va_list ap2) { size_t needed; - char *dst = (*pool_head)->base + mgr->used; - const char **p = (const char **) ptr; + size_t available; size_t space = mgr->size - mgr->used; + char *target; - /* try to write using available space */ - needed = vsnprintf(dst, space, format, ap1) + 1; - - va_end(ap1); + /* if the field already has space allocated, try to reuse it; + otherwise, use the empty space at the end of the current + pool + */ + if ((*ptr)[0] != '0') { + target = (char *) *ptr; + available = strlen(target); + } else { + target = (*pool_head)->base + mgr->used; + available = space; + } - if (needed > space) { /* if it fails, reallocate */ - size_t new_size = mgr->size * 2; + needed = vsnprintf(target, available, format, ap1) + 1; - while (new_size < needed) - new_size *= 2; + va_end(ap1); - if (add_string_pool(mgr, pool_head, new_size)) - return; + if (needed > available) { + /* if the space needed can be satisfied by using the current + pool (which could only occur if we tried to use the field's + allocated space and failed), then use that space; otherwise + allocate a new pool + */ + if (needed > space) { + size_t new_size = mgr->size * 2; + + while (new_size < needed) + new_size *= 2; + + if (add_string_pool(mgr, pool_head, new_size)) + return; + } - dst = (*pool_head)->base + mgr->used; - vsprintf(dst, format, ap2); + target = (*pool_head)->base + mgr->used; + vsprintf(target, format, ap2); } - mgr->last_alloc = *p = dst; - mgr->used += needed; + if (*ptr != target) { + mgr->last_alloc = *ptr = target; + mgr->used += needed; + } } void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head, - const ast_string_field *ptr, const char *format, ...) + ast_string_field *ptr, const char *format, ...) { va_list ap1, ap2; |