From 80fa9689b70e80fe7701832469e122d3261a2e87 Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Wed, 4 Jan 2006 21:54:09 +0000 Subject: add memory-pool based string field management for structures convert chan_sip sip_pvt and sip_registry structures to use string fields add 'const' qualifiers to a few API calls that don't modify their input strings add an asprintf() wrapper to astmm git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@7797 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- include/asterisk/stringfields.h | 288 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 include/asterisk/stringfields.h (limited to 'include/asterisk/stringfields.h') diff --git a/include/asterisk/stringfields.h b/include/asterisk/stringfields.h new file mode 100644 index 000000000..02811a611 --- /dev/null +++ b/include/asterisk/stringfields.h @@ -0,0 +1,288 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2006, Digium, Inc. + * + * Kevin P. Fleming + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + \brief String fields in structures + + This file contains objects and macros used to manage string + fields in structures without requiring them to be allocated + as fixed-size buffers or requiring individual allocations for + for each field. + + Using this functionality is quite simple... an example structure + with three fields is defined like this: + + \code + struct sample_fields { + int x1; + AST_DECLARE_STRING_FIELDS( + AST_STRING_FIELD(name); + AST_STRING_FIELD(address); + AST_STRING_FIELD(password); + ); + long x2; + }; + \endcode + + When an instance of this structure is allocated, the fields + (and the pool of storage for them) must be initialized: + + \code + struct sample_fields *sample; + + sample = calloc(1, sizeof(*sample)); + if (sample) { + if (!ast_string_field_init(sample)) { + free(sample); + sample = NULL; + } + } + + if (!sample) { + ... + } + \endcode + + Fields will default to pointing to an empty string, and will + revert to that when ast_string_field_free() is called. This means + that a string field will \b never contain NULL. + + Using the fields is much like using regular 'char *' fields + in the structure, except that writing into them must be done + using wrapper macros defined in this file. + + Storing simple values into fields can be done using ast_string_field_set(); + more complex values (using printf-style format strings) can be stored + using ast_string_field_build(). + + When the structure instance is no longer needed, the fields + and their storage pool must be freed: + + \code + ast_string_field_free_all(sample); + free(sample); + \endcode +*/ + +#ifndef _ASTERISK_STRINGFIELDS_H +#define _ASTERISK_STRINGFIELDS_H + +#include +#include +#include + +#include "asterisk/inline_api.h" +#include "asterisk/compiler.h" +#include "asterisk/compat.h" + +/*! + \internal + \brief An opaque type for managed string fields in structures + + Don't declare instances of this type directly; use the AST_STRING_FIELD() + macro instead. +*/ +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; + +/*! + \internal + \brief Structure used to manage the storage for a field pool +*/ +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 */ +}; + +/*! + \internal + \brief Initialize a field pool and fields + \param pool Pointer to the pool 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 +*/ +int __ast_string_field_init(struct ast_string_field_pool *pool, 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 + \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 + \return NULL on failure, an address for the field on success + + 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. +*/ +char *__ast_string_field_alloc_space(struct ast_string_field_pool *pool, size_t needed, + ast_string_field *fields, int num_fields); + +/*! + The default amount of storage to be allocated for a field pool. +*/ +#define AST_STRING_FIELD_DEFAULT_POOL 512 + +/*! + \brief Declare a string field + \param name The field name +*/ +#define AST_STRING_FIELD(name) const ast_string_field name; + +/*! + \brief Declare the fields needed in a structure + \param field_list The list of fields to declare, using AST_STRING_FIELD() for each one +*/ +#define AST_DECLARE_STRING_FIELDS(field_list) \ + ast_string_field __begin_field[0]; \ + field_list \ + ast_string_field __end_field[0]; \ + struct ast_string_field_pool __field_pool; + +/*! + \brief Get the number of string fields in a structure + \param x Pointer to a structure containing fields + \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) + +/*! + \brief Get the index of a field in a structure + \param x Pointer to a structure containing fields + \param field Name of the field to locate + \return the position (index) of the field within the structure's + array of fields +*/ +#define ast_string_field_index(x, field) \ + (offsetof(typeof(*x), field) - offsetof(typeof(*x), __begin_field)) / sizeof(ast_string_field) + +/*! + \brief Initialize a field pool and fields + \param x Pointer to a structure containing fields + \return 0 on failure, non-zero on success +*/ +#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)) + +/*! + \brief Set a field to a simple string value + \param x Pointer to a structure containing fields + \param index Index position of the field within the structure + \param data String value to be copied into the field + \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) + +/*! + \brief Set a field to a simple string value + \param x Pointer to a structure containing fields + \param field Name of the field to set + \param data String value to be copied into the field + \return nothing +*/ +#define ast_string_field_set(x, field, data) \ + ast_string_field_index_set(x, ast_string_field_index(x, field), data) + +/*! + \brief Set a field to a simple 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) + +/*! + \brief Set a field to a simple 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 + \param args Arguments for format string + \return nothing +*/ +#define ast_string_field_build(x, field, fmt, args...) \ + ast_string_field_index_build(x, ast_string_field_index(x, field), fmt, args) + +/*! + \brief Free a field's value. + \param x Pointer to a structure containing fields + \param index Index position of the field within the structure + \return nothing + + \note Because of the storage pool used, the memory + occupied by the field's value is \b not recovered; the field + 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; \ + } while(0) + +/*! + \brief Free a field's value. + \param x Pointer to a structure containing fields + \param field Name of the field to free + \return nothing + + \note Because of the storage pool used, the memory + occupied by the field's value is \b not recovered; the field + pointer is just changed to point to an empty string. +*/ +#define ast_string_field_free(x, field) \ + ast_string_field_index_free(x, ast_string_field_index(x, field)) + +/*! + \brief Free all fields (and the storage pool) in a structure + \param x Pointer to a structure containing fields + \return nothing + + After calling this macro, fields can no longer be accessed in + structure; it should only be called immediately before freeing + the structure itself. +*/ +#define ast_string_field_free_all(x) do { \ + int index; \ + for (index = 0; index < ast_string_field_count(x); index ++) \ + ast_string_field_index_free(x, index); \ + free(x->__field_pool.base); \ + } while(0) + +#endif /* _ASTERISK_STRINGFIELDS_H */ -- cgit v1.2.3