diff --git a/apps/app_fax.c b/apps/app_fax.c index e2085cbbb1..5285ba8338 100644 --- a/apps/app_fax.c +++ b/apps/app_fax.c @@ -46,7 +46,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/manager.h" /*** DOCUMENTATION - + Send a Fax @@ -91,7 +91,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - + Receive a Fax diff --git a/doc/appdocsxml.dtd b/doc/appdocsxml.dtd index 1de0ea452d..328752c304 100644 --- a/doc/appdocsxml.dtd +++ b/doc/appdocsxml.dtd @@ -14,10 +14,12 @@ + + diff --git a/include/asterisk/module.h b/include/asterisk/module.h index aaa8cbef32..db9c5b4656 100644 --- a/include/asterisk/module.h +++ b/include/asterisk/module.h @@ -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 */ diff --git a/include/asterisk/xmldoc.h b/include/asterisk/xmldoc.h index c876b46da5..4256dc1e91 100644 --- a/include/asterisk/xmldoc.h +++ b/include/asterisk/xmldoc.h @@ -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 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 */ diff --git a/main/loader.c b/main/loader.c index 5fe84449f2..6cd5ffbdbf 100644 --- a/main/loader.c +++ b/main/loader.c @@ -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 diff --git a/main/manager.c b/main/manager.c index d4b1b9577d..3beb815aca 100644 --- a/main/manager.c +++ b/main/manager.c @@ -5225,23 +5225,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); diff --git a/main/pbx.c b/main/pbx.c index 0e528fd4f7..a10293d77c 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -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) { diff --git a/main/xmldoc.c b/main/xmldoc.c index bbbb590e4f..6dfca71927 100644 --- a/main/xmldoc.c +++ b/main/xmldoc.c @@ -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) diff --git a/res/res_agi.c b/res/res_agi.c index d9c45e94d6..edb7b9c38b 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -3147,10 +3147,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 diff --git a/res/res_fax.c b/res/res_fax.c index c3c5a2ed61..468a2de6be 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -84,7 +84,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/translate.h" /*** DOCUMENTATION - + Receive a FAX and save as a TIFF/F file. @@ -116,7 +116,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") FAXOPT - + Sends a specified TIFF/F file as a FAX. @@ -155,7 +155,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") FAXOPT - + Gets/sets various pieces of information about a fax session.