summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
authorEliel C. Sardanons <eliels@gmail.com>2008-11-12 00:17:43 +0000
committerEliel C. Sardanons <eliels@gmail.com>2008-11-12 00:17:43 +0000
commit6f31fed83f91018f70d453afd2003150587b8856 (patch)
treeea3966ab1c52341565ff036f510bb7ecddaef0b4 /main
parentf50966c16acf6105f02e41820acf223505d2963d (diff)
Implement AGI XML documentation parsing functions.
A new <agi> element is used to describe the XML documentation. We have the usual synopsis,syntax,description and seealso for AGI commands. The CLI 'agi show commands' command was changed to show all the documentation se ctions. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@156051 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main')
-rw-r--r--main/xmldoc.c203
1 files changed, 193 insertions, 10 deletions
diff --git a/main/xmldoc.c b/main/xmldoc.c
index c24a6b7a5..3a68b6cab 100644
--- a/main/xmldoc.c
+++ b/main/xmldoc.c
@@ -57,6 +57,8 @@ struct documentation_tree {
AST_RWLIST_ENTRY(documentation_tree) entry;
};
+static char *xmldoc_get_syntax_cmd(struct ast_xml_node *fixnode, const char *name, int printname);
+
/*!
* \brief Container of documentation trees
*
@@ -548,17 +550,18 @@ static __attribute__((format(printf,4,5))) void xmldoc_reverse_helper(int revers
}
/*! \internal
- * \brief Check if the passed node has <argument> tags inside it.
- * \param node Root node to search argument elements.
+ * \brief Check if the passed node has 'what' tags inside it.
+ * \param node Root node to search 'what' elements.
+ * \param what node name to search inside node.
* \retval 1 If a <argument> element is found inside 'node'.
* \retval 0 If no <argument> is found inside 'node'.
*/
-static int xmldoc_has_arguments(struct ast_xml_node *fixnode)
+static int xmldoc_has_inside(struct ast_xml_node *fixnode, const char *what)
{
struct ast_xml_node *node = fixnode;
for (node = ast_xml_node_get_children(fixnode); node; node = ast_xml_node_get_next(node)) {
- if (!strcasecmp(ast_xml_node_get_name(node), "argument")) {
+ if (!strcasecmp(ast_xml_node_get_name(node), what)) {
return 1;
}
}
@@ -575,7 +578,7 @@ static int xmldoc_has_arguments(struct ast_xml_node *fixnode)
* \retval NULL on error.
* \retval An ast_malloc'ed string with the syntax generated.
*/
-static char *xmldoc_get_syntax(struct ast_xml_node *rootnode, const char *rootname, const char *childname, int printparenthesis, int printrootname)
+static char *xmldoc_get_syntax_fun(struct ast_xml_node *rootnode, const char *rootname, const char *childname, int printparenthesis, int printrootname)
{
#define GOTONEXT(__rev, __a) (__rev ? ast_xml_node_get_prev(__a) : ast_xml_node_get_next(__a))
#define ISLAST(__rev, __a) (__rev == 1 ? (ast_xml_node_get_prev(__a) ? 0 : 1) : (ast_xml_node_get_next(__a) ? 0 : 1))
@@ -679,7 +682,7 @@ static char *xmldoc_get_syntax(struct ast_xml_node *rootnode, const char *rootna
}
/* Get the argument name, if it is not the leaf, go inside that parameter. */
- if (xmldoc_has_arguments(node)) {
+ if (xmldoc_has_inside(node, "arguments")) {
parenthesis = ast_xml_get_attribute(node, "hasparams");
prnparenthesis = 0;
if (parenthesis) {
@@ -691,7 +694,7 @@ static char *xmldoc_get_syntax(struct ast_xml_node *rootnode, const char *rootna
}
argname = ast_xml_get_attribute(node, "name");
if (argname) {
- paramname = xmldoc_get_syntax(node, argname, "argument", prnparenthesis, prnparenthesis);
+ paramname = xmldoc_get_syntax_fun(node, argname, "argument", prnparenthesis, prnparenthesis);
ast_xml_free_attr(argname);
paramnamemalloc = 1;
} else {
@@ -805,6 +808,182 @@ static char *xmldoc_get_syntax(struct ast_xml_node *rootnode, const char *rootna
#undef MP
}
+/*! \internal
+ * \brief Parse an enumlist inside a <parameter> to generate a COMMAND
+ * syntax.
+ * \param fixnode A pointer to the <enumlist> node.
+ * \retval {<unknown>} on error.
+ * \retval A string inside brackets {} with the enum's separated by pipes |.
+ */
+static char *xmldoc_parse_cmd_enumlist(struct ast_xml_node *fixnode)
+{
+ struct ast_xml_node *node = fixnode;
+ struct ast_str *paramname;
+ char *enumname, *ret;
+ int first = 1;
+
+ paramname = ast_str_create(128);
+ if (!paramname) {
+ return ast_strdup("{<unkown>}");
+ }
+
+ ast_str_append(&paramname, 0, "{");
+
+ for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
+ if (strcasecmp(ast_xml_node_get_name(node), "enum")) {
+ continue;
+ }
+
+ enumname = xmldoc_get_syntax_cmd(node, "", 0);
+ if (!enumname) {
+ continue;
+ }
+ if (!first) {
+ ast_str_append(&paramname, 0, "|");
+ }
+ ast_str_append(&paramname, 0, "%s", enumname);
+ first = 0;
+ ast_free(enumname);
+ }
+
+ ast_str_append(&paramname, 0, "}");
+
+ ret = ast_strdup(paramname->str);
+ ast_free(paramname);
+
+ return ret;
+}
+
+/*! \internal
+ * \brief Generate a syntax of COMMAND type.
+ * \param fixnode The <syntax> node pointer.
+ * \param name The name of the 'command'.
+ * \param printname Print the name of the command before the paramters?
+ * \retval On error, return just 'name'.
+ * \retval On success return the generated syntax.
+ */
+static char *xmldoc_get_syntax_cmd(struct ast_xml_node *fixnode, const char *name, int printname)
+{
+ struct ast_str *syntax;
+ struct ast_xml_node *tmpnode, *node = fixnode;
+ char *ret;
+ const char *paramname, *paramtype, *attrname, *literal;
+ int required, isenum, first = 1, isliteral;
+
+ syntax = ast_str_create(128);
+ if (!syntax) {
+ /* at least try to return something... */
+ return ast_strdup(name);
+ }
+
+ /* append name to output string. */
+ if (printname) {
+ ast_str_append(&syntax, 0, "%s", name);
+ first = 0;
+ }
+
+ 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")) {
+ continue;
+ }
+
+ if (xmldoc_has_inside(node, "parameter")) {
+ /* is this a recursive parameter. */
+ paramname = xmldoc_get_syntax_cmd(node, "", 0);
+ isenum = 1;
+ } else if (!xmldoc_has_inside(node, "enumlist")) {
+ /* this is a simple parameter. */
+ attrname = ast_xml_get_attribute(node, "name");
+ if (!attrname) {
+ /* ignore this bogus parameter and continue. */
+ continue;
+ }
+ paramname = ast_strdup(attrname);
+ ast_xml_free_attr(attrname);
+ isenum = 0;
+ } else {
+ /* parse enumlist (note that this is a special enumlist
+ that is used to describe a syntax like {<param1>|<param2>|...} */
+ for (tmpnode = ast_xml_node_get_children(node); tmpnode; tmpnode = ast_xml_node_get_next(tmpnode)) {
+ if (!strcasecmp(ast_xml_node_get_name(tmpnode), "enumlist")) {
+ break;
+ }
+ }
+ paramname = xmldoc_parse_cmd_enumlist(tmpnode);
+ isenum = 1;
+ }
+
+ /* Is this parameter required? */
+ required = 0;
+ paramtype = ast_xml_get_attribute(node, "required");
+ if (paramtype) {
+ required = ast_true(paramtype);
+ ast_xml_free_attr(paramtype);
+ }
+
+ /* Is this a replaceable value or a fixed parameter value? */
+ isliteral = 0;
+ literal = ast_xml_get_attribute(node, "literal");
+ if (literal) {
+ isliteral = ast_true(literal);
+ ast_xml_free_attr(literal);
+ }
+
+ /* if required="false" print with [...].
+ * if literal="true" or is enum print without <..>.
+ * if not first print a space at the beginning.
+ */
+ ast_str_append(&syntax, 0, "%s%s%s%s%s%s",
+ (first ? "" : " "),
+ (required ? "" : "["),
+ (isenum || isliteral ? "" : "<"),
+ paramname,
+ (isenum || isliteral ? "" : ">"),
+ (required ? "" : "]"));
+ first = 0;
+ ast_xml_free_attr(paramname);
+ }
+
+ /* return a common string. */
+ ret = ast_strdup(syntax->str);
+ ast_free(syntax);
+
+ return ret;
+}
+
+/*! \brief Types of syntax that we are able to generate. */
+enum syntaxtype {
+ FUNCTION_SYNTAX,
+ COMMAND_SYNTAX
+};
+
+/*! \brief Mapping between type of node and type of syntax to generate. */
+struct strsyntaxtype {
+ const char *type;
+ enum syntaxtype stxtype;
+} stxtype[] = {
+ { "function", FUNCTION_SYNTAX },
+ { "application", FUNCTION_SYNTAX },
+ { "agi", COMMAND_SYNTAX }
+};
+
+/*! \internal
+ * \brief Get syntax type based on type of node.
+ * \param type Type of node.
+ * \retval The type of syntax to generate based on the type of node.
+ */
+static enum syntaxtype xmldoc_get_syntax_type(const char *type)
+{
+ int i;
+ for (i=0; i < ARRAY_LEN(stxtype); i++) {
+ if (!strcasecmp(stxtype[i].type, type)) {
+ return stxtype[i].stxtype;
+ }
+ }
+
+ return FUNCTION_SYNTAX;
+}
+
char *ast_xmldoc_build_syntax(const char *type, const char *name)
{
struct ast_xml_node *node;
@@ -822,7 +1001,11 @@ char *ast_xmldoc_build_syntax(const char *type, const char *name)
}
if (node) {
- syntax = xmldoc_get_syntax(node, name, "parameter", 1, 1);
+ if (xmldoc_get_syntax_type(type) == FUNCTION_SYNTAX) {
+ syntax = xmldoc_get_syntax_fun(node, name, "parameter", 1, 1);
+ } else {
+ syntax = xmldoc_get_syntax_cmd(node, name, 1);
+ }
}
return syntax;
}
@@ -1294,7 +1477,7 @@ static void xmldoc_parse_optionlist(struct ast_xml_node *fixnode, const char *ta
continue;
}
- optionsyntax = xmldoc_get_syntax(node, optname, "argument", 0, 1);
+ optionsyntax = xmldoc_get_syntax_fun(node, optname, "argument", 0, 1);
if (!optionsyntax) {
continue;
}
@@ -1325,7 +1508,7 @@ static void xmldoc_parse_parameter(struct ast_xml_node *fixnode, const char *tab
return;
}
- hasarguments = xmldoc_has_arguments(node);
+ hasarguments = xmldoc_has_inside(node, "arguments");
if (!(paramname = ast_xml_get_attribute(node, "name"))) {
/* parameter MUST have an attribute name. */
return;