]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Merged revisions 340108 via svnmerge from
authorMatthew Nicholson <mnicholson@digium.com>
Mon, 10 Oct 2011 14:15:41 +0000 (14:15 +0000)
committerMatthew Nicholson <mnicholson@digium.com>
Mon, 10 Oct 2011 14:15:41 +0000 (14:15 +0000)
https://origsvn.digium.com/svn/asterisk/branches/1.8

........
  r340108 | mnicholson | 2011-10-10 09:14:48 -0500 (Mon, 10 Oct 2011) | 11 lines

  Load the proper XML documentation when multiple modules document the same application.

  This patch adds an optional "module" attribute to the XML documentation spec
  that allows the documentation processor to match apps with identical names from
  different modules to their documentation. This patch also fixes a number of
  bugs with the documentation processor and should make it a little more
  efficient. Support for multiple languages has also been properly implemented.

  ASTERISK-18130
  Review: https://reviewboard.asterisk.org/r/1485/
........

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/10@340109 65c4cc65-6c06-0410-ace0-fbb531ad65f3

apps/app_fax.c
doc/appdocsxml.dtd
include/asterisk/module.h
include/asterisk/xmldoc.h
main/loader.c
main/manager.c
main/pbx.c
main/xmldoc.c
res/res_agi.c
res/res_fax.c

index e2085cbbb18a96406774adda7cb932258a9bc4ba..5285ba83386c465c44852a3fa56592479583db76 100644 (file)
@@ -46,7 +46,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/manager.h"
 
 /*** DOCUMENTATION
-       <application name="SendFAX" language="en_US">
+       <application name="SendFAX" language="en_US" module="app_fax">
                <synopsis>
                        Send a Fax
                </synopsis>
@@ -91,7 +91,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        </variablelist>
                </description>
        </application>
-       <application name="ReceiveFAX" language="en_US">
+       <application name="ReceiveFAX" language="en_US" module="app_fax">
                <synopsis>
                        Receive a Fax
                </synopsis>
index 1de0ea452d69cdae2ba68e4d0db9251c2bebcfb2..328752c3045fe871913f2c6f1315a5d0348089ed 100644 (file)
   <!ELEMENT application (synopsis?,syntax?,description?,see-also?)>
   <!ATTLIST application name CDATA #REQUIRED>
   <!ATTLIST application language CDATA #REQUIRED>
+  <!ATTLIST application module CDATA #IMPLIED>
 
   <!ELEMENT function (synopsis?,syntax?,description?,see-also?)>
   <!ATTLIST function name CDATA #REQUIRED>
   <!ATTLIST function language CDATA #REQUIRED>
+  <!ATTLIST function module CDATA #IMPLIED>
 
   <!ELEMENT agi (synopsis?,syntax?,description?,see-also?)>
   <!ATTLIST agi name CDATA #REQUIRED>
index aaa8cbef324e638702e8d63ee53a64d0167a18a4..db9c5b46568e8ede1d5ee65199f6a46d3edf5eb9 100644 (file)
@@ -175,6 +175,14 @@ char *ast_module_helper(const char *line, const char *word, int pos, int state,
 
 struct ast_module;
 
+/*!
+ * \brief Get the name of a module.
+ * \param mod A pointer to the module.
+ * \return the name of the module
+ * \retval NULL if mod or mod->info is NULL
+ */
+const char *ast_module_name(const struct ast_module *mod);
+
 /* User count routines keep track of which channels are using a given module
    resource.  They can help make removing modules safer, particularly if
    they're in use at the time they have been requested to be removed */
index c876b46da548759a5e5c73f1ac1e06c3b361ac06..4256dc1e91653eecf4ce52406fec93d9f6bc7802 100644 (file)
@@ -36,29 +36,32 @@ enum ast_doc_src {
  *  \brief Get the syntax for a specified application or function.
  *  \param type Application, Function or AGI ?
  *  \param name Name of the application or function.
+ *  \param module The module the item is in (optional, can be NULL)
  *  \retval NULL on error.
  *  \retval The generated syntax in a ast_malloc'ed string.
  */
-char *ast_xmldoc_build_syntax(const char *type, const char *name);
+char *ast_xmldoc_build_syntax(const char *type, const char *name, const char *module);
 
 /*!
  *  \brief Parse the <see-also> node content.
  *  \param type 'application', 'function' or 'agi'.
  *  \param name Application or functions name.
+ *  \param module The module the item is in (optional, can be NULL)
  *  \retval NULL on error.
  *  \retval Content of the see-also node.
  */
-char *ast_xmldoc_build_seealso(const char *type, const char *name);
+char *ast_xmldoc_build_seealso(const char *type, const char *name, const char *module);
 
 /*!
  *  \brief Generate the [arguments] 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 'arguments' tag.
+ *  \param module The module the item is in (optional, can be NULL)
  *  \retval NULL on error.
  *  \retval Output buffer with the [arguments] tag content.
  */
-char *ast_xmldoc_build_arguments(const char *type, const char *name);
+char *ast_xmldoc_build_arguments(const char *type, const char *name, const char *module);
 
 /*!
  *  \brief Colorize and put delimiters (instead of tags) to the xmldoc output.
@@ -73,19 +76,21 @@ char *ast_xmldoc_printable(const char *bwinput, int withcolors);
  *  \brief Generate synopsis documentation from XML.
  *  \param type The source of documentation (application, function, etc).
  *  \param name The name of the application, function, etc.
+ *  \param module The module the item is in (optional, can be NULL)
  *  \retval NULL on error.
  *  \retval A malloc'ed string with the synopsis.
  */
-char *ast_xmldoc_build_synopsis(const char *type, const char *name);
+char *ast_xmldoc_build_synopsis(const char *type, const char *name, const char *module);
 
 /*!
  *  \brief Generate description documentation from XML.
  *  \param type The source of documentation (application, function, etc).
  *  \param name The name of the application, function, etc.
+ *  \param module The module the item is in (optional, can be NULL)
  *  \retval NULL on error.
  *  \retval A malloc'ed string with the formatted description.
  */
-char *ast_xmldoc_build_description(const char *type, const char *name);
+char *ast_xmldoc_build_description(const char *type, const char *name, const char *module);
 
 #endif /* AST_XML_DOCS */
 
index 5fe84449f25ddbd479a2b860066f2bc1bbe6f529..6cd5ffbdbfd533fb63ea95389dda8e33d5e09531 100644 (file)
@@ -96,6 +96,15 @@ struct ast_module {
 
 static AST_LIST_HEAD_STATIC(module_list, ast_module);
 
+const char *ast_module_name(const struct ast_module *mod)
+{
+       if (!mod || !mod->info) {
+               return NULL;
+       }
+
+       return mod->info->name;
+}
+
 /*
  * module_list is cleared by its constructor possibly after
  * we start accumulating embedded modules, so we need to
index 821352d9e54c19085e19b1c345ff1a651c8a836c..629e984299559f500be5cae1f83e63f3068a4d58 100644 (file)
@@ -5215,23 +5215,23 @@ int ast_manager_register2(const char *action, int auth, int (*func)(struct manse
        cur->func = func;
 #ifdef AST_XML_DOCS
        if (ast_strlen_zero(synopsis) && ast_strlen_zero(description)) {
-               tmpxml = ast_xmldoc_build_synopsis("manager", action);
+               tmpxml = ast_xmldoc_build_synopsis("manager", action, NULL);
                ast_string_field_set(cur, synopsis, tmpxml);
                ast_free(tmpxml);
 
-               tmpxml = ast_xmldoc_build_syntax("manager", action);
+               tmpxml = ast_xmldoc_build_syntax("manager", action, NULL);
                ast_string_field_set(cur, syntax, tmpxml);
                ast_free(tmpxml);
 
-               tmpxml = ast_xmldoc_build_description("manager", action);
+               tmpxml = ast_xmldoc_build_description("manager", action, NULL);
                ast_string_field_set(cur, description, tmpxml);
                ast_free(tmpxml);
 
-               tmpxml = ast_xmldoc_build_seealso("manager", action);
+               tmpxml = ast_xmldoc_build_seealso("manager", action, NULL);
                ast_string_field_set(cur, seealso, tmpxml);
                ast_free(tmpxml);
 
-               tmpxml = ast_xmldoc_build_arguments("manager", action);
+               tmpxml = ast_xmldoc_build_arguments("manager", action, NULL);
                ast_string_field_set(cur, arguments, tmpxml);
                ast_free(tmpxml);
 
index f72a62f0b54981eba462adcfea07fabf5b3baf49..d7b6810aac1731522585fcb67fee8c2b1e458926 100644 (file)
@@ -3552,27 +3552,27 @@ static int acf_retrieve_docs(struct ast_custom_function *acf)
        }
 
        /* load synopsis */
-       tmpxml = ast_xmldoc_build_synopsis("function", acf->name);
+       tmpxml = ast_xmldoc_build_synopsis("function", acf->name, ast_module_name(acf->mod));
        ast_string_field_set(acf, synopsis, tmpxml);
        ast_free(tmpxml);
 
        /* load description */
-       tmpxml = ast_xmldoc_build_description("function", acf->name);
+       tmpxml = ast_xmldoc_build_description("function", acf->name, ast_module_name(acf->mod));
        ast_string_field_set(acf, desc, tmpxml);
        ast_free(tmpxml);
 
        /* load syntax */
-       tmpxml = ast_xmldoc_build_syntax("function", acf->name);
+       tmpxml = ast_xmldoc_build_syntax("function", acf->name, ast_module_name(acf->mod));
        ast_string_field_set(acf, syntax, tmpxml);
        ast_free(tmpxml);
 
        /* load arguments */
-       tmpxml = ast_xmldoc_build_arguments("function", acf->name);
+       tmpxml = ast_xmldoc_build_arguments("function", acf->name, ast_module_name(acf->mod));
        ast_string_field_set(acf, arguments, tmpxml);
        ast_free(tmpxml);
 
        /* load seealso */
-       tmpxml = ast_xmldoc_build_seealso("function", acf->name);
+       tmpxml = ast_xmldoc_build_seealso("function", acf->name, ast_module_name(acf->mod));
        ast_string_field_set(acf, seealso, tmpxml);
        ast_free(tmpxml);
 
@@ -5842,31 +5842,35 @@ int ast_register_application2(const char *app, int (*execute)(struct ast_channel
                return -1;
        }
 
+       strcpy(tmp->name, app);
+       tmp->execute = execute;
+       tmp->module = mod;
+
 #ifdef AST_XML_DOCS
        /* Try to lookup the docs in our XML documentation database */
        if (ast_strlen_zero(synopsis) && ast_strlen_zero(description)) {
                /* load synopsis */
-               tmpxml = ast_xmldoc_build_synopsis("application", app);
+               tmpxml = ast_xmldoc_build_synopsis("application", app, ast_module_name(tmp->module));
                ast_string_field_set(tmp, synopsis, tmpxml);
                ast_free(tmpxml);
 
                /* load description */
-               tmpxml = ast_xmldoc_build_description("application", app);
+               tmpxml = ast_xmldoc_build_description("application", app, ast_module_name(tmp->module));
                ast_string_field_set(tmp, description, tmpxml);
                ast_free(tmpxml);
 
                /* load syntax */
-               tmpxml = ast_xmldoc_build_syntax("application", app);
+               tmpxml = ast_xmldoc_build_syntax("application", app, ast_module_name(tmp->module));
                ast_string_field_set(tmp, syntax, tmpxml);
                ast_free(tmpxml);
 
                /* load arguments */
-               tmpxml = ast_xmldoc_build_arguments("application", app);
+               tmpxml = ast_xmldoc_build_arguments("application", app, ast_module_name(tmp->module));
                ast_string_field_set(tmp, arguments, tmpxml);
                ast_free(tmpxml);
 
                /* load seealso */
-               tmpxml = ast_xmldoc_build_seealso("application", app);
+               tmpxml = ast_xmldoc_build_seealso("application", app, ast_module_name(tmp->module));
                ast_string_field_set(tmp, seealso, tmpxml);
                ast_free(tmpxml);
                tmp->docsrc = AST_XML_DOC;
@@ -5879,10 +5883,6 @@ int ast_register_application2(const char *app, int (*execute)(struct ast_channel
        }
 #endif
 
-       strcpy(tmp->name, app);
-       tmp->execute = execute;
-       tmp->module = mod;
-
        /* Store in alphabetical order */
        AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
                if (strcasecmp(tmp->name, cur->name) < 0) {
index bbbb590e4f1d379c930b215f9823f2fed79b5a86..6dfca719277bafeb23648b4afd787743447936c1 100644 (file)
@@ -455,47 +455,97 @@ static void xmldoc_string_cleanup(const char *text, struct ast_str **output, int
        }
 }
 
+/*! \internal
+ * \brief Check if the given attribute on the given node matches the given value.
+ * \param node the node to match
+ * \param attr the name of the attribute
+ * \param value the expected value of the attribute
+ * \retval true if the given attribute contains the given value
+ * \retval false if the given attribute does not exist or does not contain the given value
+ */
+static int xmldoc_attribute_match(struct ast_xml_node *node, const char *attr, const char *value)
+{
+       const char *attr_value = ast_xml_get_attribute(node, attr);
+       int match = attr_value && !strcmp(attr_value, value);
+       ast_xml_free_attr(attr_value);
+       return match;
+}
+
 /*! \internal
  *  \brief Get the application/function node for 'name' application/function with language 'language'
- *         if we don't find any, get the first application with 'name' no matter which language with.
+ *         and module 'module' if we don't find any, get the first application
+ *         with 'name' no matter which language or module.
  *  \param type 'application', 'function', ...
  *  \param name Application or Function name.
+ *  \param module Module item is in.
  *  \param language Try to get this language (if not found try with en_US)
  *  \retval NULL on error.
  *  \retval A node of type ast_xml_node.
  */
-static struct ast_xml_node *xmldoc_get_node(const char *type, const char *name, const char *language)
+static struct ast_xml_node *xmldoc_get_node(const char *type, const char *name, const char *module, const char *language)
 {
        struct ast_xml_node *node = NULL;
+       struct ast_xml_node *first_match = NULL;
+       struct ast_xml_node *lang_match = NULL;
        struct documentation_tree *doctree;
-       const char *lang;
 
        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;
+               }
+
+               node = ast_xml_node_get_children(node);
                while ((node = ast_xml_find_element(node, type, "name", name))) {
+                       if (!ast_xml_node_get_children(node)) {
+                               /* ignore empty nodes */
+                               node = ast_xml_node_get_next(node);
+                               continue;
+                       }
+
+                       if (!first_match) {
+                               first_match = node;
+                       }
+
                        /* Check language */
-                       lang = ast_xml_get_attribute(node, "language");
-                       if (lang && !strcmp(lang, language)) {
-                               ast_xml_free_attr(lang);
-                               break;
-                       } else if (lang) {
-                               ast_xml_free_attr(lang);
+                       if (xmldoc_attribute_match(node, "language", language)) {
+                               if (!lang_match) {
+                                       lang_match = node;
+                               }
+
+                               /* if module is empty we have a match */
+                               if (ast_strlen_zero(module)) {
+                                       break;
+                               }
+
+                               /* Check module */
+                               if (xmldoc_attribute_match(node, "module", module)) {
+                                       break;
+                               }
                        }
+
+                       node = ast_xml_node_get_next(node);
                }
 
-               if (node && ast_xml_node_get_children(node)) {
+               /* if we matched lang and module return this match */
+               if (node) {
                        break;
                }
 
-               /* We didn't find the application documentation for the specified language,
-               so, try to load documentation for any language */
-               node = ast_xml_get_root(doctree->doc);
-               if (ast_xml_node_get_children(node)) {
-                       if ((node = ast_xml_find_element(ast_xml_node_get_children(node), type, "name", name))) {
-                               break;
-                       }
+               /* we didn't match lang and module, just return the first
+                * result with a matching language if we have one */
+               if (lang_match) {
+                       node = lang_match;
+                       break;
+               }
+
+               /* we didn't match with only the language, just return the
+                * first match */
+               if (first_match) {
+                       node = first_match;
+                       break;
                }
        }
        AST_RWLIST_UNLOCK(&xmldoc_tree);
@@ -1077,12 +1127,12 @@ static enum syntaxtype xmldoc_get_syntax_type(const char *type)
        return FUNCTION_SYNTAX;
 }
 
-char *ast_xmldoc_build_syntax(const char *type, const char *name)
+char *ast_xmldoc_build_syntax(const char *type, const char *name, const char *module)
 {
        struct ast_xml_node *node;
        char *syntax = NULL;
 
-       node = xmldoc_get_node(type, name, documentation_language);
+       node = xmldoc_get_node(type, name, module, documentation_language);
        if (!node) {
                return NULL;
        }
@@ -1383,7 +1433,7 @@ 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)
+char *ast_xmldoc_build_seealso(const char *type, const char *name, const char *module)
 {
        struct ast_str *outputstr;
        char *output;
@@ -1397,7 +1447,7 @@ char *ast_xmldoc_build_seealso(const char *type, const char *name)
        }
 
        /* get the application/function root node. */
-       node = xmldoc_get_node(type, name, documentation_language);
+       node = xmldoc_get_node(type, name, module, documentation_language);
        if (!node || !ast_xml_node_get_children(node)) {
                return NULL;
        }
@@ -1677,7 +1727,7 @@ 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)
+char *ast_xmldoc_build_arguments(const char *type, const char *name, const char *module)
 {
        struct ast_xml_node *node;
        struct ast_str *ret = ast_str_create(128);
@@ -1687,7 +1737,7 @@ char *ast_xmldoc_build_arguments(const char *type, const char *name)
                return NULL;
        }
 
-       node = xmldoc_get_node(type, name, documentation_language);
+       node = xmldoc_get_node(type, name, module, documentation_language);
 
        if (!node || !ast_xml_node_get_children(node)) {
                return NULL;
@@ -1772,7 +1822,7 @@ static struct ast_str *xmldoc_get_formatted(struct ast_xml_node *node, int raw_o
  *  \retval NULL On error.
  *  \retval Field text content on success.
  */
-static char *xmldoc_build_field(const char *type, const char *name, const char *var, int raw)
+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;
@@ -1783,7 +1833,7 @@ static char *xmldoc_build_field(const char *type, const char *name, const char *
                return ret;
        }
 
-       node = xmldoc_get_node(type, name, documentation_language);
+       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);
@@ -1806,14 +1856,14 @@ static char *xmldoc_build_field(const char *type, const char *name, const char *
        return ret;
 }
 
-char *ast_xmldoc_build_synopsis(const char *type, const char *name)
+char *ast_xmldoc_build_synopsis(const char *type, const char *name, const char *module)
 {
-       return xmldoc_build_field(type, name, "synopsis", 1);
+       return xmldoc_build_field(type, name, module, "synopsis", 1);
 }
 
-char *ast_xmldoc_build_description(const char *type, const char *name)
+char *ast_xmldoc_build_description(const char *type, const char *name, const char *module)
 {
-       return xmldoc_build_field(type, name, "description", 0);
+       return xmldoc_build_field(type, name, module, "description", 0);
 }
 
 #if !defined(HAVE_GLOB_NOMAGIC) || !defined(HAVE_GLOB_BRACE) || defined(DEBUG_NONGNU)
index 87ae21a6df7c17003fba6bbdb3c6a28bacfd50c2..326cfc5825b4c28d28fa3a2a723a649a16a440df 100644 (file)
@@ -3141,10 +3141,10 @@ int AST_OPTIONAL_API_NAME(ast_agi_register)(struct ast_module *mod, agi_command
                *((enum ast_doc_src *) &cmd->docsrc) = AST_STATIC_DOC;
                if (ast_strlen_zero(cmd->summary) && ast_strlen_zero(cmd->usage)) {
 #ifdef AST_XML_DOCS
-                       *((char **) &cmd->summary) = ast_xmldoc_build_synopsis("agi", fullcmd);
-                       *((char **) &cmd->usage) = ast_xmldoc_build_description("agi", fullcmd);
-                       *((char **) &cmd->syntax) = ast_xmldoc_build_syntax("agi", fullcmd);
-                       *((char **) &cmd->seealso) = ast_xmldoc_build_seealso("agi", fullcmd);
+                       *((char **) &cmd->summary) = ast_xmldoc_build_synopsis("agi", fullcmd, NULL);
+                       *((char **) &cmd->usage) = ast_xmldoc_build_description("agi", fullcmd, NULL);
+                       *((char **) &cmd->syntax) = ast_xmldoc_build_syntax("agi", fullcmd, NULL);
+                       *((char **) &cmd->seealso) = ast_xmldoc_build_seealso("agi", fullcmd, NULL);
                        *((enum ast_doc_src *) &cmd->docsrc) = AST_XML_DOC;
 #endif
 #ifndef HAVE_NULLSAFE_PRINTF
index f9295987702ab4ad171b0904e2f25e5cc0fec21d..0cd3911442395ee32f6b32b0ffc4b986bc6a7726 100644 (file)
@@ -84,7 +84,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/translate.h"
 
 /*** DOCUMENTATION
-       <application name="ReceiveFAX" language="en_US">
+       <application name="ReceiveFAX" language="en_US" module="res_fax">
                <synopsis>
                        Receive a FAX and save as a TIFF/F file.
                </synopsis>
@@ -116,7 +116,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <ref type="function">FAXOPT</ref>
                </see-also>
        </application>
-       <application name="SendFAX" language="en_US">
+       <application name="SendFAX" language="en_US" module="res_fax">
                <synopsis>
                        Sends a specified TIFF/F file as a FAX.
                </synopsis>
@@ -155,7 +155,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <ref type="function">FAXOPT</ref>
                </see-also>
        </application>
-       <function name="FAXOPT" language="en_US">
+       <function name="FAXOPT" language="en_US" module="res_fax">
                <synopsis>
                        Gets/sets various pieces of information about a fax session.
                </synopsis>