[asterisk-commits] rizzo: trunk r88454 - in /trunk: apps/ channels/ include/asterisk/ main/ res/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Sun Nov 4 13:44:32 CST 2007


Author: rizzo
Date: Sun Nov  4 13:44:31 2007
New Revision: 88454

URL: http://svn.digium.com/view/asterisk?view=rev&rev=88454
Log:
Simplify the implementation and the API for stringfields;
details and examples are in include/asterisk/stringfields.h.

Not applicable to older branches except for 1.4 which will
receive a fix for the routines that free memory pools.


Modified:
    trunk/apps/app_meetme.c
    trunk/channels/chan_iax2.c
    trunk/channels/chan_sip.c
    trunk/include/asterisk/stringfields.h
    trunk/main/channel.c
    trunk/main/pbx.c
    trunk/main/utils.c
    trunk/res/res_features.c

Modified: trunk/apps/app_meetme.c
URL: http://svn.digium.com/view/asterisk/trunk/apps/app_meetme.c?view=diff&rev=88454&r1=88453&r2=88454
==============================================================================
--- trunk/apps/app_meetme.c (original)
+++ trunk/apps/app_meetme.c Sun Nov  4 13:44:31 2007
@@ -4872,7 +4872,7 @@
 	while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
 		ast_free(station_ref);
 
-	ast_string_field_free_all(trunk);
+	ast_string_field_free_memory(trunk);
 	ast_free(trunk);
 }
 
@@ -4898,7 +4898,7 @@
 	while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
 		ast_free(trunk_ref);
 
-	ast_string_field_free_all(station);
+	ast_string_field_free_memory(station);
 	ast_free(station);
 }
 

Modified: trunk/channels/chan_iax2.c
URL: http://svn.digium.com/view/asterisk/trunk/channels/chan_iax2.c?view=diff&rev=88454&r1=88453&r2=88454
==============================================================================
--- trunk/channels/chan_iax2.c (original)
+++ trunk/channels/chan_iax2.c Sun Nov  4 13:44:31 2007
@@ -2152,7 +2152,7 @@
 				iax2_frame_free(frame.data);
 			jb_destroy(pvt->jb);
 			/* gotta free up the stringfields */
-			ast_string_field_free_pools(pvt);
+			ast_string_field_free_memory(pvt);
 			ast_free(pvt);
 		}
 	}
@@ -9735,7 +9735,7 @@
 	if (peer->mwi_event_sub)
 		ast_event_unsubscribe(peer->mwi_event_sub);
 
-	ast_string_field_free_pools(peer);
+	ast_string_field_free_memory(peer);
 }
 
 /*! \brief Create peer structure based on configuration */
@@ -9987,7 +9987,7 @@
 		ast_variables_destroy(user->vars);
 		user->vars = NULL;
 	}
-	ast_string_field_free_pools(user);
+	ast_string_field_free_memory(user);
 }
 
 /*! \brief Create in-memory user structure from configuration */
@@ -10028,7 +10028,7 @@
 	
 	if (user) {
 		if (firstpass) {
-			ast_string_field_free_pools(user);
+			ast_string_field_free_memory(user);
 			memset(user, 0, sizeof(struct iax2_user));
 			if (ast_string_field_init(user, 32)) {
 				user = user_unref(user);

Modified: trunk/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/trunk/channels/chan_sip.c?view=diff&rev=88454&r1=88453&r2=88454
==============================================================================
--- trunk/channels/chan_sip.c (original)
+++ trunk/channels/chan_sip.c Sun Nov  4 13:44:31 2007
@@ -3602,7 +3602,7 @@
 		ast_sched_del(sched, reg->expire);
 	if (reg->timeout > -1)
 		ast_sched_del(sched, reg->timeout);
-	ast_string_field_free_pools(reg);
+	ast_string_field_free_memory(reg);
 	regobjs--;
 	ast_free(reg);
 	
@@ -3709,7 +3709,7 @@
 	}
 	ast_mutex_destroy(&p->pvt_lock);
 
-	ast_string_field_free_pools(p);
+	ast_string_field_free_memory(p);
 
 	ast_free(p);
 }
@@ -6455,7 +6455,7 @@
 
 	if (!ast_strlen_zero(p->url)) {
 		add_header(resp, "Access-URL", p->url);
-		ast_string_field_free(p, url);
+		ast_string_field_set(p, url, NULL);
 	}
 
 	return 0;
@@ -6565,7 +6565,7 @@
 
 	if (!ast_strlen_zero(p->url)) {
 		add_header(req, "Access-URL", p->url);
-		ast_string_field_free(p, url);
+		ast_string_field_set(p, url, NULL);
 	}
 
 	return 0;
@@ -6607,7 +6607,7 @@
 {
 	struct sip_pvt *p = data;
 
-	ast_string_field_free_pools(p);
+	ast_string_field_free_memory(p);
 
 	ast_free(data);
 }
@@ -6657,7 +6657,7 @@
 	__transmit_response(p, msg, req, XMIT_UNRELIABLE);
 
 	/* Free the string fields, but not the pool space */
-	ast_string_field_free_all(p);
+	ast_string_field_init(p, 0);
 
 	return 0;
 }
@@ -8178,7 +8178,7 @@
 		} else {
 			p = r->call;
 			make_our_tag(p->tag, sizeof(p->tag));	/* create a new local tag for every register attempt */
-			ast_string_field_free(p, theirtag);	/* forget their old tag, so we don't match tags when getting response */
+			ast_string_field_set(p, theirtag, NULL);	/* forget their old tag, so we don't match tags when getting response */
 		}
 	} else {
 		/* Build callid for registration if we haven't registered before */
@@ -10238,8 +10238,8 @@
 		p->timer_t1 = peer->lastms < global_t1min ? global_t1min : peer->lastms;
 	if (ast_test_flag(&peer->flags[0], SIP_INSECURE_INVITE)) {
 		/* Pretend there is no required authentication */
-		ast_string_field_free(p, peersecret);
-		ast_string_field_free(p, peermd5secret);
+		ast_string_field_set(p, peersecret, NULL);
+		ast_string_field_set(p, peermd5secret, NULL);
 	}
 	if (!(res = check_auth(p, req, peer->name, p->peersecret, p->peermd5secret, sipmethod, uri2, reliable, req->ignore))) {
 		ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
@@ -12633,13 +12633,13 @@
 	/* table of recognised keywords, and places where they should be copied */
 	const struct x {
 		const char *key;
-		int field_index;
+		const ast_string_field *field;
 	} *i, keys[] = {
-		{ "realm=", ast_string_field_index(p, realm) },
-		{ "nonce=", ast_string_field_index(p, nonce) },
-		{ "opaque=", ast_string_field_index(p, opaque) },
-		{ "qop=", ast_string_field_index(p, qop) },
-		{ "domain=", ast_string_field_index(p, domain) },
+		{ "realm=", &p->realm },
+		{ "nonce=", &p->nonce },
+		{ "opaque=", &p->opaque },
+		{ "qop=", &p->qop },
+		{ "domain=", &p->domain },
 		{ NULL, 0 },
 	};
 
@@ -12667,7 +12667,7 @@
 				separator = ",";
 			}
 			strsep(&c, separator); /* clear separator and move ptr */
-			ast_string_field_index_set(p, i->field_index, src);
+			ast_string_field_ptr_set(p, i->field, src);
 			break;
 		}
 		if (i->key == NULL) /* not found, try ',' */
@@ -13285,7 +13285,7 @@
 			p->options->auth_type = resp;
 
 		/* Then we AUTH */
-		ast_string_field_free(p, theirtag);	/* forget their old tag, so we don't match tags when getting response */
+		ast_string_field_set(p, theirtag, NULL);	/* forget their old tag, so we don't match tags when getting response */
 		if (!req->ignore) {
 			if (p->authtries < MAX_AUTHTRIES)
 				p->invitestate = INV_CALLING;
@@ -14853,7 +14853,7 @@
 			}
 			p->invitestate = INV_COMPLETED;	
 			sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
-			ast_string_field_free(p, theirtag);
+			ast_string_field_set(p, theirtag, NULL);
 			return 0;
 		}
 
@@ -16974,7 +16974,7 @@
 	   SIP/peername will still use the full contact */
 	if (ext) {
 		ast_string_field_set(p, username, ext);
-		ast_string_field_free(p, fullcontact);
+		ast_string_field_set(p, fullcontact, NULL);
 	}
 #if 0
 	printf("Setting up to call extension '%s' at '%s'\n", ext ? ext : "<none>", host);

Modified: trunk/include/asterisk/stringfields.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/stringfields.h?view=diff&rev=88454&r1=88453&r2=88454
==============================================================================
--- trunk/include/asterisk/stringfields.h (original)
+++ trunk/include/asterisk/stringfields.h Sun Nov  4 13:44:31 2007
@@ -23,60 +23,80 @@
   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
+
+  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);
+		  AST_STRING_FIELD(foo);
+		  AST_STRING_FIELD(bar);
+		  AST_STRING_FIELD(blah);
 	  );
 	  long x2;
   };
   \endcode
   
-  When an instance of this structure is allocated, the fields
-  (and the pool of storage for them) must be initialized:
+  When an instance of this structure is allocated (either statically or
+  dynamically), 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, 256)) {
-		  free(sample);
-		  sample = NULL;
-	  }
-  }
-  
-  if (!sample) {
-  ...
+  struct sample_fields *x;
+  
+  x = ast_calloc(1, sizeof(*x));
+  if (x == NULL || ast_string_field_init(x, 252)) {
+	if (x)
+		ast_free(x);
+	x = NULL;
+  	... handle error
   }
   \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().
-  
+
+  Fields will default to pointing to an empty string, and will revert to
+  that when ast_string_field_set() is called with a NULL argument.
+  A string field will \b never contain NULL (this feature is not used
+  in this code, but comes from external requirements).
+
+  ast_string_field_init(x, 0) will reset fields to the
+  initial value while keeping the pool allocated.
+  
+  Reading the fields is much like using 'const char * const' fields in the
+  structure: you cannot write to the field or to the memory it points to
+  (XXX perhaps the latter is too much of a restriction since values
+  are not shared).
+
+  Writing to the fields must be done using the wrapper macros listed below;
+  and assignments are always by value (i.e. strings are copied):
+  * ast_string_field_set() stores a simple value;
+  * ast_string_field_build() builds the string using a printf-style;
+  * ast_string_field_build_va() is the varargs version of the above (for
+    portability reasons it uses two vararg);
+  * variants of these function allow passing a pointer to the field
+    as an argument.
+  \code
+  ast_string_field_set(x, foo, "infinite loop");
+  ast_string_field_set(x, foo, NULL); // set to an empty string
+  ast_string_field_ptr_set(x, &x->bar, "right way");
+
+  ast_string_field_build(x, blah, "%d %s", zipcode, city);
+  ast_string_field_ptr_build(x, &x->blah, "%d %s", zipcode, city);
+
+  ast_string_field_build_va(x, bar, fmt, args1, args2)
+  ast_string_field_ptr_build_va(x, &x->bar, fmt, args1, args2)
+  \endcode
+
   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);
+  ast_string_field_free_memory(x);
+  ast_free(x);
   \endcode
+
+  This completes the API description.
 */
 
 #ifndef _ASTERISK_STRINGFIELDS_H
@@ -116,26 +136,14 @@
 
 /*!
   \internal
-  \brief Structure used to manage the storage for a set of string fields
+  \brief Structure used to manage the storage for a set of string fields.
+  Because of the way pools are managed, we can only allocate from the topmost
+  pool, so the numbers here reflect just that.
 */
 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 */
+	size_t size;		/*!< the total size of 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 success, non-zero on failure
-*/
-int __ast_string_field_init(struct ast_string_field_mgr *mgr, size_t size,
-			    ast_string_field *fields, int num_fields);
 
 /*!
   \internal
@@ -143,45 +151,42 @@
   \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
   \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,
   an additional pool will be allocated.
 */
-ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr, size_t needed,
-						ast_string_field *fields, int num_fields);
+ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr,
+	 struct ast_string_field_pool **pool_head, size_t needed);
 
 /*!
   \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 ptr Pointer to a field within the structure
   \param format printf-style format string
   \return nothing
 */
-void __ast_string_field_index_build(struct ast_string_field_mgr *mgr,
-				    ast_string_field *fields, int num_fields,
-				    int index, const char *format, ...);
+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, ...);
 
 /*!
   \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 ptr Pointer to a field within the structure
   \param format printf-style format string
   \param args va_list of the args for the format_string
   \param args_again a copy of the first va_list for the sake of bsd not having a copy routine
   \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);
+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);
 
 /*!
   \brief Declare a string field
@@ -191,79 +196,61 @@
 
 /*!
   \brief Declare the fields needed in a structure
-  \param field_list The list of fields to declare, using AST_STRING_FIELD() for each one
+  \param field_list The list of fields to declare, using AST_STRING_FIELD() for each one.
+  Internally, string fields are stored as a pointer to the head of the pool,
+  followed by individual string fields, and then a struct ast_string_field_mgr
+  which describes the space allocated.
+  We split the two variables so they can be used as markers around the
+  field_list, and this allows us to determine how many entries are in
+  the field, and play with them.
+  In particular, for writing to the fields, we rely on __field_mgr_pool to be
+  a non-const pointer, so we know it has the same size as ast_string_field,
+  and we can use it to locate the fields.
 */
 #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_mgr_pool;	\
+	field_list					\
 	struct ast_string_field_mgr __field_mgr
 
 /*!
-  \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
-  \param size Amount of storage to allocate
+  \param size Amount of storage to allocate.
+	Use 0 to reset fields to the default value,
+	and release all but the most recent pool.
+	size<0 (used internally) means free all pools.
   \return 0 on success, non-zero on failure
 */
 #define ast_string_field_init(x, size) \
-	__ast_string_field_init(&(x)->__field_mgr, size, &(x)->__begin_field[0], ast_string_field_count(x))
+	__ast_string_field_init(&(x)->__field_mgr, &(x)->__field_mgr_pool, size)
+
+/*! \brief free all memory - to be called before destroying the object */
+#define ast_string_field_free_memory(x)	\
+	__ast_string_field_init(&(x)->__field_mgr, &(x)->__field_mgr_pool, -1)
+
+/*! \internal \brief internal version of ast_string_field_init */
+int __ast_string_field_init(struct ast_string_field_mgr *mgr,
+	struct ast_string_field_pool **pool_head, size_t needed);
 
 /*!
   \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 ptr Pointer to a 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 { \
-    char *__zz__ = (char*)(x)->__begin_field[index]; \
-    size_t __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]; \
-    size_t __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
+
+#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)					\
+		*__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__);			\
+	} while (0)
 
 /*!
   \brief Set a field to a simple string value
@@ -272,47 +259,44 @@
   \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)
-
-#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
-  \param x Pointer to a structure containing fields
-  \param index Index position of the field within the structure
+#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
+  \param ptr Pointer to a 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...) \
-	__ast_string_field_index_build(&(x)->__field_mgr, &(x)->__begin_field[0], ast_string_field_count(x), index, fmt, args)
+#define ast_string_field_ptr_build(x, ptr, fmt, args...) \
+	__ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, ptr, fmt, args)
+
+/*!
+  \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
+  \param args Arguments for format string
+  \return nothing
+*/
+#define ast_string_field_build(x, field, fmt, args...) \
+	__ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, &(x)->field, fmt, args)
 
 /*!
   \brief Set a field to a complex (built) value with prebuilt va_lists.
   \param x Pointer to a structure containing fields
-  \param index Index position of the field within the structure
+  \param ptr Pointer to a field within the structure
   \param fmt printf-style format string
   \param args1 Arguments for format string in va_list format
   \param args2 a second copy of the va_list for the sake of bsd, with no va_list copy operation
   \return nothing
 */
-#define ast_string_field_index_build_va(x, index, fmt, args1, args2) \
-	__ast_string_field_index_build_va(&(x)->__field_mgr, &(x)->__begin_field[0], ast_string_field_count(x), index, fmt, args1, args2)
-
-/*!
-  \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
-  \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)
+#define ast_string_field_ptr_build_va(x, ptr, fmt, args1, args2) \
+	__ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, ptr, fmt, args1, args2)
 
 /*!
   \brief Set a field to a complex (built) value
@@ -324,67 +308,6 @@
   \return nothing
 */
 #define ast_string_field_build_va(x, field, fmt, args1, args2) \
-	ast_string_field_index_build_va(x, ast_string_field_index(x, field), fmt, args1, args2)
-
-/*!
-  \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 the stringfield storage pools attached to 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_pools(x) do { \
-	struct ast_string_field_pool *this, *prev; \
-	for (this = (x)->__field_mgr.pool; this; this = prev) { \
-		prev = this->prev; \
-		free(this); \
-	} \
-	} while(0)
-
-/*!
-  \brief Free the stringfields in a structure
-  \param x Pointer to a structure containing fields
-  \return nothing.
-
-  After calling this macro, the most recently allocated pool
-  attached to the structure will be available for use by
-  stringfields again.
-*/
-#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); \
-	(x)->__field_mgr.used = 0; \
-	(x)->__field_mgr.space = (x)->__field_mgr.size; \
-	} while(0)
+	__ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, &(x)->field, fmt, args1, args2)
 
 #endif /* _ASTERISK_STRINGFIELDS_H */

Modified: trunk/main/channel.c
URL: http://svn.digium.com/view/asterisk/trunk/main/channel.c?view=diff&rev=88454&r1=88453&r2=88454
==============================================================================
--- trunk/main/channel.c (original)
+++ trunk/main/channel.c Sun Nov  4 13:44:31 2007
@@ -678,7 +678,7 @@
 	if (needqueue) {
 		if (pipe(tmp->alertpipe)) {
 			ast_log(LOG_WARNING, "Channel allocation failed: Can't create alert pipe!\n");
-			ast_string_field_free_pools(tmp);
+			ast_string_field_free_memory(tmp);
 			ast_free(tmp);
 			return NULL;
 		} else {
@@ -1171,7 +1171,7 @@
 	/* Destroy the jitterbuffer */
 	ast_jb_destroy(chan);
 
-	ast_string_field_free_pools(chan);
+	ast_string_field_free_memory(chan);
 	ast_free(chan);
 	AST_RWLIST_UNLOCK(&channels);
 

Modified: trunk/main/pbx.c
URL: http://svn.digium.com/view/asterisk/trunk/main/pbx.c?view=diff&rev=88454&r1=88453&r2=88454
==============================================================================
--- trunk/main/pbx.c (original)
+++ trunk/main/pbx.c Sun Nov  4 13:44:31 2007
@@ -1289,7 +1289,7 @@
 static void exception_store_free(void *data)
 {
 	struct pbx_exception *exception = data;
-	ast_string_field_free_pools(exception);
+	ast_string_field_free_memory(exception);
 	ast_free(exception);
 }
 

Modified: trunk/main/utils.c
URL: http://svn.digium.com/view/asterisk/trunk/main/utils.c?view=diff&rev=88454&r1=88453&r2=88454
==============================================================================
--- trunk/main/utils.c (original)
+++ trunk/main/utils.c Sun Nov  4 13:44:31 2007
@@ -1207,100 +1207,141 @@
 	s[ofs] = '\0';
 }
 
-const char __ast_string_field_empty[] = "";
-
-static int add_string_pool(struct ast_string_field_mgr *mgr, size_t size)
+/*
+ * stringfields support routines.
+ */
+
+const char __ast_string_field_empty[] = ""; /*!< the empty string */
+
+/*! \brief add a new block to the pool.
+ * We can only allocate from the topmost pool, so the
+ * 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;
 
 	if (!(pool = ast_calloc(1, sizeof(*pool) + size)))
 		return -1;
 	
-	pool->prev = mgr->pool;
-	mgr->pool = pool;
+	pool->prev = *pool_head;
+	*pool_head = pool;
 	mgr->size = size;
-	mgr->space = size;
 	mgr->used = 0;
 
 	return 0;
 }
 
-int __ast_string_field_init(struct ast_string_field_mgr *mgr, size_t size,
-			    ast_string_field *fields, int num_fields)
-{
-	int index;
-
-	if (add_string_pool(mgr, size))
-		return -1;
-
-	for (index = 0; index < num_fields; index++)
-		fields[index] = __ast_string_field_empty;
-
+/*
+ * This is an internal API, code should not use it directly.
+ * It initializes all fields as empty, then uses 'size' for 3 functions:
+ * size > 0 means initialize the pool list with a pool of given size.
+ *	This must be called right after allocating the object.
+ * size = 0 means release all pools except the most recent one.
+ *	This is useful to e.g. reset an object to the initial value.
+ * size < 0 means release all pools.
+ *	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, size_t size)
+{
+	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)
+		*p++ = __ast_string_field_empty;
+	if (size > 0) {			/* allocate the initial pool */
+		*pool_head = NULL;
+		return add_string_pool(mgr, pool_head, size);
+	}
+	if (size < 0) {			/* reset all pools */
+		*pool_head = NULL;
+	} else {			/* preserve the first pool */
+		if (cur == NULL) {
+			ast_log(LOG_WARNING, "trying to reset empty pool\n");
+			return -1;
+		}
+		cur = cur->prev;
+		(*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, size_t needed,
-						ast_string_field *fields, int num_fields)
+ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr,
+	struct ast_string_field_pool **pool_head, size_t needed)
 {
 	char *result = NULL;
-
-	if (__builtin_expect(needed > mgr->space, 0)) {
+	size_t space = mgr->size - mgr->used;
+
+	if (__builtin_expect(needed > space, 0)) {
 		size_t new_size = mgr->size * 2;
 
 		while (new_size < needed)
 			new_size *= 2;
 
-		if (add_string_pool(mgr, new_size))
+		if (add_string_pool(mgr, pool_head, new_size))
 			return NULL;
 	}
 
-	result = mgr->pool->base + mgr->used;
+	result = (*pool_head)->base + mgr->used;
 	mgr->used += needed;
-	mgr->space -= needed;
 	return result;
 }
 
-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)
+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)
 {
 	size_t needed;
-
-	needed = vsnprintf(mgr->pool->base + mgr->used, mgr->space, format, ap1) + 1;
+	char *dst = (*pool_head)->base + mgr->used;
+	const char **p = (const char **)ptr;
+	size_t space = mgr->size - mgr->used;
+
+	/* try to write using available space */
+	needed = vsnprintf(dst, space, format, ap1) + 1;
 
 	va_end(ap1);
 
-	if (needed > mgr->space) {
+	if (needed > space) {	/* if it fails, reallocate */
 		size_t new_size = mgr->size * 2;
 
 		while (new_size < needed)
 			new_size *= 2;
 
-		if (add_string_pool(mgr, new_size))
+		if (add_string_pool(mgr, pool_head, new_size))
 			return;
 
-		vsprintf(mgr->pool->base + mgr->used, format, ap2);
-	}
-
-	fields[index] = mgr->pool->base + mgr->used;
+		dst = (*pool_head)->base + mgr->used;
+		vsprintf(dst, format, ap2);
+	}
+
+	*p = dst;
 	mgr->used += needed;
-	mgr->space -= needed;
-}
-
-void __ast_string_field_index_build(struct ast_string_field_mgr *mgr,
-				    ast_string_field *fields, int num_fields,
-				    int index, const char *format, ...)
+}
+
+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, ...)
 {
 	va_list ap1, ap2;
 
 	va_start(ap1, format);
 	va_start(ap2, format);		/* va_copy does not exist on FreeBSD */
 
-	__ast_string_field_index_build_va(mgr, fields, num_fields, index, format, ap1, ap2);
+	__ast_string_field_ptr_build_va(mgr, pool_head, ptr, format, ap1, ap2);
 
 	va_end(ap1);
 	va_end(ap2);
 }
+/* end of stringfields support */
 
 AST_MUTEX_DEFINE_STATIC(fetchadd_m); /* used for all fetc&add ops */
 

Modified: trunk/res/res_features.c
URL: http://svn.digium.com/view/asterisk/trunk/res/res_features.c?view=diff&rev=88454&r1=88453&r2=88454
==============================================================================
--- trunk/res/res_features.c (original)
+++ trunk/res/res_features.c Sun Nov  4 13:44:31 2007
@@ -1272,11 +1272,11 @@
 	AST_RWLIST_WRLOCK(&feature_groups);
 	while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
 		while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) {
-			ast_string_field_free_all(fge);
+			ast_string_field_free_memory(fge);
 			ast_free(fge);
 		}
 
-		ast_string_field_free_all(fg);
+		ast_string_field_free_memory(fg);
 		ast_free(fg);
 	}
 	AST_RWLIST_UNLOCK(&feature_groups);




More information about the asterisk-commits mailing list