summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/asterisk/stringfields.h50
-rw-r--r--main/utils.c53
2 files changed, 75 insertions, 28 deletions
diff --git a/include/asterisk/stringfields.h b/include/asterisk/stringfields.h
index 65f1b53f9..b0cda6902 100644
--- a/include/asterisk/stringfields.h
+++ b/include/asterisk/stringfields.h
@@ -135,12 +135,30 @@ struct ast_string_field_pool {
pool, so the numbers here reflect just that.
*/
struct ast_string_field_mgr {
- size_t size; /*!< the total size of the current pool */
- size_t used; /*!< the space used in the current pool */
+ size_t size; /*!< the total size of the current pool */
+ size_t used; /*!< the space used in the current pool */
+ ast_string_field last_alloc; /*!< the last field allocated */
};
/*!
\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 ptr Pointer to a 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_ptr_grow(struct ast_string_field_mgr *mgr, size_t needed,
+ const ast_string_field *ptr);
+
+/*!
+ \internal
\brief Allocate space for a field
\param mgr Pointer to the pool manager structure
\param needed Amount of space needed for this field
@@ -152,7 +170,7 @@ struct ast_string_field_mgr {
an additional pool will be allocated.
*/
ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr,
- struct ast_string_field_pool **pool_head, size_t needed);
+ struct ast_string_field_pool **pool_head, size_t needed);
/*!
\internal
@@ -164,8 +182,8 @@ ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr
\return nothing
*/
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, ...);
+ struct ast_string_field_pool **pool_head,
+ const ast_string_field *ptr, const char *format, ...);
/*!
\internal
@@ -179,8 +197,8 @@ void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr,
\return nothing
*/
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);
+ struct ast_string_field_pool **pool_head,
+ const ast_string_field *ptr, const char *format, va_list a1, va_list a2);
/*!
\brief Declare a string field
@@ -233,17 +251,16 @@ int __ast_string_field_init(struct ast_string_field_mgr *mgr,
\param data String value to be copied into the field
\return nothing
*/
-
#define ast_string_field_ptr_set(x, ptr, data) do { \
const char *__d__ = (data); \
- size_t __dlen__ = (__d__) ? strlen(__d__) : 0; \
- const char **__p__ = (const char **)(ptr); \
- if (__dlen__ == 0) \
+ size_t __dlen__ = (__d__) ? strlen(__d__) + 1 : 1; \
+ const char **__p__ = (const char **) (ptr); \
+ if (__dlen__ == 1) \
*__p__ = __ast_string_field_empty; \
- else if (__dlen__ <= strlen(*__p__)) \
- strcpy((char *)*__p__, __d__); \
- else if ( (*__p__ = __ast_string_field_alloc_space(&(x)->__field_mgr, &(x)->__field_mgr_pool, __dlen__ + 1) ) ) \
- strcpy((char *)*__p__, __d__); \
+ else if (!__ast_string_field_ptr_grow(&(x)->__field_mgr, __dlen__, ptr)) \
+ memcpy((char *) *__p__, __d__, __dlen__); \
+ else if ((*__p__ = __ast_string_field_alloc_space(&(x)->__field_mgr, &(x)->__field_mgr_pool, __dlen__))) \
+ memcpy((char *) *__p__, __d__, __dlen__); \
} while (0)
/*!
@@ -253,11 +270,10 @@ int __ast_string_field_init(struct ast_string_field_mgr *mgr,
\param data String value to be copied into the field
\return nothing
*/
-#define ast_string_field_set(x, field, data) do { \
+#define ast_string_field_set(x, field, data) do { \
ast_string_field_ptr_set(x, &(x)->field, data); \
} while (0)
-
/*!
\brief Set a field to a complex (built) value
\param x Pointer to a structure containing fields
diff --git a/main/utils.c b/main/utils.c
index f156770ca..eff270fba 100644
--- a/main/utils.c
+++ b/main/utils.c
@@ -1425,7 +1425,8 @@ const char __ast_string_field_empty[] = ""; /*!< the empty string */
* fields in *mgr reflect the size of that only.
*/
static int add_string_pool(struct ast_string_field_mgr *mgr,
- struct ast_string_field_pool **pool_head, size_t size)
+ struct ast_string_field_pool **pool_head,
+ size_t size)
{
struct ast_string_field_pool *pool;
@@ -1436,6 +1437,7 @@ static int add_string_pool(struct ast_string_field_mgr *mgr,
*pool_head = pool;
mgr->size = size;
mgr->used = 0;
+ mgr->last_alloc = NULL;
return 0;
}
@@ -1451,14 +1453,16 @@ static int add_string_pool(struct ast_string_field_mgr *mgr,
* This must be done before destroying the object.
*/
int __ast_string_field_init(struct ast_string_field_mgr *mgr,
- struct ast_string_field_pool **pool_head, int size)
+ struct ast_string_field_pool **pool_head,
+ int size)
{
- const char **p = (const char **)pool_head + 1;
+ const char **p = (const char **) pool_head + 1;
struct ast_string_field_pool *cur = *pool_head;
/* clear fields - this is always necessary */
- while ((struct ast_string_field_mgr *)p != mgr)
+ while ((struct ast_string_field_mgr *) p != mgr)
*p++ = __ast_string_field_empty;
+ mgr->last_alloc = NULL;
if (size > 0) { /* allocate the initial pool */
*pool_head = NULL;
return add_string_pool(mgr, pool_head, size);
@@ -1474,16 +1478,19 @@ int __ast_string_field_init(struct ast_string_field_mgr *mgr,
(*pool_head)->prev = NULL;
mgr->used = 0;
}
+
while (cur) {
struct ast_string_field_pool *prev = cur->prev;
+
ast_free(cur);
cur = prev;
}
+
return 0;
}
ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr,
- struct ast_string_field_pool **pool_head, size_t needed)
+ struct ast_string_field_pool **pool_head, size_t needed)
{
char *result = NULL;
size_t space = mgr->size - mgr->used;
@@ -1500,17 +1507,41 @@ ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr
result = (*pool_head)->base + mgr->used;
mgr->used += needed;
+ mgr->last_alloc = result;
return result;
}
+int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr, size_t needed,
+ const ast_string_field *ptr)
+{
+ int grow = needed - (strlen(*ptr) + 1);
+ size_t space = mgr->size - mgr->used;
+
+ if (grow <= 0) {
+ return 0;
+ }
+
+ if (*ptr != mgr->last_alloc) {
+ return 1;
+ }
+
+ if (space < grow) {
+ return 1;
+ }
+
+ mgr->used += grow;
+
+ return 0;
+}
+
__attribute((format (printf, 4, 0)))
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)
+ struct ast_string_field_pool **pool_head,
+ const 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;
+ const char **p = (const char **) ptr;
size_t space = mgr->size - mgr->used;
/* try to write using available space */
@@ -1531,14 +1562,14 @@ void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
vsprintf(dst, format, ap2);
}
- *p = dst;
+ mgr->last_alloc = *p = dst;
mgr->used += needed;
}
__attribute((format (printf, 4, 5)))
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, ...)
+ struct ast_string_field_pool **pool_head,
+ const ast_string_field *ptr, const char *format, ...)
{
va_list ap1, ap2;