diff --git a/include/asterisk/stringfields.h b/include/asterisk/stringfields.h index 8b32f9ee79..3a99cf5dc7 100644 --- a/include/asterisk/stringfields.h +++ b/include/asterisk/stringfields.h @@ -123,6 +123,7 @@ struct ast_string_field_mgr { size_t size; /*!< the total size of the current pool */ size_t space; /*!< the space available in the current pool */ size_t used; /*!< the space used in the current pool */ + ast_string_field last_alloc; /*!< the last field allocated */ }; /*! @@ -137,6 +138,24 @@ struct ast_string_field_mgr { int __ast_string_field_init(struct ast_string_field_mgr *mgr, size_t size, ast_string_field *fields, int num_fields); +/*! + \internal + \brief Attempt to 'grow' an already allocated field to a larger size + \param mgr Pointer to the pool manager structure + \param needed Amount of space needed for this field + \param fields Pointer to the first entry of the field array + \param index Index position of the field within the structure + \return 0 on success, non-zero on failure + + This function will attempt to increase the amount of space allocated to + an existing field to the amount requested; this is only possible if the + field was the last field allocated from the current storage pool and + the pool has enough space available. If so, the additional space will be + allocated to this field and the field's address will not be changed. +*/ +int __ast_string_field_index_grow(struct ast_string_field_mgr *mgr, size_t needed, + ast_string_field *fields, int index); + /*! \internal \brief Allocate space for a field @@ -180,8 +199,8 @@ void __ast_string_field_index_build(struct ast_string_field_mgr *mgr, \return nothing */ void __ast_string_field_index_build_va(struct ast_string_field_mgr *mgr, - ast_string_field *fields, int num_fields, - int index, const char *format, va_list a1, va_list a2); + ast_string_field *fields, int num_fields, + int index, const char *format, va_list a1, va_list a2); /*! \brief Declare a string field @@ -234,36 +253,36 @@ void __ast_string_field_index_build_va(struct ast_string_field_mgr *mgr, \return nothing */ #define ast_string_field_index_set(x, index, data) do { \ - char *__zz__ = (char*)(x)->__begin_field[index]; \ - size_t __dlen__ = strlen(data); \ - if( __dlen__ == 0 ) { (x)->__begin_field[index] = __ast_string_field_empty; \ + char *__zz__ = (char*) (x)->__begin_field[index]; \ + size_t __dlen__ = strlen(data) + 1; \ + if ( __dlen__ == 1 ) {\ + (x)->__begin_field[index] = __ast_string_field_empty; \ } else { \ - if( __zz__[0] != 0 && __dlen__ <= strlen(__zz__) ) { \ - strcpy(__zz__, data); \ - } else { \ - if (((x)->__begin_field[index] = __ast_string_field_alloc_space(&(x)->__field_mgr, __dlen__ + 1, &(x)->__begin_field[0], ast_string_field_count(x)))) \ - strcpy((char*)(x)->__begin_field[index], data); \ - } \ - } \ + if (!__ast_string_field_index_grow(&(x)->__field_mgr, __dlen__, &(x)->__begin_field[0], index)) { \ + memcpy(__zz__, data, __dlen__); \ + } else { \ + if (((x)->__begin_field[index] = __ast_string_field_alloc_space(&(x)->__field_mgr, __dlen__, &(x)->__begin_field[0], ast_string_field_count(x)))) \ + memcpy((char*) (x)->__begin_field[index], data, __dlen__); \ + } \ + } \ } while (0) -#ifdef FOR_TEST #define ast_string_field_index_logset(x, index, data, logstr) do { \ - char *__zz__ = (char*)(x)->__begin_field[index]; \ - size_t __dlen__ = strlen(data); \ - if( __dlen__ == 0 ) { (x)->__begin_field[index] = __ast_string_field_empty; \ + char *__zz__ = (char*) (x)->__begin_field[index]; \ + size_t __dlen__ = strlen(data) + 1; \ + if ( __dlen__ == 1 ) {\ + (x)->__begin_field[index] = __ast_string_field_empty; \ } else { \ - if( __zz__[0] != 0 && __dlen__ <= strlen(__zz__) ) { \ - ast_verbose("%s: ======replacing '%s' with '%s'\n", logstr, __zz__, data); \ - strcpy(__zz__, data); \ - } else { \ - ast_verbose("%s: ++++++allocating room for '%s' to replace '%s'\n", logstr, data, __zz__); \ - if (((x)->__begin_field[index] = __ast_string_field_alloc_space(&(x)->__field_mgr, __dlen__ + 1, &(x)->__begin_field[0], ast_string_field_count(x)))) \ - strcpy((char*)(x)->__begin_field[index], data); \ - } \ - } \ + if (!__ast_string_field_index_grow(&(x)->__field_mgr, __dlen__, &(x)->__begin_field[0], index)) { \ + ast_verbose("%s: ======replacing '%s' with '%s'\n", logstr, __zz__, data); \ + memcpy(__zz__, data, __dlen__); \ + } else { \ + if (((x)->__begin_field[index] = __ast_string_field_alloc_space(&(x)->__field_mgr, __dlen__, &(x)->__begin_field[0], ast_string_field_count(x)))) \ + ast_verbose("%s: ++++++allocating room for '%s' to replace '%s'\n", logstr, data, __zz__); \ + memcpy((char*) (x)->__begin_field[index], data, __dlen__); \ + } \ + } \ } while (0) -#endif /*! \brief Set a field to a simple string value @@ -275,10 +294,8 @@ void __ast_string_field_index_build_va(struct ast_string_field_mgr *mgr, #define ast_string_field_set(x, field, data) \ ast_string_field_index_set(x, ast_string_field_index(x, field), data) -#ifdef FOR_TEST #define ast_string_field_logset(x, field, data, logstr) \ ast_string_field_index_logset(x, ast_string_field_index(x, field), data, logstr) -#endif /*! \brief Set a field to a complex (built) value diff --git a/main/utils.c b/main/utils.c index 74ecfaf578..8906eff119 100644 --- a/main/utils.c +++ b/main/utils.c @@ -1223,6 +1223,7 @@ static int add_string_pool(struct ast_string_field_mgr *mgr, size_t size) mgr->size = size; mgr->space = size; mgr->used = 0; + mgr->last_alloc = NULL; return 0; } @@ -1259,12 +1260,36 @@ ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr result = mgr->pool->base + mgr->used; mgr->used += needed; mgr->space -= needed; + mgr->last_alloc = result; return result; } +int __ast_string_field_index_grow(struct ast_string_field_mgr *mgr, size_t needed, + ast_string_field *fields, int index) +{ + int grow = needed - (strlen(fields[index]) + 1); + + if (grow <= 0) { + return 0; + } + + if (fields[index] != mgr->last_alloc) { + return 1; + } + + if (mgr->space < grow) { + return 1; + } + + mgr->space -= grow; + mgr->used += grow; + + return 0; +} + void __ast_string_field_index_build_va(struct ast_string_field_mgr *mgr, - ast_string_field *fields, int num_fields, - int index, const char *format, va_list ap1, va_list ap2) + ast_string_field *fields, int num_fields, + int index, const char *format, va_list ap1, va_list ap2) { size_t needed; @@ -1285,6 +1310,7 @@ void __ast_string_field_index_build_va(struct ast_string_field_mgr *mgr, } fields[index] = mgr->pool->base + mgr->used; + mgr->last_alloc = fields[index]; mgr->used += needed; mgr->space -= needed; }