This commit folds in changes to both stringfields (some enhancements to the ...field_...
[asterisk/asterisk.git] / include / asterisk / stringfields.h
index 02811a6..9b5fbc6 100644 (file)
@@ -47,7 +47,7 @@
   
   sample = calloc(1, sizeof(*sample));
   if (sample) {
-         if (!ast_string_field_init(sample)) {
+         if (ast_string_field_init(sample, 256)) {
                  free(sample);
                  sample = NULL;
          }
@@ -103,35 +103,44 @@ typedef const char * ast_string_field;
   \internal
   \brief A constant empty string used for fields that have no other value
 */
-extern const char *__ast_string_field_empty;
+extern const char __ast_string_field_empty[];
 
 /*!
   \internal
-  \brief Structure used to manage the storage for a field pool
+  \brief Structure used to hold a pool of space for string fields
 */
 struct ast_string_field_pool {
-       char *base;     /*!< the address of the pool's base in memory */
-       size_t size;    /*!< the total size of the pool */
-       size_t space;   /*!< the space available in the pool */
-       size_t used;    /*!< the space used in the pool */
+       struct ast_string_field_pool *prev;     /*!< pointer to the previous pool, if any */
+       char base[0];                           /*!< storage space for the fields */
 };
 
 /*!
   \internal
-  \brief Initialize a field pool and fields
-  \param pool Pointer to the pool structure
+  \brief Structure used to manage the storage for a set of string fields
+*/
+struct ast_string_field_mgr {
+       struct ast_string_field_pool *pool;     /*!< the address of the pool's structure */
+       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 */
+};
+
+/*!
+  \internal
+  \brief Initialize a field pool manager and fields
+  \param mgr Pointer to the pool manager structure
   \param size Amount of storage to allocate
   \param fields Pointer to the first entry of the field array
   \param num_fields Number of fields in the array
-  \return 0 on failure, non-zero on success
+  \return 0 on success, non-zero on failure
 */
-int __ast_string_field_init(struct ast_string_field_pool *pool, size_t size,
+int __ast_string_field_init(struct ast_string_field_mgr *mgr, size_t size,
                            ast_string_field *fields, int num_fields);
 
 /*!
   \internal
-  \brief Allocate space for field in the pool
-  \param pool Pointer to the pool structure
+  \brief Allocate space for a field
+  \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 num_fields Number of fields in the array
@@ -139,23 +148,30 @@ int __ast_string_field_init(struct ast_string_field_pool *pool, size_t size,
 
   This function will allocate the requested amount of space from
   the field pool. If the requested amount of space is not available,
-  the pool will be expanded until enough space becomes available,
-  and the existing fields stored there will be updated to point
-  into the new pool.
+  an additional pool will be allocated.
 */
-char *__ast_string_field_alloc_space(struct ast_string_field_pool *pool, size_t needed,
-                                    ast_string_field *fields, int num_fields);
+ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr, size_t needed,
+                                               ast_string_field *fields, int num_fields);
 
 /*!
-  The default amount of storage to be allocated for a field pool.
+  \internal
+  \brief Set a field to a complex (built) value
+  \param mgr Pointer to the pool manager structure
+  \param fields Pointer to the first entry of the field array
+  \param num_fields Number of fields in the array
+  \param index Index position of the field within the structure
+  \param format printf-style format string
+  \return nothing
 */
-#define AST_STRING_FIELD_DEFAULT_POOL 512
+void __ast_string_field_index_build(struct ast_string_field_mgr *mgr,
+                                   ast_string_field *fields, int num_fields,
+                                   int index, const char *format, ...);
 
 /*!
   \brief Declare a string field
   \param name The field name
 */
-#define AST_STRING_FIELD(name) const ast_string_field name;
+#define AST_STRING_FIELD(name) const ast_string_field name
 
 /*!
   \brief Declare the fields needed in a structure
@@ -165,7 +181,7 @@ char *__ast_string_field_alloc_space(struct ast_string_field_pool *pool, size_t
        ast_string_field __begin_field[0]; \
        field_list \
        ast_string_field __end_field[0]; \
-       struct ast_string_field_pool __field_pool;
+       struct ast_string_field_mgr __field_mgr
 
 /*!
   \brief Get the number of string fields in a structure
@@ -173,7 +189,7 @@ char *__ast_string_field_alloc_space(struct ast_string_field_pool *pool, size_t
   \return the number of fields in the structure's definition
 */
 #define ast_string_field_count(x) \
-       (offsetof(typeof(*x), __end_field) - offsetof(typeof(*x), __begin_field)) / sizeof(ast_string_field)
+       (offsetof(typeof(*(x)), __end_field) - offsetof(typeof(*(x)), __begin_field)) / sizeof(ast_string_field)
 
 /*!
   \brief Get the index of a field in a structure
@@ -188,10 +204,11 @@ char *__ast_string_field_alloc_space(struct ast_string_field_pool *pool, size_t
 /*!
   \brief Initialize a field pool and fields
   \param x Pointer to a structure containing fields
-  \return 0 on failure, non-zero on success
+  \param size Amount of storage to allocate
+  \return 0 on success, non-zero on failure
 */
-#define ast_string_field_init(x) \
-       __ast_string_field_init(&x->__field_pool, AST_STRING_FIELD_DEFAULT_POOL, &x->__begin_field[0], ast_string_field_count(x))
+#define ast_string_field_init(x, size) \
+       __ast_string_field_init(&(x)->__field_mgr, size, &(x)->__begin_field[0], ast_string_field_count(x))
 
 /*!
   \brief Set a field to a simple string value
@@ -201,10 +218,36 @@ char *__ast_string_field_alloc_space(struct ast_string_field_pool *pool, size_t
   \return nothing
 */
 #define ast_string_field_index_set(x, index, data) do { \
-       if ((x->__begin_field[index] = __ast_string_field_alloc_space(&x->__field_pool, strlen(data) + 1, &x->__begin_field[0], ast_string_field_count(x)))) \
-               strcpy((char *) x->__begin_field[index], data); \
-       } while (0)
+    char *__zz__ = (char*)(x)->__begin_field[index]; \
+    int __dlen__ = strlen(data); \
+    if( __dlen__ == 0 ) { (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); \
+        } \
+       } \
+   } while (0)
 
+#ifdef FOR_TEST
+#define ast_string_field_index_logset(x, index, data, logstr) do { \
+    char *__zz__ = (char*)(x)->__begin_field[index]; \
+    int __dlen__ = strlen(data); \
+    if( __dlen__ == 0 ) { (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); \
+        } \
+       } \
+   } while (0)
+#endif
 /*!
   \brief Set a field to a simple string value
   \param x Pointer to a structure containing fields
@@ -215,24 +258,23 @@ char *__ast_string_field_alloc_space(struct ast_string_field_pool *pool, size_t
 #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 simple complex (built) value
+  \brief Set a field to a complex (built) value
   \param x Pointer to a structure containing fields
   \param index Index position of the field within the structure
   \param fmt printf-style format string
   \param args Arguments for format string
   \return nothing
 */
-#define ast_string_field_index_build(x, index, fmt, args...) do { \
-       char s; \
-       size_t needed; \
-       needed = snprintf(&s, 1, fmt, args) + 1; \
-       if ((x->__begin_field[index] = __ast_string_field_alloc_space(&x->__field_pool, needed, &x->__begin_field[0], ast_string_field_count(x)))) \
-               sprintf((char *) x->__begin_field[index], fmt, args); \
-       } while (0)
+#define ast_string_field_index_build(x, index, fmt, args...) \
+       __ast_string_field_index_build(&(x)->__field_mgr, &(x)->__begin_field[0], ast_string_field_count(x), index, fmt, args)
 
 /*!
-  \brief Set a field to a simple complex (built) value
+  \brief Set a field to a complex (built) value
   \param x Pointer to a structure containing fields
   \param field Name of the field to set
   \param fmt printf-style format string
@@ -253,7 +295,7 @@ char *__ast_string_field_alloc_space(struct ast_string_field_pool *pool, size_t
   pointer is just changed to point to an empty string.
 */
 #define ast_string_field_index_free(x, index) do { \
-       x->__begin_field[index] = __ast_string_field_empty; \
+       (x)->__begin_field[index] = __ast_string_field_empty; \
        } while(0)
 
 /*!
@@ -280,9 +322,13 @@ char *__ast_string_field_alloc_space(struct ast_string_field_pool *pool, size_t
 */
 #define ast_string_field_free_all(x) do { \
        int index; \
+       struct ast_string_field_pool *this, *prev; \
        for (index = 0; index < ast_string_field_count(x); index ++) \
                ast_string_field_index_free(x, index); \
-       free(x->__field_pool.base); \
+       for (this = (x)->__field_mgr.pool; this; this = prev) { \
+               prev = this->prev; \
+               free(this); \
+       } \
        } while(0)
 
 #endif /* _ASTERISK_STRINGFIELDS_H */