diff --git a/include/asterisk/xml.h b/include/asterisk/xml.h index d80fb26f78..722155848c 100644 --- a/include/asterisk/xml.h +++ b/include/asterisk/xml.h @@ -82,6 +82,23 @@ struct ast_xml_node *ast_xml_new_child(struct ast_xml_node *parent, const char * */ struct ast_xml_node *ast_xml_add_child(struct ast_xml_node *parent, struct ast_xml_node *child); +/*! + * \brief Add a list of child nodes, to a specified parent node. + * \param parent Where to add the child node. + * \param child The child list to add. + * \retval NULL on error. + * \retval non-NULL The added child list on success. + */ +struct ast_xml_node *ast_xml_add_child_list(struct ast_xml_node *parent, struct ast_xml_node *child); + +/*! + * \brief Create a copy of a n ode list. + * \param list The list to copy. + * \retval NULL on error. + * \retval non-NULL The copied list. + */ +struct ast_xml_node *ast_xml_copy_node_list(struct ast_xml_node *list); + /*! * \brief Close an already open document and free the used * structure. diff --git a/main/xml.c b/main/xml.c index 1b90aa9c63..d60dd90bcd 100644 --- a/main/xml.c +++ b/main/xml.c @@ -142,6 +142,22 @@ struct ast_xml_node *ast_xml_add_child(struct ast_xml_node *parent, struct ast_x return (struct ast_xml_node *) xmlAddChild((xmlNode *) parent, (xmlNode *) child); } +struct ast_xml_node *ast_xml_add_child_list(struct ast_xml_node *parent, struct ast_xml_node *child) +{ + if (!parent || !child) { + return NULL; + } + return (struct ast_xml_node *) xmlAddChildList((xmlNode *) parent, (xmlNode *) child); +} + +struct ast_xml_node *ast_xml_copy_node_list(struct ast_xml_node *list) +{ + if (!list) { + return NULL; + } + return (struct ast_xml_node *) xmlCopyNodeList((xmlNode *) list); +} + struct ast_xml_doc *ast_xml_read_memory(char *buffer, size_t size) { xmlDoc *doc; diff --git a/main/xmldoc.c b/main/xmldoc.c index 7ab27a7905..b4649ac774 100644 --- a/main/xmldoc.c +++ b/main/xmldoc.c @@ -2783,6 +2783,8 @@ static int xml_pathmatch(char *xmlpattern, int xmlpattern_maxlen, glob_t *globbu static char *handle_dump_docs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct documentation_tree *doctree; + struct ast_xml_doc *dumpdoc; + struct ast_xml_node *dumproot; FILE *f; switch (cmd) { @@ -2799,15 +2801,53 @@ static char *handle_dump_docs(struct ast_cli_entry *e, int cmd, struct ast_cli_a if (a->argc != 3) { return CLI_SHOWUSAGE; } + + dumpdoc = ast_xml_new(); + if (!dumpdoc) { + ast_log(LOG_ERROR, "Could not create new XML document\n"); + return CLI_FAILURE; + } + + dumproot = ast_xml_new_node("docs"); + if (!dumproot) { + ast_xml_close(dumpdoc); + ast_log(LOG_ERROR, "Could not create new XML root node\n"); + return CLI_FAILURE; + } + + ast_xml_set_root(dumpdoc, dumproot); + + AST_RWLIST_RDLOCK(&xmldoc_tree); + AST_LIST_TRAVERSE(&xmldoc_tree, doctree, entry) { + struct ast_xml_node *root_node = ast_xml_get_root(doctree->doc); + struct ast_xml_node *kids = ast_xml_node_get_children(root_node); + struct ast_xml_node *kids_copy; + + /* If there are no kids someone screwed up, but we check anyway. */ + if (!kids) { + continue; + } + + kids_copy = ast_xml_copy_node_list(kids); + if (!kids_copy) { + ast_xml_close(dumpdoc); + ast_log(LOG_ERROR, "Could not create copy of XML node list\n"); + return CLI_FAILURE; + } + + ast_xml_add_child_list(dumproot, kids_copy); + } + AST_RWLIST_UNLOCK(&xmldoc_tree); + if (!(f = fopen(a->argv[2], "w"))) { + ast_xml_close(dumpdoc); ast_log(LOG_ERROR, "Could not open file '%s': %s\n", a->argv[2], strerror(errno)); return CLI_FAILURE; } - AST_RWLIST_RDLOCK(&xmldoc_tree); - AST_LIST_TRAVERSE(&xmldoc_tree, doctree, entry) { - ast_xml_doc_dump_file(f, doctree->doc); - } - AST_RWLIST_UNLOCK(&xmldoc_tree); + + ast_xml_doc_dump_file(f, dumpdoc); + ast_xml_close(dumpdoc); + fclose(f); return CLI_SUCCESS; }