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
This commit is contained in:
Kevin P. Fleming
2006-01-04 21:54:09 +00:00
parent 223c0c303a
commit 80fa9689b7
8 changed files with 717 additions and 304 deletions

View File

@@ -1,7 +1,7 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Copyright (C) 1999 - 2006, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
*
@@ -38,6 +38,7 @@
#undef realloc
#undef strdup
#undef strndup
#undef asprintf
#undef vasprintf
void *__ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func);
@@ -46,6 +47,7 @@ void __ast_free(void *ptr, const char *file, int lineno, const char *func);
void *__ast_realloc(void *ptr, size_t size, const char *file, int lineno, const char *func);
char *__ast_strdup(const char *s, const char *file, int lineno, const char *func);
char *__ast_strndup(const char *s, size_t n, const char *file, int lineno, const char *func);
int __ast_asprintf(const char *file, int lineno, const char *func, char **strp, const char *format, ...);
int __ast_vasprintf(char **strp, const char *format, va_list ap, const char *file, int lineno, const char *func);
void __ast_mm_init(void);
@@ -70,6 +72,9 @@ void __ast_mm_init(void);
#define strndup(a,b) \
__ast_strndup(a,b,__FILE__, __LINE__, __PRETTY_FUNCTION__)
#define asprintf(a, b, c...) \
__ast_asprintf(__FILE__, __LINE__, __PRETTY_FUNCTION__, a, b, c)
#define vasprintf(a,b,c) \
__ast_vasprintf(a,b,c,__FILE__, __LINE__, __PRETTY_FUNCTION__)

View File

@@ -287,7 +287,7 @@ int ast_unregister_application(const char *app);
* \param exten which extension to get state
* Returns extension state !! = AST_EXTENSION_???
*/
int ast_extension_state(struct ast_channel *c, char *context, char *exten);
int ast_extension_state(struct ast_channel *c, const char *context, const char *exten);
/*! Return string of the state of an extension */
/*!

View File

@@ -0,0 +1,288 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2006, Digium, Inc.
*
* Kevin P. Fleming <kpfleming@digium.com>
*
* 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 <string.h>
#include <stdarg.h>
#include <stddef.h>
#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 */

View File

@@ -1,7 +1,7 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Copyright (C) 1999 - 2006, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
*
@@ -162,7 +162,7 @@ int ast_base64decode(unsigned char *dst, const char *src, int max);
\param doreserved Convert reserved characters
*/
char *ast_uri_encode(char *string, char *outbuf, int buflen, int doreserved);
char *ast_uri_encode(const char *string, char *outbuf, int buflen, int doreserved);
/*! \brief Decode URI, URN, URL (overwrite string)
\param s String to be decoded