summaryrefslogtreecommitdiff
path: root/main/xmldoc.c
diff options
context:
space:
mode:
Diffstat (limited to 'main/xmldoc.c')
-rw-r--r--main/xmldoc.c254
1 files changed, 244 insertions, 10 deletions
diff --git a/main/xmldoc.c b/main/xmldoc.c
index 225ed6611..a38b59852 100644
--- a/main/xmldoc.c
+++ b/main/xmldoc.c
@@ -38,6 +38,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/term.h"
#include "asterisk/astobj2.h"
#include "asterisk/xmldoc.h"
+#include "asterisk/cli.h"
#ifdef AST_XML_DOCS
@@ -979,6 +980,10 @@ static char *xmldoc_get_syntax_cmd(struct ast_xml_node *fixnode, const char *nam
const char *paramtype, *attrname, *literal;
int required, isenum, first = 1, isliteral;
+ if (!fixnode) {
+ return NULL;
+ }
+
syntax = ast_str_create(128);
if (!syntax) {
/* at least try to return something... */
@@ -1078,6 +1083,10 @@ static char *xmldoc_get_syntax_manager(struct ast_xml_node *fixnode, const char
int required;
char *ret;
+ if (!fixnode) {
+ return NULL;
+ }
+
syntax = ast_str_create(128);
if (!syntax) {
return ast_strdup(name);
@@ -1118,11 +1127,76 @@ static char *xmldoc_get_syntax_manager(struct ast_xml_node *fixnode, const char
return ret;
}
+static char *xmldoc_get_syntax_config_object(struct ast_xml_node *fixnode, const char *name)
+{
+ struct ast_xml_node *matchinfo, *tmp;
+ int match;
+ const char *attr_value;
+ const char *text;
+ RAII_VAR(struct ast_str *, syntax, ast_str_create(128), ast_free);
+
+ if (!syntax || !fixnode) {
+ return NULL;
+ }
+ if (!(matchinfo = ast_xml_find_element(ast_xml_node_get_children(fixnode), "matchInfo", NULL, NULL))) {
+ return NULL;
+ }
+ if (!(tmp = ast_xml_find_element(ast_xml_node_get_children(matchinfo), "category", NULL, NULL))) {
+ return NULL;
+ }
+ attr_value = ast_xml_get_attribute(tmp, "match");
+ if (attr_value) {
+ match = ast_true(attr_value);
+ text = ast_xml_get_text(tmp);
+ ast_str_set(&syntax, 0, "category %s /%s/", match ? "=~" : "!~", text);
+ ast_xml_free_attr(attr_value);
+ }
+
+ if ((tmp = ast_xml_find_element(ast_xml_node_get_children(matchinfo), "field", NULL, NULL))) {
+ text = ast_xml_get_text(tmp);
+ attr_value = ast_xml_get_attribute(tmp, "name");
+ ast_str_append(&syntax, 0, " matchfield: %s = %s", S_OR(attr_value, "Unknown"), text);
+ ast_xml_free_attr(attr_value);
+ }
+ return ast_strdup(ast_str_buffer(syntax));
+}
+
+static char *xmldoc_get_syntax_config_option(struct ast_xml_node *fixnode, const char *name)
+{
+ const char *type;
+ const char *default_value;
+ const char *regex;
+ RAII_VAR(struct ast_str *, syntax, ast_str_create(128), ast_free);
+
+ if (!syntax || !fixnode) {
+ return NULL;
+ }
+ type = ast_xml_get_attribute(fixnode, "type");
+ default_value = ast_xml_get_attribute(fixnode, "default");
+
+ regex = ast_xml_get_attribute(fixnode, "regex");
+ ast_str_set(&syntax, 0, "%s = [%s] (Default: %s) (Regex: %s)\n",
+ name,
+ type,
+ default_value,
+ regex ? regex : "False");
+
+ ast_xml_free_attr(type);
+ ast_xml_free_attr(default_value);
+ ast_xml_free_attr(regex);
+
+ return ast_strdup(ast_str_buffer(syntax));
+}
+
/*! \brief Types of syntax that we are able to generate. */
enum syntaxtype {
FUNCTION_SYNTAX,
MANAGER_SYNTAX,
MANAGER_EVENT_SYNTAX,
+ CONFIG_INFO_SYNTAX,
+ CONFIG_FILE_SYNTAX,
+ CONFIG_OPTION_SYNTAX,
+ CONFIG_OBJECT_SYNTAX,
COMMAND_SYNTAX
};
@@ -1131,11 +1205,15 @@ static struct strsyntaxtype {
const char *type;
enum syntaxtype stxtype;
} stxtype[] = {
- { "function", FUNCTION_SYNTAX },
- { "application", FUNCTION_SYNTAX },
- { "manager", MANAGER_SYNTAX },
- { "managerEvent", MANAGER_EVENT_SYNTAX },
- { "agi", COMMAND_SYNTAX }
+ { "function", FUNCTION_SYNTAX },
+ { "application", FUNCTION_SYNTAX },
+ { "manager", MANAGER_SYNTAX },
+ { "managerEvent", MANAGER_EVENT_SYNTAX },
+ { "configInfo", CONFIG_INFO_SYNTAX },
+ { "configFile", CONFIG_FILE_SYNTAX },
+ { "configOption", CONFIG_OPTION_SYNTAX },
+ { "configObject", CONFIG_OBJECT_SYNTAX },
+ { "agi", COMMAND_SYNTAX },
};
/*! \internal
@@ -1170,9 +1248,10 @@ static enum syntaxtype xmldoc_get_syntax_type(const char *type)
*
* \since 11
*/
-static char *_ast_xmldoc_build_syntax(struct ast_xml_node *node, const char *type, const char *name)
+static char *_ast_xmldoc_build_syntax(struct ast_xml_node *root_node, const char *type, const char *name)
{
char *syntax = NULL;
+ struct ast_xml_node *node = root_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), "syntax")) {
@@ -1180,10 +1259,6 @@ static char *_ast_xmldoc_build_syntax(struct ast_xml_node *node, const char *typ
}
}
- if (!node) {
- return syntax;
- }
-
switch (xmldoc_get_syntax_type(type)) {
case FUNCTION_SYNTAX:
syntax = xmldoc_get_syntax_fun(node, name, "parameter", 1, 1);
@@ -1197,6 +1272,12 @@ static char *_ast_xmldoc_build_syntax(struct ast_xml_node *node, const char *typ
case MANAGER_EVENT_SYNTAX:
syntax = xmldoc_get_syntax_manager(node, name, "Event");
break;
+ case CONFIG_OPTION_SYNTAX:
+ syntax = xmldoc_get_syntax_config_option(root_node, name);
+ break;
+ case CONFIG_OBJECT_SYNTAX:
+ syntax = xmldoc_get_syntax_config_object(node, name);
+ break;
default:
syntax = xmldoc_get_syntax_fun(node, name, "parameter", 1, 1);
}
@@ -2198,6 +2279,7 @@ static struct ast_xml_doc_item *xmldoc_build_documentation_item(struct ast_xml_n
if (!(item = ast_xml_doc_item_alloc(name, type))) {
return NULL;
}
+ item->node = node;
syntax = _ast_xmldoc_build_syntax(node, type, name);
seealso = _ast_xmldoc_build_seealso(node);
@@ -2230,6 +2312,105 @@ static struct ast_xml_doc_item *xmldoc_build_documentation_item(struct ast_xml_n
return item;
}
+struct ast_xml_xpath_results *__attribute__((format(printf, 1, 2))) ast_xmldoc_query(const char *fmt, ...)
+{
+ struct ast_xml_xpath_results *results = NULL;
+ struct documentation_tree *doctree;
+ RAII_VAR(struct ast_str *, xpath_str, ast_str_create(128), ast_free);
+ va_list ap;
+
+ if (!xpath_str) {
+ return NULL;
+ }
+
+ va_start(ap, fmt);
+ ast_str_set_va(&xpath_str, 0, fmt, ap);
+ va_end(ap);
+
+ AST_RWLIST_RDLOCK(&xmldoc_tree);
+ AST_LIST_TRAVERSE(&xmldoc_tree, doctree, entry) {
+ if (!(results = ast_xml_query(doctree->doc, ast_str_buffer(xpath_str)))) {
+ continue;
+ }
+ break;
+ }
+ AST_RWLIST_UNLOCK(&xmldoc_tree);
+
+ return results;
+}
+
+static void build_config_docs(struct ast_xml_node *cur, struct ast_xml_doc_item **tail)
+{
+ struct ast_xml_node *iter;
+ struct ast_xml_doc_item *item;
+
+ for (iter = ast_xml_node_get_children(cur); iter; iter = ast_xml_node_get_next(iter)) {
+ if (strncasecmp(ast_xml_node_get_name(iter), "config", 6)) {
+ continue;
+ }
+ /* Now add all of the child config-related items to the list */
+ if (!(item = xmldoc_build_documentation_item(iter, ast_xml_get_attribute(iter, "name"), ast_xml_node_get_name(iter)))) {
+ ast_log(LOG_ERROR, "Could not build documentation for '%s:%s'\n", ast_xml_node_get_name(iter), ast_xml_get_attribute(iter, "name"));
+ break;
+ }
+ if (!strcasecmp(ast_xml_node_get_name(iter), "configOption")) {
+ ast_string_field_set(item, ref, ast_xml_get_attribute(cur, "name"));
+ }
+ (*tail)->next = item;
+ *tail = (*tail)->next;
+ build_config_docs(iter, tail);
+ }
+}
+
+int ast_xmldoc_regenerate_doc_item(struct ast_xml_doc_item *item)
+{
+ const char *name;
+ char *syntax;
+ char *seealso;
+ char *arguments;
+ char *synopsis;
+ char *description;
+
+ if (!item || !item->node) {
+ return -1;
+ }
+
+ name = ast_xml_get_attribute(item->node, "name");
+ if (!name) {
+ return -1;
+ }
+
+ syntax = _ast_xmldoc_build_syntax(item->node, item->type, name);
+ seealso = _ast_xmldoc_build_seealso(item->node);
+ arguments = _ast_xmldoc_build_arguments(item->node);
+ synopsis = _ast_xmldoc_build_synopsis(item->node);
+ description = _ast_xmldoc_build_description(item->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);
+ ast_xml_free_attr(name);
+ return 0;
+}
+
struct ao2_container *ast_xmldoc_build_documentation(const char *type)
{
struct ao2_container *docs;
@@ -2282,6 +2463,19 @@ struct ao2_container *ast_xmldoc_build_documentation(const char *type)
}
item = root;
break;
+ case CONFIG_INFO_SYNTAX:
+ {
+ struct ast_xml_doc_item *tail;
+ if (item || !ast_xml_node_get_children(node) || strcasecmp(ast_xml_node_get_name(node), "configInfo")) {
+ break;
+ }
+ if (!(item = xmldoc_build_documentation_item(node, ast_xml_get_attribute(node, "name"), "configInfo"))) {
+ break;
+ }
+ tail = item;
+ build_config_docs(node, &tail);
+ break;
+ }
default:
item = xmldoc_build_documentation_item(node, name, type);
}
@@ -2299,6 +2493,9 @@ struct ao2_container *ast_xmldoc_build_documentation(const char *type)
return docs;
}
+int ast_xmldoc_regenerate_doc_item(struct ast_xml_doc_item *item);
+
+
#if !defined(HAVE_GLOB_NOMAGIC) || !defined(HAVE_GLOB_BRACE) || defined(DEBUG_NONGNU)
static int xml_pathmatch(char *xmlpattern, int xmlpattern_maxlen, glob_t *globbuf)
{
@@ -2342,11 +2539,47 @@ static int xml_pathmatch(char *xmlpattern, int xmlpattern_maxlen, glob_t *globbu
}
#endif
+static char *handle_dump_docs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ struct documentation_tree *doctree;
+ FILE *f;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "xmldoc dump";
+ e->usage =
+ "Usage: xmldoc dump <filename>\n"
+ " Dump XML documentation to a file\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc != 3) {
+ return CLI_SHOWUSAGE;
+ }
+ if (!(f = fopen(a->argv[2], "w"))) {
+ 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);
+ fclose(f);
+ return CLI_SUCCESS;
+}
+
+static struct ast_cli_entry cli_dump_xmldocs = AST_CLI_DEFINE(handle_dump_docs, "Dump the XML docs to the specified file");
+
/*! \brief Close and unload XML documentation. */
static void xmldoc_unload_documentation(void)
{
struct documentation_tree *doctree;
+ ast_cli_unregister(&cli_dump_xmldocs);
+
AST_RWLIST_WRLOCK(&xmldoc_tree);
while ((doctree = AST_RWLIST_REMOVE_HEAD(&xmldoc_tree, entry))) {
ast_free(doctree->filename);
@@ -2390,6 +2623,7 @@ int ast_xmldoc_load_documentation(void)
/* initialize the XML library. */
ast_xml_init();
+ ast_cli_register(&cli_dump_xmldocs);
/* register function to be run when asterisk finish. */
ast_register_atexit(xmldoc_unload_documentation);