ivrdemo_读取xml
ivrdemo.c
/* * Asterisk -- An open source telephony toolkit.* * Copyright (C) 1999 - 2005,Digium,Inc. * * Mark Spencer <markster@digium.com> * * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site,mailing lists and IRC * channels for your use. * * This program is free software,distributed under the terms of * the GNU General Public License Version 2. See the LICENSE file * at the top of the source tree. */ /*! file * * brief IVR Demo application * * author Mark Spencer <markster@digium.com> * * ingroup applications */ /*** MODULEINFO <defaultenabled>no</defaultenabled> ***/ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <assert.h> #include <mxml.h> #define XML_FILE_PATH "./menu.xml" //define for menu attr #define TITLE "title" #define FLAGS "flags" //define for option attr #define OPTION "option" #define ACTION "action" typedef enum {False = 0,True = 1} BOOL; typedef enum { AST_ACTION_UPONE,/*!< adata is unused */ AST_ACTION_EXIT,/*!< adata is the return value for ast_ivr_menu_run if channel was not hungup */ AST_ACTION_CALLBACK,/*!< adata is an ast_ivr_callback */ AST_ACTION_PLAYBACK,/*!< adata is file to play */ AST_ACTION_BACKGROUND,/*!< adata is file to play */ AST_ACTION_PLAYLIST,/*!< adata is list of files,separated by ; to play */ AST_ACTION_MENU,/*!< adata is a pointer to an ast_ivr_menu */ AST_ACTION_REPEAT,/*!< adata is max # of repeats,cast to a pointer */ AST_ACTION_RESTART,/*!< adata is like repeat,but resets repeats to 0 */ AST_ACTION_TRANSFER,/*!< adata is a string with extenverbatim[@context]endverbatim */ AST_ACTION_WAITOPTION,/*!< adata is a timeout,or 0 for defaults */ AST_ACTION_NOOP,/*!< adata is unused */ AST_ACTION_BACKLIST,/*!< adata is list of files separated by ; allows interruption */ } ast_ivr_action; //define for the last option attr flag typedef enum { STR_ATTR, SUBMENU_ATTR, ULONG_ATTR, FUN_ATTR } option_last_attr_flag; struct ast_ivr_option { char *option; ast_ivr_action action; void *adata; }; typedef struct ast_ivr_option ast_ivr_option_t ; struct ast_ivr_menu { char *title; /*!< Title of menu */ unsigned int flags; /*!< Flags */ struct ast_ivr_option *options; /*!< All options */ }; typedef struct ast_ivr_menu ast_ivr_menu_t ; /************************************************************************************************* * use to parse : <mainmenu falgs=0 options="mainmenu" title="IVR Demo Main Menu"> * <submenu1 falgs=0 options="submenu1" title="IVR Demo Sub Menu1"> */ typedef struct ivr_menu_des_s { const char *title_str ; // title str const char *flags_str ; // flag str //const char *options_str ; // options str unused } ivr_menu_des_t ; typedef struct _value_string { int value; const char *string; } value_string; typedef int (*ivr_demo_func)(const char *chan,void *data); typedef struct _string_2_fun { const char *string; ivr_demo_func fun; } string_2_fun; typedef struct _string_2_menu { const char *string; ast_ivr_menu_t * menu_ptr; } string_2_menu; //static BOOL load_xml_file(const char *filename); static inline int strlen_zero(const char *s); static BOOL load_xml_file(const char *filename,const char *menuname,ast_ivr_menu_t *ivr_menu) ; static BOOL parse_menu_attrs(mxml_node_t *node,ivr_menu_des_t *menu_des); static BOOL parse_option_attrs(mxml_node_t *node,int num_attrs,ast_ivr_option_t *option); static ast_ivr_action str_2_action(const char *str); static int ivr_demo_function(const char *chan,void *data); static ivr_demo_func string_2_fun_pointer( const char * str); static ast_ivr_menu_t* string_2_menu_pointer(const char * str); static BOOL parse_last_option_attr(mxml_node_t *node,ast_ivr_option_t *option); static ast_ivr_option_t *init_ivr_option(int *argc); static ast_ivr_option_t *add_ivr_option(ast_ivr_option_t *option_ptr,int *argc,ast_ivr_option_t option); //this table use to change string to ast_ivr_action static const value_string option_vals[] = { { AST_ACTION_UPONE,"AST_ACTION_UPONE" }, { AST_ACTION_EXIT,"AST_ACTION_EXIT" }, { AST_ACTION_CALLBACK,"AST_ACTION_CALLBACK" }, { AST_ACTION_PLAYBACK,"AST_ACTION_PLAYBACK" }, { AST_ACTION_BACKGROUND,"AST_ACTION_BACKGROUND" }, { AST_ACTION_PLAYLIST,"AST_ACTION_PLAYLIST" }, { AST_ACTION_MENU,"AST_ACTION_MENU" }, { AST_ACTION_REPEAT,"AST_ACTION_REPEAT" }, { AST_ACTION_RESTART,"AST_ACTION_RESTART" }, { AST_ACTION_TRANSFER,"AST_ACTION_TRANSFER" }, { AST_ACTION_WAITOPTION,"AST_ACTION_WAITOPTION" }, { AST_ACTION_NOOP,"AST_ACTION_NOOP" }, { AST_ACTION_BACKLIST,"AST_ACTION_BACKLIST" } }; static value_string option_last_attr_vals[] = { { STR_ATTR, "str" }, { SUBMENU_ATTR,"submenu" }, { ULONG_ATTR, "ulong" }, { FUN_ATTR, "fun" } }; //the ivr_menu static ast_ivr_menu_t ivr_menu ; static ast_ivr_menu_t ivr_submenu ; //this table use to change string to function pointer static string_2_fun string_fun_vals[] = { { "ivr_demo_func", ivr_demo_function } }; //this table use to change string to menu pointer static string_2_menu string_menu_vals[] = { { "ivr_submenu", &ivr_submenu} }; static int ivr_demo_function(const char *chan,void *data) { fprintf(stderr,"Open the file %s error!n",(char *)data); return 1; } /*! brief returns non-zero if the string is not defined,or has zero length */ static inline int strlen_zero(const char *s) { return (!s || (*s == ' ')); } /*********************************************************************************************** filename : the xml file name (including path) menuname : such as : <mainmenu flags=0 title="IVR Demo Main Menu"> ---------> the menuname is mainmenu ....... </mainmenu> <submenu1 flags=0 title="IVR Demo Sub Menu1"> ---------> the menuname is submenu1 ....... </submenu1> ivr_menu_ptr: the pointer of the ast_ivr_menu_t */ static BOOL load_xml_file(const char *filename,ast_ivr_menu_t *ivr_menu_ptr) { FILE *fp = NULL; mxml_node_t *tree; mxml_node_t *menu; mxml_node_t *mainmenu; mxml_node_t *option; ivr_menu_des_t menu_des ; int option_num ; ast_ivr_option_t *ivr_option ; fp = fopen(filename,"r"); if( fp == NULL ) { fprintf(stderr,filename); return False; } fprintf(stderr,"##########Here load_xml_file!############n"); tree = mxmlLoadFile(NULL,fp,MXML_TEXT_CALLBACK); if( tree != False ) { if ((menu = mxmlFindElement(tree,tree,"menu",NULL, MXML_DESCEND)) == NULL) { fprintf(stderr,"Unable to find first <menu> element in XML tree!n"); return False; } if ((mainmenu = mxmlFindElement(menu,menu,menuname,"Unable to find first <%s> element in XML tree!n",menuname); return False; } if( !parse_menu_attrs(mainmenu,&menu_des) ) { fprintf(stderr,"Parse menu attrs error !n"); return False; } //fprintf(stderr,"The menu_des.title_str is %s n",menu_des.title_str); //fprintf(stderr,"The menu_des.flags_str is %s n",menu_des.flags_str); ivr_option = init_ivr_option(&option_num); if( !ivr_option ) { fprintf(stderr,"init_ivr_option error!n"); return False; } for(option=mxmlFindElement(mainmenu,mainmenu,"option",MXML_DESCEND_FIRST); option; option=mxmlFindElement(option,MXML_NO_DESCEND)) { ast_ivr_option_t ast_option ; ast_option.option = NULL ; //init ast_option.action = -1 ; ast_option.adata = NULL ; int num_attrs = option->value.element.num_attrs ; //fprintf(stderr,"The num_attrs is %dn",num_attrs); if( !parse_option_attrs(option,num_attrs,&ast_option) ) { fprintf(stderr,"parse_option_attrs error!n"); return False ; } //option_num += 1 ; ivr_option = add_ivr_option(ivr_option,&option_num,ast_option); if( !ivr_option ) { fprintf(stderr,"add_ivr_option error!n"); return False; } } ivr_menu_ptr->title = (char *)menu_des.title_str; ivr_menu_ptr->flags = atoi( menu_des.flags_str ); ivr_menu_ptr->options = ivr_option ; } fclose(fp); return True; } /********************************************************************** such as : <mainmenu flags=0 title="IVR Demo Main Menu"> ....... </mainmenu> to parse the "flags=0 " and "title="IVR Demo Main Menu"" */ static BOOL parse_menu_attrs(mxml_node_t *node,ivr_menu_des_t *menu_des) { assert( node != NULL ); const char *tmp = NULL ; tmp = mxmlElementGetAttr(node,TITLE) ; if( strlen_zero(tmp) ) { return False; } menu_des->title_str = tmp ; tmp = mxmlElementGetAttr(node,FLAGS) ; if( strlen_zero(tmp) ) { return False; } menu_des->flags_str = tmp ; return True; } /************************************************************************************** such as : <option option="s" action=AST_ACTION_BACKGROUND str="demo-abouttotry"></option> <option option="s" action=AST_ACTION_WAITOPTION></option> to parse all the attrs */ static BOOL parse_option_attrs(mxml_node_t *node,ast_ivr_option_t *option) { //fprintf(stderr,"The num_attrs is %d n",num_attrs); const char *tmp = NULL; ast_ivr_action flags ; tmp = mxmlElementGetAttr(node,OPTION) ; if( strlen_zero(tmp) ) { return False; } option->option = (char *)tmp ; tmp = mxmlElementGetAttr(node,ACTION) ; if( strlen_zero(tmp) ) { return False; } flags = str_2_action(tmp); //fprintf(stderr,"The flags is %dn",flags); if( flags == -1 ) { return False; } option->action = flags; if( num_attrs == 3 ) //some options have 3 attrs { if( !parse_last_option_attr(node,option) ) { fprintf(stderr,"parse_last_option_attr error!n"); return False; } } return True; } //parse the last option attr static BOOL parse_last_option_attr(mxml_node_t *node,ast_ivr_option_t *option) { const char *tmp = NULL; BOOL found = False ; int i ; int num = sizeof(option_last_attr_vals) / sizeof(option_last_attr_vals[0]); //fprintf(stderr,"The num is %dn",num); for(i=0;i<num;i++) { tmp = mxmlElementGetAttr(node,option_last_attr_vals[i].string) ; if( !strlen_zero(tmp) ) { //fprintf(stderr,"The tmp is %s n",tmp); //fprintf(stderr,"The (option_last_attr_flag)i is %d n",i); switch((option_last_attr_flag)i) { case STR_ATTR: option->adata = (void *)tmp ; found = True; break; case SUBMENU_ATTR: { ast_ivr_menu_t* menu = string_2_menu_pointer(tmp); if( !menu ) { found = False ; } option->adata = (void *)menu; found = True; } break; case ULONG_ATTR: option->adata = (void *)atoi(tmp); found = True; break; case FUN_ATTR: { ivr_demo_func fun = string_2_fun_pointer(tmp); if( !fun ) { found = False ; } option->adata = (void *)fun; found = True; } break; default: found = False ; break; } if( found ) { return True ; } } } return False; } // change string to function pointer static ivr_demo_func string_2_fun_pointer( const char * str) { int i ; int num = sizeof(string_fun_vals) / sizeof(string_fun_vals[0]); //fprintf(stderr,num); for(i=0;i<num;i++) { if( !strcmp(str,string_fun_vals[i].string) ) { return string_fun_vals[i].fun ; } } return (ivr_demo_func)NULL; } //change string to menu pointer static ast_ivr_menu_t* string_2_menu_pointer(const char * str) { int i ; int num = sizeof(string_menu_vals) / sizeof(string_menu_vals[0]); //fprintf(stderr,num); for(i=0;i<num;i++) { if( !strcmp(str,string_menu_vals[i].string) ) { return string_menu_vals[i].menu_ptr ; } } return (ast_ivr_menu_t*)NULL; } //change string to ast_ivr_action static ast_ivr_action str_2_action(const char *str) { int i ; int action_num = sizeof(option_vals) / sizeof(option_vals[0]); //fprintf(stderr,"The action_num is %dn",action_num); for(i=0;i<action_num;i++) { //fprintf(stderr,"The str is %sn",str); //fprintf(stderr,"The option_vals[i].string is %sn",option_vals[i].string); if( !strcmp(str,option_vals[i].string) ) { return (ast_ivr_action)i; } } return -1; } static ast_ivr_option_t *init_ivr_option(int *argc) { ast_ivr_option_t *ivr_option = NULL ; *argc = 0 ; ivr_option = calloc(1,sizeof(ast_ivr_option_t)); if( !ivr_option ) { fprintf(stderr,"No Merrory!n"); return (ast_ivr_option_t *)NULL ; } return ivr_option ; } static ast_ivr_option_t *add_ivr_option(ast_ivr_option_t *option_ptr,ast_ivr_option_t option) { /* Grow the array; "*argc" currently contains the number of string pointers,*not* counting the NULL pointer at the end,so we have to add 1 in order to get the new size of the array,including the new pointer and the terminating NULL pointer. */ option_ptr = realloc( option_ptr,((*argc)+1) * sizeof(ast_ivr_option_t ) ); if( !option_ptr ) { fprintf(stderr,"No Merrory!n"); return (ast_ivr_option_t *)NULL ; } option_ptr[*argc] = option ; (*argc)++ ; //increase the num return option_ptr; } int main( void ) { if( load_xml_file(XML_FILE_PATH,"mainmenu",&ivr_menu) ) { int i ; //ivr_menu_ptr->title = (char *)menu_des.title_str; //ivr_menu_ptr->flags = atoi( menu_des.flags_str ); fprintf(stderr,"The ivr_menu.title is %sn",ivr_menu.title); fprintf(stderr,"The ivr_menu.flags is %dn",ivr_menu.flags); for(i=0;i<10;i++) { //fprintf(stderr,"The ivr_menu.options[%d] is %sn",i,ivr_menu.options[i]); fprintf(stderr,"The ivr_menu.options[%d] :n",i); fprintf(stderr,"tThe option %s n",(char *)ivr_menu.options[i].option); fprintf(stderr,"tThe action %d n",(ast_ivr_action)ivr_menu.options[i].action); //fprintf(stderr,"tThe adata %s n",(char *)ivr_menu.options[i].adata); } } if( load_xml_file(XML_FILE_PATH,"submenu1",&ivr_submenu) ) { int i ; //ivr_menu_ptr->title = (char *)menu_des.title_str; //ivr_menu_ptr->flags = atoi( menu_des.flags_str ); fprintf(stderr,ivr_submenu.title); fprintf(stderr,ivr_submenu.flags); for(i=0;i<8;i++) { //fprintf(stderr,(char *)ivr_submenu.options[i].option); fprintf(stderr,(ast_ivr_action)ivr_submenu.options[i].action); //fprintf(stderr,(char *)ivr_menu.options[i].adata); } } return 0 ; }
*********************************************************** Makefile
CC = gcc -Wall -O2
***********************************************************************' menu.xml
<?xml version="1.0"?> <menu> <mainmenu flags=0 title="IVR Demo Main Menu"> <option option="s" action=AST_ACTION_BACKGROUND str="demo-congrats"></option> <option option="g" action=AST_ACTION_BACKGROUND str="demo-instruct"></option> <option option="g" action=AST_ACTION_WAITOPTION></option> <option option="1" action=AST_ACTION_PLAYBACK str="digits/1"></option> <option option="1" action=AST_ACTION_RESTART></option> <option option="2" action=AST_ACTION_MENU submenu="ivr_submenu"></option> <option option="2" action=AST_ACTION_RESTART></option> <option option="i" action=AST_ACTION_PLAYBACK str="invalid"></option> <option option="i" action=AST_ACTION_REPEAT ulong=2></option> <option option="#" action=AST_ACTION_EXIT></option> </mainmenu> <submenu1 flags=0 title="IVR Demo Sub Menu1"> <option option="s" action=AST_ACTION_BACKGROUND str="demo-abouttotry"></option> <option option="s" action=AST_ACTION_WAITOPTION></option> <option option="1" action=AST_ACTION_PLAYBACK str="digits/1"></option> <option option="1" action=AST_ACTION_RESTART></option> <option option="2" action=AST_ACTION_PLAYLIST str="digits/2;digits/3"></option> <option option="3" action=AST_ACTION_CALLBACK fun="ivr_demo_func"></option> <option option="*" action=AST_ACTION_REPEAT></option> <option option="#" action=AST_ACTION_UPONE></option> </submenu1> </menu> (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |