[asterisk-commits] kmoore: trunk r419342 - in /trunk: doc/ include/asterisk/ main/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Jul 24 08:01:08 CDT 2014


Author: kmoore
Date: Thu Jul 24 08:00:59 2014
New Revision: 419342

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=419342
Log:
AMI: Allow for command response documentation

Allow for responses to AMI actions/commands to be documented properly
in XML and displayed via the CLI. Response events are documented
exactly as standard AMI events are documented.

Review: https://reviewboard.asterisk.org/r/3812/

Modified:
    trunk/doc/appdocsxml.dtd
    trunk/include/asterisk/manager.h
    trunk/include/asterisk/xmldoc.h
    trunk/main/config_options.c
    trunk/main/manager.c
    trunk/main/manager_bridges.c
    trunk/main/xmldoc.c

Modified: trunk/doc/appdocsxml.dtd
URL: http://svnview.digium.com/svn/asterisk/trunk/doc/appdocsxml.dtd?view=diff&rev=419342&r1=419341&r2=419342
==============================================================================
--- trunk/doc/appdocsxml.dtd (original)
+++ trunk/doc/appdocsxml.dtd Thu Jul 24 08:00:59 2014
@@ -26,10 +26,14 @@
   <!ATTLIST agi language CDATA #REQUIRED>
   <!ATTLIST agi module CDATA #IMPLIED>
 
-  <!ELEMENT manager (synopsis?,syntax?,description?,see-also?)>
+  <!ELEMENT manager (synopsis?,syntax?,description?,see-also?,responses?)>
   <!ATTLIST manager name CDATA #REQUIRED>
   <!ATTLIST manager language CDATA #REQUIRED>
   <!ATTLIST manager module CDATA #IMPLIED>
+
+  <!ELEMENT responses (list-elements?,(managerEvent|xi:include))>
+
+  <!ELEMENT list-elements (managerEvent+|xi:include+)>
 
   <!ELEMENT managerEvent (managerEventInstance+)>
   <!ATTLIST managerEvent name CDATA #REQUIRED>

Modified: trunk/include/asterisk/manager.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/manager.h?view=diff&rev=419342&r1=419341&r2=419342
==============================================================================
--- trunk/include/asterisk/manager.h (original)
+++ trunk/include/asterisk/manager.h Thu Jul 24 08:00:59 2014
@@ -148,6 +148,10 @@
 		AST_STRING_FIELD(arguments);	/*!< Description of each argument. */
 		AST_STRING_FIELD(seealso);	/*!< See also */
 	);
+	/*! Possible list element response events. */
+	struct ast_xml_doc_item *list_responses;
+	/*! Final response event. */
+	struct ast_xml_doc_item *final_response;
 	/*! Permission required for action.  EVENT_FLAG_* */
 	int authority;
 	/*! Function to be called */

Modified: trunk/include/asterisk/xmldoc.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/xmldoc.h?view=diff&rev=419342&r1=419341&r2=419342
==============================================================================
--- trunk/include/asterisk/xmldoc.h (original)
+++ trunk/include/asterisk/xmldoc.h Thu Jul 24 08:00:59 2014
@@ -36,6 +36,13 @@
 
 struct ao2_container;
 struct ast_xml_node;
+
+/*!
+ * \brief The struct to be used as the head of an ast_xml_doc_item list
+ *        when being manipulated
+ * \since 13.0.0
+ */
+AST_LIST_HEAD(ast_xml_doc_item_list, ast_xml_doc_item);
 
 /*! \brief Struct that contains the XML documentation for a particular item.  Note
  * that this is an ao2 ref counted object.
@@ -70,7 +77,7 @@
 	 */
 	struct ast_xml_node *node;
 	/*! The next XML documentation item that matches the same name/item type */
-	struct ast_xml_doc_item *next;
+	AST_LIST_ENTRY(ast_xml_doc_item) next;
 };
 
 /*! \brief Execute an XPath query on the loaded XML documentation
@@ -115,6 +122,34 @@
 char *ast_xmldoc_build_arguments(const char *type, const char *name, const char *module);
 
 /*!
+ * \brief Generate the [final response] tag based on type of node ('application',
+ *        'function' or 'agi') and name.
+ *
+ * \param type 'application', 'function' or 'agi'
+ * \param name Name of the application or function to build the 'responses' tag.
+ * \param module The module the item is in (optional, can be NULL)
+ *
+ * \return An XMLDoc item list with the [final response] tag content.
+ *
+ * \since 13.0.0
+ */
+struct ast_xml_doc_item *ast_xmldoc_build_final_response(const char *type, const char *name, const char *module);
+
+/*!
+ * \brief Generate the [list responses] tag based on type of node ('application',
+ *        'function' or 'agi') and name.
+ *
+ * \param type 'application', 'function' or 'agi'
+ * \param name Name of the application or function to build the 'responses' tag.
+ * \param module The module the item is in (optional, can be NULL)
+ *
+ * \return An XMLDoc item list with the [list responses] tag content.
+ *
+ * \since 13.0.0
+ */
+struct ast_xml_doc_item *ast_xmldoc_build_list_responses(const char *type, const char *name, const char *module);
+
+/*!
  *  \brief Colorize and put delimiters (instead of tags) to the xmldoc output.
  *  \param bwinput Not colorized input with tags.
  *  \param withcolors Result output with colors.

Modified: trunk/main/config_options.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/config_options.c?view=diff&rev=419342&r1=419341&r2=419342
==============================================================================
--- trunk/main/config_options.c (original)
+++ trunk/main/config_options.c Thu Jul 24 08:00:59 2014
@@ -249,7 +249,7 @@
 		return NULL;
 	}
 	/* First is just the configInfo, we can skip it */
-	while ((iter = iter->next)) {
+	while ((iter = AST_LIST_NEXT(iter, next))) {
 		size_t x;
 		if (strcasecmp(iter->name, name)) {
 			continue;
@@ -274,7 +274,7 @@
 		return NULL;
 	}
 	/* First is just the config Info, skip it */
-	while ((iter = iter->next)) {
+	while ((iter = AST_LIST_NEXT(iter, next))) {
 		if (!strcasecmp(iter->type, "configObject") && !strcasecmp(iter->name, name)) {
 			break;
 		}
@@ -915,7 +915,7 @@
 	}
 
 	cur = info;
-	while ((cur = cur->next)) {
+	while ((cur = AST_LIST_NEXT(cur, next))) {
 		if (!strcasecmp(cur->type, "configObject") && !strncasecmp(word, cur->name, wordlen) && ++which > state) {
 			c = ast_strdup(cur->name);
 			break;
@@ -944,7 +944,7 @@
 	}
 
 	cur = info;
-	while ((cur = cur->next)) {
+	while ((cur = AST_LIST_NEXT(cur, next))) {
 		if (!strcasecmp(cur->type, "configOption") && !strcasecmp(cur->ref, option) && !strncasecmp(word, cur->name, wordlen) && ++which > state) {
 			c = ast_strdup(cur->name);
 			break;
@@ -1109,7 +1109,7 @@
 
 	tmp = item;
 	ast_cli(a->fd, "Configuration option types for %s:\n", tmp->name);
-	while ((tmp = tmp->next)) {
+	while ((tmp = AST_LIST_NEXT(tmp, next))) {
 		if (!strcasecmp(tmp->type, "configObject")) {
 			ast_cli(a->fd, "%-25s -- %-65.65s\n", tmp->name,
 				ast_str_buffer(tmp->synopsis));
@@ -1135,7 +1135,7 @@
 	}
 
 	tmp = item;
-	while ((tmp = tmp->next)) {
+	while ((tmp = AST_LIST_NEXT(tmp, next))) {
 		if (!strcasecmp(tmp->type, "configObject") && !strcasecmp(tmp->name, a->argv[4])) {
 			match = 1;
 			term_color(option_type, tmp->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(option_type));
@@ -1161,7 +1161,7 @@
 
 	/* Now iterate over the options for the type */
 	tmp = item;
-	while ((tmp = tmp->next)) {
+	while ((tmp = AST_LIST_NEXT(tmp, next))) {
 		if (!strcasecmp(tmp->type, "configOption") && !strcasecmp(tmp->ref, a->argv[4])) {
 			ast_cli(a->fd, "%-25s -- %-65.65s\n", tmp->name,
 					ast_str_buffer(tmp->synopsis));
@@ -1186,7 +1186,7 @@
 		return;
 	}
 	tmp = item;
-	while ((tmp = tmp->next)) {
+	while ((tmp = AST_LIST_NEXT(tmp, next))) {
 		if (!strcasecmp(tmp->type, "configOption") && !strcasecmp(tmp->ref, a->argv[4]) && !strcasecmp(tmp->name, a->argv[5])) {
 			if (match) {
 				ast_cli(a->fd, "\n");

Modified: trunk/main/manager.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/manager.c?view=diff&rev=419342&r1=419341&r2=419342
==============================================================================
--- trunk/main/manager.c (original)
+++ trunk/main/manager.c Thu Jul 24 08:00:59 2014
@@ -1912,6 +1912,8 @@
 	return ret;
 }
 
+static void print_event_instance(struct ast_cli_args *a, struct ast_xml_doc_item *instance);
+
 static char *handle_showmancmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	struct manager_action *cur;
@@ -1919,7 +1921,8 @@
 	int num, l, which;
 	char *ret = NULL;
 #ifdef AST_XML_DOCS
-	char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64], arguments_title[64], privilege_title[64];
+	char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64];
+	char arguments_title[64], privilege_title[64], final_response_title[64], list_responses_title[64];
 #endif
 
 	switch (cmd) {
@@ -1955,6 +1958,8 @@
 	term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA, 0, 40);
 	term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
 	term_color(privilege_title, "[Privilege]\n", COLOR_MAGENTA, 0, 40);
+	term_color(final_response_title, "[Final Response]\n", COLOR_MAGENTA, 0, 40);
+	term_color(list_responses_title, "[List Responses]\n", COLOR_MAGENTA, 0, 40);
 #endif
 
 	AST_RWLIST_RDLOCK(&actions);
@@ -1971,13 +1976,34 @@
 					char *arguments = ast_xmldoc_printable(S_OR(cur->arguments, "Not available"), 1);
 					char *seealso = ast_xmldoc_printable(S_OR(cur->seealso, "Not available"), 1);
 					char *privilege = ast_xmldoc_printable(S_OR(authority->str, "Not available"), 1);
-					ast_cli(a->fd, "%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n",
+					char *responses = ast_xmldoc_printable("None", 1);
+					ast_cli(a->fd, "%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s",
 						syntax_title, syntax,
 						synopsis_title, synopsis,
 						description_title, description,
 						arguments_title, arguments,
 						seealso_title, seealso,
-						privilege_title, privilege);
+						privilege_title, privilege,
+						list_responses_title);
+
+					if (!cur->list_responses) {
+						ast_cli(a->fd, "%s\n\n", responses);
+					} else {
+						struct ast_xml_doc_item *temp;
+						for (temp = cur->list_responses; temp; temp = AST_LIST_NEXT(temp, next)) {
+							ast_cli(a->fd, "Event: %s\n", temp->name);
+							print_event_instance(a, temp);
+						}
+					}
+
+					ast_cli(a->fd, "%s", final_response_title);
+
+					if (!cur->final_response) {
+						ast_cli(a->fd, "%s\n\n", responses);
+					} else {
+						ast_cli(a->fd, "Event: %s\n", cur->final_response->name);
+						print_event_instance(a, cur->final_response);
+					}
 				} else
 #endif
 				{
@@ -6309,6 +6335,8 @@
 		/* The string fields were initialized. */
 		ast_string_field_free_memory(doomed);
 	}
+	ao2_cleanup(doomed->final_response);
+	ao2_cleanup(doomed->list_responses);
 }
 
 /*! \brief register a new command with manager, including online help. This is
@@ -6353,6 +6381,9 @@
 		tmpxml = ast_xmldoc_build_arguments("manager", action, NULL);
 		ast_string_field_set(cur, arguments, tmpxml);
 		ast_free(tmpxml);
+
+		cur->final_response = ast_xmldoc_build_final_response("manager", action, NULL);
+		cur->list_responses = ast_xmldoc_build_list_responses("manager", action, NULL);
 
 		cur->docsrc = AST_XML_DOC;
 	} else
@@ -7745,6 +7776,43 @@
 	return CLI_SUCCESS;
 }
 
+static void print_event_instance(struct ast_cli_args *a, struct ast_xml_doc_item *instance)
+{
+	char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64], arguments_title[64];
+
+	term_color(synopsis_title, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
+	term_color(description_title, "[Description]\n", COLOR_MAGENTA, 0, 40);
+	term_color(syntax_title, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
+	term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA, 0, 40);
+	term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
+
+	if (!ast_strlen_zero(ast_str_buffer(instance->synopsis))) {
+		char *synopsis = ast_xmldoc_printable(ast_str_buffer(instance->synopsis), 1);
+		ast_cli(a->fd, "%s%s\n\n", synopsis_title, synopsis);
+		ast_free(synopsis);
+	}
+	if (!ast_strlen_zero(ast_str_buffer(instance->syntax))) {
+		char *syntax = ast_xmldoc_printable(ast_str_buffer(instance->syntax), 1);
+		ast_cli(a->fd, "%s%s\n\n", syntax_title, syntax);
+		ast_free(syntax);
+	}
+	if (!ast_strlen_zero(ast_str_buffer(instance->description))) {
+		char *description = ast_xmldoc_printable(ast_str_buffer(instance->description), 1);
+		ast_cli(a->fd, "%s%s\n\n", description_title, description);
+		ast_free(description);
+	}
+	if (!ast_strlen_zero(ast_str_buffer(instance->arguments))) {
+		char *arguments = ast_xmldoc_printable(ast_str_buffer(instance->arguments), 1);
+		ast_cli(a->fd, "%s%s\n\n", arguments_title, arguments);
+		ast_free(arguments);
+	}
+	if (!ast_strlen_zero(ast_str_buffer(instance->seealso))) {
+		char *seealso = ast_xmldoc_printable(ast_str_buffer(instance->seealso), 1);
+		ast_cli(a->fd, "%s%s\n\n", seealso_title, seealso);
+		ast_free(seealso);
+	}
+}
+
 static char *handle_manager_show_event(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	RAII_VAR(struct ao2_container *, events, NULL, ao2_cleanup);
@@ -7753,7 +7821,6 @@
 	int length;
 	int which;
 	char *match = NULL;
-	char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64], arguments_title[64];
 
 	if (cmd == CLI_INIT) {
 		e->command = "manager show event";
@@ -7794,39 +7861,9 @@
 		return CLI_SUCCESS;
 	}
 
-	term_color(synopsis_title, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
-	term_color(description_title, "[Description]\n", COLOR_MAGENTA, 0, 40);
-	term_color(syntax_title, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
-	term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA, 0, 40);
-	term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
-
 	ast_cli(a->fd, "Event: %s\n", a->argv[3]);
-	for (temp = item; temp; temp = temp->next) {
-		if (!ast_strlen_zero(ast_str_buffer(temp->synopsis))) {
-			char *synopsis = ast_xmldoc_printable(ast_str_buffer(temp->synopsis), 1);
-			ast_cli(a->fd, "%s%s\n\n", synopsis_title, synopsis);
-			ast_free(synopsis);
-		}
-		if (!ast_strlen_zero(ast_str_buffer(temp->syntax))) {
-			char *syntax = ast_xmldoc_printable(ast_str_buffer(temp->syntax), 1);
-			ast_cli(a->fd, "%s%s\n\n", syntax_title, syntax);
-			ast_free(syntax);
-		}
-		if (!ast_strlen_zero(ast_str_buffer(temp->description))) {
-			char *description = ast_xmldoc_printable(ast_str_buffer(temp->description), 1);
-			ast_cli(a->fd, "%s%s\n\n", description_title, description);
-			ast_free(description);
-		}
-		if (!ast_strlen_zero(ast_str_buffer(temp->arguments))) {
-			char *arguments = ast_xmldoc_printable(ast_str_buffer(temp->arguments), 1);
-			ast_cli(a->fd, "%s%s\n\n", arguments_title, arguments);
-			ast_free(arguments);
-		}
-		if (!ast_strlen_zero(ast_str_buffer(temp->seealso))) {
-			char *seealso = ast_xmldoc_printable(ast_str_buffer(temp->seealso), 1);
-			ast_cli(a->fd, "%s%s\n\n", seealso_title, seealso);
-			ast_free(seealso);
-		}
+	for (temp = item; temp; temp = AST_LIST_NEXT(temp, next)) {
+		print_event_instance(a, temp);
 	}
 
 	ao2_ref(item, -1);

Modified: trunk/main/manager_bridges.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/manager_bridges.c?view=diff&rev=419342&r1=419341&r2=419342
==============================================================================
--- trunk/main/manager_bridges.c (original)
+++ trunk/main/manager_bridges.c Thu Jul 24 08:00:59 2014
@@ -100,6 +100,26 @@
 		<description>
 			<para>Returns detailed information about a bridge and the channels in it.</para>
 		</description>
+		<responses>
+			<list-elements>
+				<managerEvent language="en_US" name="BridgeInfoChannel">
+					<managerEventInstance class="EVENT_FLAG_COMMAND">
+						<synopsis>Information about a channel in a bridge.</synopsis>
+						<syntax>
+							<channel_snapshot/>
+						</syntax>
+					</managerEventInstance>
+				</managerEvent>
+			</list-elements>
+			<managerEvent language="en_US" name="BridgeInfoComplete">
+				<managerEventInstance class="EVENT_FLAG_COMMAND">
+					<synopsis>Information about a bridge.</synopsis>
+					<syntax>
+						<bridge_snapshot/>
+					</syntax>
+				</managerEventInstance>
+			</managerEvent>
+		</responses>
 	</manager>
 	<manager name="BridgeDestroy" language="en_US">
 		<synopsis>

Modified: trunk/main/xmldoc.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/xmldoc.c?view=diff&rev=419342&r1=419341&r2=419342
==============================================================================
--- trunk/main/xmldoc.c (original)
+++ trunk/main/xmldoc.c Thu Jul 24 08:00:59 2014
@@ -2300,9 +2300,9 @@
 	ast_free(doc->description);
 	ast_string_field_free_memory(doc);
 
-	if (doc->next) {
-		ao2_ref(doc->next, -1);
-		doc->next = NULL;
+	if (AST_LIST_NEXT(doc, next)) {
+		ao2_ref(AST_LIST_NEXT(doc, next), -1);
+		AST_LIST_NEXT(doc, next) = NULL;
 	}
 }
 
@@ -2428,6 +2428,139 @@
 	return item;
 }
 
+/*!
+ * \internal
+ * \brief Build the list responses for an item
+ *
+ * \param manager_action The action node to parse
+ *
+ * \note This method exists for when you already have the node.  This
+ * prevents having to lock the documentation tree twice
+ *
+ * \retval A list of ast_xml_doc_items
+ * \retval NULL on failure
+ *
+ * \since 13.0.0
+ */
+static struct ast_xml_doc_item *xmldoc_build_list_responses(struct ast_xml_node *manager_action)
+{
+	struct ast_xml_node *event;
+	struct ast_xml_node *responses;
+	struct ast_xml_node *list_elements;
+	struct ast_xml_doc_item_list root;
+
+	AST_LIST_HEAD_INIT(&root);
+
+	responses = ast_xml_find_element(ast_xml_node_get_children(manager_action), "responses", NULL, NULL);
+	if (!responses) {
+		return NULL;
+	}
+
+	list_elements = ast_xml_find_element(ast_xml_node_get_children(responses), "list-elements", NULL, NULL);
+	if (!list_elements) {
+		return NULL;
+	}
+
+	/* Iterate over managerEvent nodes */
+	for (event = ast_xml_node_get_children(list_elements); event; event = ast_xml_node_get_next(event)) {
+		struct ast_xml_node *event_instance;
+		const char *name = ast_xml_get_attribute(event, "name");
+		struct ast_xml_doc_item *new_item;
+
+		if (!name || strcmp(ast_xml_node_get_name(event), "managerEvent")) {
+			continue;
+		}
+
+		event_instance = ast_xml_find_element(ast_xml_node_get_children(event),
+			"managerEventInstance", NULL, NULL);
+		new_item = xmldoc_build_documentation_item(event_instance, name, "managerEvent");
+		if (!new_item) {
+			ao2_cleanup(AST_LIST_FIRST(&root));
+			return NULL;
+		}
+
+		AST_LIST_INSERT_TAIL(&root, new_item, next);
+	}
+
+	return AST_LIST_FIRST(&root);
+}
+
+struct ast_xml_doc_item *ast_xmldoc_build_list_responses(const char *type, const char *name, const char *module)
+{
+	struct ast_xml_node *node;
+
+	if (ast_strlen_zero(type) || ast_strlen_zero(name)) {
+		return NULL;
+	}
+
+	node = xmldoc_get_node(type, name, module, documentation_language);
+
+	if (!node || !ast_xml_node_get_children(node)) {
+		return NULL;
+	}
+
+	return xmldoc_build_list_responses(node);
+}
+
+/*!
+ * \internal
+ * \brief Build the final response for an item
+ *
+ * \param manager_action The action node to parse
+ *
+ * \note This method exists for when you already have the node.  This
+ * prevents having to lock the documentation tree twice
+ *
+ * \retval An ast_xml_doc_item
+ * \retval NULL on failure
+ *
+ * \since 13.0.0
+ */
+static struct ast_xml_doc_item *xmldoc_build_final_response(struct ast_xml_node *manager_action)
+{
+	struct ast_xml_node *responses;
+	struct ast_xml_node *final_response_event;
+	struct ast_xml_node *event_instance;
+
+	responses = ast_xml_find_element(ast_xml_node_get_children(manager_action),
+		"responses", NULL, NULL);
+	if (!responses) {
+		return NULL;
+	}
+
+	final_response_event = ast_xml_find_element(ast_xml_node_get_children(responses),
+		"managerEvent", NULL, NULL);
+	if (!final_response_event) {
+		return NULL;
+	}
+
+	event_instance = ast_xml_find_element(ast_xml_node_get_children(final_response_event),
+		"managerEventInstance", NULL, NULL);
+	if (!event_instance) {
+		return NULL;
+	}
+
+	return xmldoc_build_documentation_item(event_instance,
+		ast_xml_get_attribute(final_response_event, "name"), "managerEvent");
+}
+
+struct ast_xml_doc_item *ast_xmldoc_build_final_response(const char *type, const char *name, const char *module)
+{
+	struct ast_xml_node *node;
+
+	if (ast_strlen_zero(type) || ast_strlen_zero(name)) {
+		return NULL;
+	}
+
+	node = xmldoc_get_node(type, name, module, documentation_language);
+
+	if (!node || !ast_xml_node_get_children(node)) {
+		return NULL;
+	}
+
+	return xmldoc_build_final_response(node);
+}
+
 struct ast_xml_xpath_results *__attribute__((format(printf, 1, 2))) ast_xmldoc_query(const char *fmt, ...)
 {
 	struct ast_xml_xpath_results *results = NULL;
@@ -2455,7 +2588,7 @@
 	return results;
 }
 
-static void build_config_docs(struct ast_xml_node *cur, struct ast_xml_doc_item **tail)
+static void build_config_docs(struct ast_xml_node *cur, struct ast_xml_doc_item_list *root)
 {
 	struct ast_xml_node *iter;
 	struct ast_xml_doc_item *item;
@@ -2478,9 +2611,8 @@
 			ast_string_field_set(item, ref, name);
 			ast_xml_free_attr(name);
 		}
-		(*tail)->next = item;
-		*tail = (*tail)->next;
-		build_config_docs(iter, tail);
+		AST_LIST_INSERT_TAIL(root, item, next);
+		build_config_docs(iter, root);
 	}
 }
 
@@ -2536,7 +2668,6 @@
 struct ao2_container *ast_xmldoc_build_documentation(const char *type)
 {
 	struct ao2_container *docs;
-	struct ast_xml_doc_item *item = NULL, *root = NULL;
 	struct ast_xml_node *node = NULL, *instance = NULL;
 	struct documentation_tree *doctree;
 	const char *name;
@@ -2555,6 +2686,8 @@
 		}
 
 		for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
+			struct ast_xml_doc_item *item = NULL;
+
 			/* Ignore empty nodes or nodes that aren't of the type requested */
 			if (!ast_xml_node_get_children(node) || strcasecmp(ast_xml_node_get_name(node), type)) {
 				continue;
@@ -2566,6 +2699,10 @@
 
 			switch (xmldoc_get_syntax_type(type)) {
 			case MANAGER_EVENT_SYNTAX:
+			{
+				struct ast_xml_doc_item_list root;
+
+				AST_LIST_HEAD_INIT(&root);
 				for (instance = ast_xml_node_get_children(node); instance; instance = ast_xml_node_get_next(instance)) {
 					struct ast_xml_doc_item *temp;
 					if (!ast_xml_node_get_children(instance) || strcasecmp(ast_xml_node_get_name(instance), "managerEventInstance")) {
@@ -2575,28 +2712,27 @@
 					if (!temp) {
 						break;
 					}
-					if (!item) {
-						item = temp;
-						root = item;
-					} else {
-						item->next = temp;
-						item = temp;
-					}
+					AST_LIST_INSERT_TAIL(&root, temp, next);
 				}
-				item = root;
+				item = AST_LIST_FIRST(&root);
 				break;
+			}
 			case CONFIG_INFO_SYNTAX:
 			{
-				struct ast_xml_doc_item *tail;
 				RAII_VAR(const char *, name, ast_xml_get_attribute(node, "name"), ast_xml_free_attr);
-				if (item || !ast_xml_node_get_children(node) || strcasecmp(ast_xml_node_get_name(node), "configInfo")) {
+
+				if (!ast_xml_node_get_children(node) || strcasecmp(ast_xml_node_get_name(node), "configInfo")) {
 					break;
 				}
-				if (!(item = xmldoc_build_documentation_item(node, name, "configInfo"))) {
-					break;
+
+				item = xmldoc_build_documentation_item(node, name, "configInfo");
+				if (item) {
+					struct ast_xml_doc_item_list root;
+
+					AST_LIST_HEAD_INIT(&root);
+					AST_LIST_INSERT_TAIL(&root, item, next);
+					build_config_docs(node, &root);
 				}
-				tail = item;
-				build_config_docs(node, &tail);
 				break;
 			}
 			default:
@@ -2607,7 +2743,6 @@
 			if (item) {
 				ao2_link(docs, item);
 				ao2_t_ref(item, -1, "Dispose of creation ref");
-				item = NULL;
 			}
 		}
 	}




More information about the asterisk-commits mailing list