@ -68,9 +68,8 @@ static int xmldoc_parse_specialtags(struct ast_xml_node *fixnode, const char *ta
/*!
* \ brief Container of documentation trees
*
* \ note A RWLIST is a sufficient container type to use here for now .
* However , some changes will need to be made to implement ref counting
* if reload support is added in the future .
* \ note A RWLIST is a sufficient container type to use , provided
* the list lock is always held while there are references to the list .
*/
static AST_RWLIST_HEAD_STATIC ( xmldoc_tree , documentation_tree ) ;
@ -430,6 +429,8 @@ static int xmldoc_attribute_match(struct ast_xml_node *node, const char *attr, c
*
* \ retval NULL on error .
* \ retval A node of type ast_xml_node .
*
* \ note Must be called with a RDLOCK held on xmldoc_tree
*/
static struct ast_xml_node * xmldoc_get_node ( const char * type , const char * name , const char * module , const char * language )
{
@ -438,7 +439,6 @@ static struct ast_xml_node *xmldoc_get_node(const char *type, const char *name,
struct ast_xml_node * lang_match = NULL ;
struct documentation_tree * doctree ;
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 ) ;
@ -497,7 +497,6 @@ static struct ast_xml_node *xmldoc_get_node(const char *type, const char *name,
break ;
}
}
AST_RWLIST_UNLOCK ( & xmldoc_tree ) ;
return node ;
}
@ -1253,13 +1252,18 @@ static char *_ast_xmldoc_build_syntax(struct ast_xml_node *root_node, const char
char * ast_xmldoc_build_syntax ( const char * type , const char * name , const char * module )
{
struct ast_xml_node * node ;
char * syntax ;
AST_RWLIST_RDLOCK ( & xmldoc_tree ) ;
node = xmldoc_get_node ( type , name , module , documentation_language ) ;
if ( ! node ) {
AST_RWLIST_UNLOCK ( & xmldoc_tree ) ;
return NULL ;
}
return _ast_xmldoc_build_syntax ( node , type , name ) ;
syntax = _ast_xmldoc_build_syntax ( node , type , name ) ;
AST_RWLIST_UNLOCK ( & xmldoc_tree ) ;
return syntax ;
}
/*!
@ -1705,12 +1709,15 @@ char *ast_xmldoc_build_seealso(const char *type, const char *name, const char *m
}
/* get the application/function root node. */
AST_RWLIST_RDLOCK ( & xmldoc_tree ) ;
node = xmldoc_get_node ( type , name , module , documentation_language ) ;
if ( ! node | | ! ast_xml_node_get_children ( node ) ) {
AST_RWLIST_UNLOCK ( & xmldoc_tree ) ;
return NULL ;
}
output = _ast_xmldoc_build_seealso ( node ) ;
AST_RWLIST_UNLOCK ( & xmldoc_tree ) ;
return output ;
}
@ -2077,18 +2084,23 @@ static char *_ast_xmldoc_build_arguments(struct ast_xml_node *node)
char * ast_xmldoc_build_arguments ( const char * type , const char * name , const char * module )
{
struct ast_xml_node * node ;
char * arguments ;
if ( ast_strlen_zero ( type ) | | ast_strlen_zero ( name ) ) {
return NULL ;
}
AST_RWLIST_RDLOCK ( & xmldoc_tree ) ;
node = xmldoc_get_node ( type , name , module , documentation_language ) ;
if ( ! node | | ! ast_xml_node_get_children ( node ) ) {
AST_RWLIST_UNLOCK ( & xmldoc_tree ) ;
return NULL ;
}
return _ast_xmldoc_build_arguments ( node ) ;
arguments = _ast_xmldoc_build_arguments ( node ) ;
AST_RWLIST_UNLOCK ( & xmldoc_tree ) ;
return arguments ;
}
/*!
@ -2192,20 +2204,27 @@ static char *_xmldoc_build_field(struct ast_xml_node *node, const char *var, int
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 * field ;
if ( ast_strlen_zero ( type ) | | ast_strlen_zero ( name ) ) {
ast_log ( LOG_ERROR , " Tried to look in XML tree with faulty values. \n " ) ;
return NULL ;
}
AST_RWLIST_RDLOCK ( & xmldoc_tree ) ;
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 ) ;
AST_RWLIST_UNLOCK ( & xmldoc_tree ) ;
ast_log ( LOG_WARNING , " Couldn't find %s %s in XML documentation "
" If this module was recently built, run 'xmldoc reload' to refresh documentation \n " ,
type , name ) ;
return NULL ;
}
return _xmldoc_build_field ( node , var , raw ) ;
field = _xmldoc_build_field ( node , var , raw ) ;
AST_RWLIST_UNLOCK ( & xmldoc_tree ) ;
return field ;
}
/*!
@ -2465,18 +2484,23 @@ static struct ast_xml_doc_item *xmldoc_build_list_responses(struct ast_xml_node
struct ast_xml_doc_item * ast_xmldoc_build_list_responses ( const char * type , const char * name , const char * module )
{
struct ast_xml_node * node ;
struct ast_xml_doc_item * responses ;
if ( ast_strlen_zero ( type ) | | ast_strlen_zero ( name ) ) {
return NULL ;
}
AST_RWLIST_RDLOCK ( & xmldoc_tree ) ;
node = xmldoc_get_node ( type , name , module , documentation_language ) ;
if ( ! node | | ! ast_xml_node_get_children ( node ) ) {
AST_RWLIST_UNLOCK ( & xmldoc_tree ) ;
return NULL ;
}
return xmldoc_build_list_responses ( node ) ;
responses = xmldoc_build_list_responses ( node ) ;
AST_RWLIST_UNLOCK ( & xmldoc_tree ) ;
return responses ;
}
/*!
@ -2530,18 +2554,23 @@ static struct ast_xml_doc_item *xmldoc_build_final_response(struct ast_xml_node
struct ast_xml_doc_item * ast_xmldoc_build_final_response ( const char * type , const char * name , const char * module )
{
struct ast_xml_node * node ;
static struct ast_xml_doc_item * response ;
if ( ast_strlen_zero ( type ) | | ast_strlen_zero ( name ) ) {
return NULL ;
}
AST_RWLIST_RDLOCK ( & xmldoc_tree ) ;
node = xmldoc_get_node ( type , name , module , documentation_language ) ;
if ( ! node | | ! ast_xml_node_get_children ( node ) ) {
AST_RWLIST_UNLOCK ( & xmldoc_tree ) ;
return NULL ;
}
return xmldoc_build_final_response ( node ) ;
response = xmldoc_build_final_response ( node ) ;
AST_RWLIST_UNLOCK ( & xmldoc_tree ) ;
return response ;
}
struct ast_xml_xpath_results * __attribute__ ( ( format ( printf , 1 , 2 ) ) ) ast_xmldoc_query ( const char * fmt , . . . )
@ -2860,25 +2889,35 @@ static char *handle_dump_docs(struct ast_cli_entry *e, int cmd, struct ast_cli_a
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 )
static char * handle_reload_docs ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a ) ;
static struct ast_cli_entry cli_reload_xmldocs = AST_CLI_DEFINE ( handle_reload_docs , " Reload the XML docs " ) ;
/*! \note Must be called with xmldoc_tree locked */
static void xmldoc_purge_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 ) ;
ast_xml_close ( doctree - > doc ) ;
ast_free ( doctree ) ;
}
}
/*! \brief Close and unload XML documentation. */
static void xmldoc_unload_documentation ( void )
{
ast_cli_unregister ( & cli_reload_xmldocs ) ;
ast_cli_unregister ( & cli_dump_xmldocs ) ;
AST_RWLIST_WRLOCK ( & xmldoc_tree ) ;
xmldoc_purge_documentation ( ) ;
AST_RWLIST_UNLOCK ( & xmldoc_tree ) ;
ast_xml_finish ( ) ;
}
int ast_xmldoc_load_documentation ( void )
static int xmldoc_load_documentation ( int first_time )
{
struct ast_xml_node * root_node ;
struct ast_xml_doc * tmpdoc ;
@ -2907,12 +2946,14 @@ int ast_xmldoc_load_documentation(void)
ast_config_destroy ( cfg ) ;
}
/* initialize the XML library. */
ast_xml_init ( ) ;
ast_cli_register ( & cli_dump_xmldocs ) ;
/* register function to be run when asterisk finish. */
ast_register_cleanup ( xmldoc_unload_documentation ) ;
if ( first_time ) {
/* initialize the XML library. */
ast_xml_init ( ) ;
ast_cli_register ( & cli_dump_xmldocs ) ;
ast_cli_register ( & cli_reload_xmldocs ) ;
/* register function to be run when asterisk finish. */
ast_register_cleanup ( xmldoc_unload_documentation ) ;
}
globbuf . gl_offs = 0 ; /* slots to reserve in gl_pathv */
@ -2942,6 +2983,16 @@ int ast_xmldoc_load_documentation(void)
ast_free ( xmlpattern ) ;
AST_RWLIST_WRLOCK ( & xmldoc_tree ) ;
if ( ! first_time ) {
/* If we're reloading, purge the existing documentation.
* We do this with the lock held so that if somebody
* else tries to get documentation , there ' s no chance
* of retrieiving it after we purged the old docs
* but before we loaded the new ones . */
xmldoc_purge_documentation ( ) ;
}
/* loop over expanded files */
for ( i = 0 ; i < globbuf . gl_pathc ; i + + ) {
/* check for duplicates (if we already [try to] open the same file. */
@ -2993,4 +3044,31 @@ int ast_xmldoc_load_documentation(void)
return 0 ;
}
int ast_xmldoc_load_documentation ( void )
{
return xmldoc_load_documentation ( 1 ) ;
}
static int xmldoc_reload_documentation ( void )
{
return xmldoc_load_documentation ( 0 ) ;
}
static char * handle_reload_docs ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
{
switch ( cmd ) {
case CLI_INIT :
e - > command = " xmldoc reload " ;
e - > usage =
" Usage: xmldoc reload \n "
" Reload XML documentation \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
xmldoc_reload_documentation ( ) ;
return CLI_SUCCESS ;
}
# endif /* AST_XML_DOCS */