summaryrefslogtreecommitdiff
path: root/main/xmldoc.c
diff options
context:
space:
mode:
Diffstat (limited to 'main/xmldoc.c')
-rw-r--r--main/xmldoc.c474
1 files changed, 399 insertions, 75 deletions
diff --git a/main/xmldoc.c b/main/xmldoc.c
index 7ef81f181..631444431 100644
--- a/main/xmldoc.c
+++ b/main/xmldoc.c
@@ -34,9 +34,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/_private.h"
#include "asterisk/paths.h"
#include "asterisk/linkedlists.h"
-#include "asterisk/strings.h"
#include "asterisk/config.h"
#include "asterisk/term.h"
+#include "asterisk/astobj2.h"
#include "asterisk/xmldoc.h"
#ifdef AST_XML_DOCS
@@ -1043,13 +1043,14 @@ static char *xmldoc_get_syntax_cmd(struct ast_xml_node *fixnode, const char *nam
}
/*! \internal
- * \brief Generate an AMI action syntax.
- * \param fixnode The manager action node pointer.
- * \param name The name of the manager action.
+ * \brief Generate an AMI action/event syntax.
+ * \param fixnode The manager action/event node pointer.
+ * \param name The name of the manager action/event.
+ * \param manager_type "Action" or "Event"
* \retval The generated syntax.
* \retval NULL on error.
*/
-static char *xmldoc_get_syntax_manager(struct ast_xml_node *fixnode, const char *name)
+static char *xmldoc_get_syntax_manager(struct ast_xml_node *fixnode, const char *name, const char *manager_type)
{
struct ast_str *syntax;
struct ast_xml_node *node = fixnode;
@@ -1062,7 +1063,7 @@ static char *xmldoc_get_syntax_manager(struct ast_xml_node *fixnode, const char
return ast_strdup(name);
}
- ast_str_append(&syntax, 0, "Action: %s", name);
+ ast_str_append(&syntax, 0, "%s: %s", manager_type, name);
for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
if (strcasecmp(ast_xml_node_get_name(node), "parameter")) {
@@ -1070,7 +1071,7 @@ static char *xmldoc_get_syntax_manager(struct ast_xml_node *fixnode, const char
}
/* Is this parameter required? */
- required = 0;
+ required = !strcasecmp(manager_type, "event") ? 1 : 0;
paramtype = ast_xml_get_attribute(node, "required");
if (paramtype) {
required = ast_true(paramtype);
@@ -1087,7 +1088,6 @@ static char *xmldoc_get_syntax_manager(struct ast_xml_node *fixnode, const char
(required ? "" : "["),
attrname,
(required ? "" : "]"));
-
ast_xml_free_attr(attrname);
}
@@ -1102,6 +1102,7 @@ static char *xmldoc_get_syntax_manager(struct ast_xml_node *fixnode, const char
enum syntaxtype {
FUNCTION_SYNTAX,
MANAGER_SYNTAX,
+ MANAGER_EVENT_SYNTAX,
COMMAND_SYNTAX
};
@@ -1110,10 +1111,11 @@ static struct strsyntaxtype {
const char *type;
enum syntaxtype stxtype;
} stxtype[] = {
- { "function", FUNCTION_SYNTAX },
- { "application", FUNCTION_SYNTAX },
- { "manager", MANAGER_SYNTAX },
- { "agi", COMMAND_SYNTAX }
+ { "function", FUNCTION_SYNTAX },
+ { "application", FUNCTION_SYNTAX },
+ { "manager", MANAGER_SYNTAX },
+ { "managerEvent", MANAGER_EVENT_SYNTAX },
+ { "agi", COMMAND_SYNTAX }
};
/*! \internal
@@ -1133,40 +1135,67 @@ static enum syntaxtype xmldoc_get_syntax_type(const char *type)
return FUNCTION_SYNTAX;
}
-char *ast_xmldoc_build_syntax(const char *type, const char *name, const char *module)
+/*!
+ * \internal
+ * \brief Build syntax information for an item
+ * \param node The syntax node to parse
+ * \param type The source type
+ * \param name The name of the item that the syntax describes
+ *
+ * \note This method exists for when you already have the node. This
+ * prevents having to lock the documentation tree twice
+ *
+ * \returns A malloc'd character pointer to the syntax of the item
+ * \returns NULL on failure
+ *
+ * \since 11
+ */
+static char *_ast_xmldoc_build_syntax(struct ast_xml_node *node, const char *type, const char *name)
{
- struct ast_xml_node *node;
char *syntax = NULL;
- node = xmldoc_get_node(type, name, module, documentation_language);
- if (!node) {
- return NULL;
- }
-
for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
if (!strcasecmp(ast_xml_node_get_name(node), "syntax")) {
break;
}
}
- if (node) {
- switch (xmldoc_get_syntax_type(type)) {
- case FUNCTION_SYNTAX:
- syntax = xmldoc_get_syntax_fun(node, name, "parameter", 1, 1);
- break;
- case COMMAND_SYNTAX:
- syntax = xmldoc_get_syntax_cmd(node, name, 1);
- break;
- case MANAGER_SYNTAX:
- syntax = xmldoc_get_syntax_manager(node, name);
- break;
- default:
- syntax = xmldoc_get_syntax_fun(node, name, "parameter", 1, 1);
- }
+ if (!node) {
+ return syntax;
}
+
+ switch (xmldoc_get_syntax_type(type)) {
+ case FUNCTION_SYNTAX:
+ syntax = xmldoc_get_syntax_fun(node, name, "parameter", 1, 1);
+ break;
+ case COMMAND_SYNTAX:
+ syntax = xmldoc_get_syntax_cmd(node, name, 1);
+ break;
+ case MANAGER_SYNTAX:
+ syntax = xmldoc_get_syntax_manager(node, name, "Action");
+ break;
+ case MANAGER_EVENT_SYNTAX:
+ syntax = xmldoc_get_syntax_manager(node, name, "Event");
+ break;
+ default:
+ syntax = xmldoc_get_syntax_fun(node, name, "parameter", 1, 1);
+ }
+
return syntax;
}
+char *ast_xmldoc_build_syntax(const char *type, const char *name, const char *module)
+{
+ struct ast_xml_node *node;
+
+ node = xmldoc_get_node(type, name, module, documentation_language);
+ if (!node) {
+ return NULL;
+ }
+
+ return _ast_xmldoc_build_syntax(node, type, name);
+}
+
/*! \internal
* \brief Parse a <para> element.
* \param node The <para> element pointer.
@@ -1439,25 +1468,27 @@ static int xmldoc_parse_variablelist(struct ast_xml_node *node, const char *tabs
return ret;
}
-char *ast_xmldoc_build_seealso(const char *type, const char *name, const char *module)
+/*!
+ * \internal
+ * \brief Build seealso information for an item
+ * \param node The seealso node to parse
+ *
+ * \note This method exists for when you already have the node. This
+ * prevents having to lock the documentation tree twice
+ *
+ * \returns A malloc'd character pointer to the seealso information of the item
+ * \returns NULL on failure
+ *
+ * \since 11
+ */
+static char *_ast_xmldoc_build_seealso(struct ast_xml_node *node)
{
- struct ast_str *outputstr;
char *output;
- struct ast_xml_node *node;
+ struct ast_str *outputstr;
const char *typename;
const char *content;
int first = 1;
- if (ast_strlen_zero(type) || ast_strlen_zero(name)) {
- return NULL;
- }
-
- /* get the application/function root node. */
- node = xmldoc_get_node(type, name, module, documentation_language);
- if (!node || !ast_xml_node_get_children(node)) {
- return NULL;
- }
-
/* Find the <see-also> node. */
for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
if (!strcasecmp(ast_xml_node_get_name(node), "see-also")) {
@@ -1512,6 +1543,26 @@ char *ast_xmldoc_build_seealso(const char *type, const char *name, const char *m
return output;
}
+char *ast_xmldoc_build_seealso(const char *type, const char *name, const char *module)
+{
+ char *output;
+ struct ast_xml_node *node;
+
+ if (ast_strlen_zero(type) || ast_strlen_zero(name)) {
+ return NULL;
+ }
+
+ /* get the application/function root node. */
+ node = xmldoc_get_node(type, name, module, documentation_language);
+ if (!node || !ast_xml_node_get_children(node)) {
+ return NULL;
+ }
+
+ output = _ast_xmldoc_build_seealso(node);
+
+ return output;
+}
+
/*! \internal
* \brief Parse a <enum> node.
* \brief fixnode An ast_xml_node pointer to the <enum> node.
@@ -1738,21 +1789,26 @@ static void xmldoc_parse_parameter(struct ast_xml_node *fixnode, const char *tab
ast_free(internaltabs);
}
-char *ast_xmldoc_build_arguments(const char *type, const char *name, const char *module)
+/*!
+ * \internal
+ * \brief Build the arguments for an item
+ * \param node The arguments node to parse
+ *
+ * \note This method exists for when you already have the node. This
+ * prevents having to lock the documentation tree twice
+ *
+ * \returns A malloc'd character pointer to the arguments for the item
+ * \returns NULL on failure
+ *
+ * \since 11
+ */
+static char *_ast_xmldoc_build_arguments(struct ast_xml_node *node)
{
- struct ast_xml_node *node;
- struct ast_str *ret = ast_str_create(128);
char *retstr = NULL;
+ struct ast_str *ret;
- if (ast_strlen_zero(type) || ast_strlen_zero(name)) {
- ast_free(ret);
- return NULL;
- }
-
- node = xmldoc_get_node(type, name, module, documentation_language);
-
- if (!node || !ast_xml_node_get_children(node)) {
- ast_free(ret);
+ ret = ast_str_create(128);
+ if (!ret) {
return NULL;
}
@@ -1786,6 +1842,23 @@ char *ast_xmldoc_build_arguments(const char *type, const char *name, const char
return retstr;
}
+char *ast_xmldoc_build_arguments(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 _ast_xmldoc_build_arguments(node);
+}
+
/*! \internal
* \brief Return the string within a node formatted with <para> and <variablelist> elements.
* \param node Parent node where content resides.
@@ -1828,6 +1901,36 @@ static struct ast_str *xmldoc_get_formatted(struct ast_xml_node *node, int raw_o
}
/*!
+ * \brief Get the content of a field (synopsis, description, etc) from an asterisk document tree node
+ * \param node The node to obtain the information from
+ * \param var Name of field to return (synopsis, description, etc).
+ * \param raw Field only contains text, no other elements inside it.
+ * \retval NULL On error.
+ * \retval Field text content on success.
+ * \since 11
+ */
+static char *_xmldoc_build_field(struct ast_xml_node *node, const char *var, int raw)
+{
+ char *ret = NULL;
+ struct ast_str *formatted;
+
+ node = ast_xml_find_element(ast_xml_node_get_children(node), var, NULL, NULL);
+
+ if (!node || !ast_xml_node_get_children(node)) {
+ ast_debug(1, "Cannot find variable '%s' in tree\n", var);
+ return ret;
+ }
+
+ formatted = xmldoc_get_formatted(node, raw, raw);
+ if (ast_str_strlen(formatted) > 0) {
+ ret = ast_strdup(ast_str_buffer(formatted));
+ }
+ ast_free(formatted);
+
+ return ret;
+}
+
+/*!
* \brief Get the content of a field (synopsis, description, etc) from an asterisk document tree
* \param type Type of element (application, function, ...).
* \param name Name of element (Dial, Echo, Playback, ...).
@@ -1839,35 +1942,36 @@ static struct ast_str *xmldoc_get_formatted(struct ast_xml_node *node, int raw_o
static char *xmldoc_build_field(const char *type, const char *name, const char *module, const char *var, int raw)
{
struct ast_xml_node *node;
- char *ret = NULL;
- struct ast_str *formatted;
if (ast_strlen_zero(type) || ast_strlen_zero(name)) {
ast_log(LOG_ERROR, "Tried to look in XML tree with faulty values.\n");
- return ret;
+ return NULL;
}
node = xmldoc_get_node(type, name, module, documentation_language);
if (!node) {
ast_log(LOG_WARNING, "Couldn't find %s %s in XML documentation\n", type, name);
- return ret;
- }
-
- node = ast_xml_find_element(ast_xml_node_get_children(node), var, NULL, NULL);
-
- if (!node || !ast_xml_node_get_children(node)) {
- ast_debug(1, "Cannot find variable '%s' in tree '%s'\n", var, name);
- return ret;
+ return NULL;
}
- formatted = xmldoc_get_formatted(node, raw, raw);
- if (ast_str_strlen(formatted) > 0) {
- ret = ast_strdup(ast_str_buffer(formatted));
- }
- ast_free(formatted);
+ return _xmldoc_build_field(node, var, raw);
+}
- return ret;
+/* \internal
+ * \brief Build the synopsis for an item
+ * \param node The synopsis node
+ *
+ * \note This method exists for when you already have the node. This
+ * prevents having to lock the documentation tree twice
+ *
+ * \returns A malloc'd character pointer to the synopsis information
+ * \returns NULL on failure
+ * \since 11
+ */
+static char *_ast_xmldoc_build_synopsis(struct ast_xml_node *node)
+{
+ return _xmldoc_build_field(node, "synopsis", 1);
}
char *ast_xmldoc_build_synopsis(const char *type, const char *name, const char *module)
@@ -1875,11 +1979,231 @@ char *ast_xmldoc_build_synopsis(const char *type, const char *name, const char *
return xmldoc_build_field(type, name, module, "synopsis", 1);
}
+/*!
+ * \internal
+ * \brief Build the descripton for an item
+ * \param node The description node to parse
+ *
+ * \note This method exists for when you already have the node. This
+ * prevents having to lock the documentation tree twice
+ *
+ * \returns A malloc'd character pointer to the arguments for the item
+ * \returns NULL on failure
+ * \since 11
+ */
+static char *_ast_xmldoc_build_description(struct ast_xml_node *node)
+{
+ return _xmldoc_build_field(node, "description", 0);
+}
+
char *ast_xmldoc_build_description(const char *type, const char *name, const char *module)
{
return xmldoc_build_field(type, name, module, "description", 0);
}
+/*! \internal \brief ast_xml_doc_item ao2 destructor
+ * \since 11
+ */
+static void ast_xml_doc_item_destructor(void *obj)
+{
+ struct ast_xml_doc_item *doc = obj;
+
+ if (!doc) {
+ return;
+ }
+
+ ast_free(doc->syntax);
+ ast_free(doc->seealso);
+ ast_free(doc->arguments);
+ ast_free(doc->synopsis);
+ ast_free(doc->description);
+ ast_string_field_free_memory(doc);
+
+ if (doc->next) {
+ ao2_ref(doc->next, -1);
+ doc->next = NULL;
+ }
+}
+
+/*! \internal
+ * \brief Create an ao2 ref counted ast_xml_doc_item
+ * \param name The name of the item
+ * \param type The item's source type
+ * \since 11
+ */
+static struct ast_xml_doc_item *ast_xml_doc_item_alloc(const char *name, const char *type)
+{
+ struct ast_xml_doc_item *item;
+
+ if (!(item = ao2_alloc(sizeof(*item), ast_xml_doc_item_destructor))) {
+ ast_log(AST_LOG_ERROR, "Failed to allocate memory for ast_xml_doc_item instance\n");
+ return NULL;
+ }
+
+ if ( !(item->syntax = ast_str_create(128))
+ || !(item->seealso = ast_str_create(128))
+ || !(item->arguments = ast_str_create(128))
+ || !(item->synopsis = ast_str_create(128))
+ || !(item->description = ast_str_create(128))) {
+ ast_log(AST_LOG_ERROR, "Failed to allocate strings for ast_xml_doc_item instance\n");
+ goto ast_xml_doc_item_failure;
+ }
+
+ if (ast_string_field_init(item, 64)) {
+ ast_log(AST_LOG_ERROR, "Failed to initialize string field for ast_xml_doc_item instance\n");
+ goto ast_xml_doc_item_failure;
+ }
+ ast_string_field_set(item, name, name);
+ ast_string_field_set(item, type, type);
+
+ return item;
+
+ast_xml_doc_item_failure:
+ ao2_ref(item, -1);
+ return NULL;
+}
+
+/*! \internal
+ * \brief ao2 item hash function for ast_xml_doc_item
+ * \since 11
+ */
+static int ast_xml_doc_item_hash(const void *obj, const int flags)
+{
+ const struct ast_xml_doc_item *item = obj;
+ const char *name = (flags & OBJ_KEY) ? obj : item->name;
+ return ast_str_case_hash(name);
+}
+
+/*! \internal
+ * \brief ao2 item comparison function for ast_xml_doc_item
+ * \since 11
+ */
+static int ast_xml_doc_item_cmp(void *obj, void *arg, int flags)
+{
+ struct ast_xml_doc_item *left = obj;
+ struct ast_xml_doc_item *right = arg;
+ const char *match = (flags & OBJ_KEY) ? arg : right->name;
+ return strcasecmp(left->name, match) ? 0 : (CMP_MATCH | CMP_STOP);
+}
+
+/* \internal
+ * \brief Build an XML documentation item
+ * \param node The root node for the item
+ * \param name The name of the item
+ * \param type The item's source type
+ *
+ * \returns NULL on failure
+ * \returns An ao2 ref counted object
+ * \since 11
+ */
+static struct ast_xml_doc_item *xmldoc_build_documentation_item(struct ast_xml_node *node, const char *name, const char *type)
+{
+ struct ast_xml_doc_item *item;
+ char *syntax;
+ char *seealso;
+ char *arguments;
+ char *synopsis;
+ char *description;
+
+ if (!(item = ast_xml_doc_item_alloc(name, type))) {
+ return NULL;
+ }
+
+ syntax = _ast_xmldoc_build_syntax(node, type, name);
+ seealso = _ast_xmldoc_build_seealso(node);
+ arguments = _ast_xmldoc_build_arguments(node);
+ synopsis = _ast_xmldoc_build_synopsis(node);
+ description = _ast_xmldoc_build_description(node);
+
+ if (syntax) {
+ ast_str_set(&item->syntax, 0, "%s", syntax);
+ }
+ if (seealso) {
+ ast_str_set(&item->seealso, 0, "%s", seealso);
+ }
+ if (arguments) {
+ ast_str_set(&item->arguments, 0, "%s", arguments);
+ }
+ if (synopsis) {
+ ast_str_set(&item->synopsis, 0, "%s", synopsis);
+ }
+ if (description) {
+ ast_str_set(&item->description, 0, "%s", description);
+ }
+
+ ast_free(syntax);
+ ast_free(seealso);
+ ast_free(arguments);
+ ast_free(synopsis);
+ ast_free(description);
+
+ return item;
+}
+
+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;
+
+ if (!(docs = ao2_container_alloc(127, ast_xml_doc_item_hash, ast_xml_doc_item_cmp))) {
+ ast_log(AST_LOG_ERROR, "Failed to create container for xml document item instances\n");
+ return NULL;
+ }
+
+ AST_RWLIST_RDLOCK(&xmldoc_tree);
+ AST_LIST_TRAVERSE(&xmldoc_tree, doctree, entry) {
+ /* the core xml documents have priority over thirdparty document. */
+ node = ast_xml_get_root(doctree->doc);
+ if (!node) {
+ break;
+ }
+
+ for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
+ /* 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;
+ }
+ name = ast_xml_get_attribute(node, "name");
+
+ switch (xmldoc_get_syntax_type(type)) {
+ case MANAGER_EVENT_SYNTAX:
+ 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")) {
+ continue;
+ }
+ temp = xmldoc_build_documentation_item(instance, name, type);
+ if (!temp) {
+ break;
+ }
+ if (!item) {
+ item = temp;
+ root = item;
+ } else {
+ item->next = temp;
+ item = temp;
+ }
+ }
+ item = root;
+ break;
+ default:
+ item = xmldoc_build_documentation_item(node, name, type);
+ }
+
+ if (item) {
+ ao2_link(docs, item);
+ item = NULL;
+ }
+ }
+ }
+ AST_RWLIST_UNLOCK(&xmldoc_tree);
+
+ return docs;
+}
+
#if !defined(HAVE_GLOB_NOMAGIC) || !defined(HAVE_GLOB_BRACE) || defined(DEBUG_NONGNU)
static int xml_pathmatch(char *xmlpattern, int xmlpattern_maxlen, glob_t *globbuf)
{