From 426360e3897a4bd682c71e10ea0415071411735a Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" <kpfleming@digium.com> Date: Thu, 3 Nov 2005 21:19:11 +0000 Subject: [PATCH] major update to arg/option parsing APIs and documentation git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@6953 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- ChangeLog | 5 ++ app.c | 23 ++++--- apps/app_chanspy.c | 39 +++++++----- apps/app_controlplayback.c | 2 +- apps/app_cut.c | 2 +- apps/app_dial.c | 52 ++++++++-------- apps/app_dictate.c | 2 +- apps/app_meetme.c | 46 +++++++------- apps/app_mixmonitor.c | 51 +++++++++------- apps/app_page.c | 16 ++--- apps/app_read.c | 2 +- apps/app_voicemail.c | 42 +++++++------ channels/chan_agent.c | 2 +- funcs/func_cdr.c | 4 +- funcs/func_db.c | 6 +- funcs/func_math.c | 2 +- funcs/func_md5.c | 2 +- include/asterisk/app.h | 120 ++++++++++++++++++++++++++++++++----- pbx.c | 35 +++++------ 19 files changed, 283 insertions(+), 170 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6a4915ced0..c58b18cc69 100755 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2005-11-03 Kevin P. Fleming <kpfleming@digium.com> + + * include/asterisk/app.h: re-work application arg/option parsing APIs for consistent naming, add doxygen docs for option API + * many files: update to new APIs + 2005-11-02 Kevin P. Fleming <kpfleming@digium.com> * apps/app_dial.c (dial_exec_full): convert to use API calls for argument/option parsing diff --git a/app.c b/app.c index 0a72bec427..b76387825d 100755 --- a/app.c +++ b/app.c @@ -1105,7 +1105,7 @@ int ast_app_group_match_get_count(char *groupmatch, char *category) return count; } -int ast_separate_app_args(char *buf, char delim, char **array, int arraylen) +unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen) { int argc; char *scan; @@ -1523,41 +1523,40 @@ char *ast_read_textfile(const char *filename) return output; } -int ast_parseoptions(const struct ast_option *options, struct ast_flags *flags, char **args, char *optstr) +int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr) { char *s; int curarg; - int argloc; + unsigned int argloc; char *arg; int res = 0; - flags->flags = 0; + ast_clear_flag(flags, AST_FLAGS_ALL); if (!optstr) return 0; s = optstr; while (*s) { - curarg = *s & 0x7f; - flags->flags |= options[curarg].flag; + curarg = *s++ & 0x7f; + ast_set_flag(flags, options[curarg].flag); argloc = options[curarg].arg_index; - s++; if (*s == '(') { /* Has argument */ - s++; arg = s; - while (*s && (*s != ')')) s++; + while (*++s && (*s != ')')); if (*s) { if (argloc) args[argloc - 1] = arg; - *s = '\0'; - s++; + *s++ = '\0'; } else { ast_log(LOG_WARNING, "Missing closing parenthesis for argument '%c' in string '%s'\n", curarg, arg); res = -1; } - } else if (argloc) + } else if (argloc) { args[argloc - 1] = NULL; + } } + return res; } diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c index d9138ed00f..116441cb91 100755 --- a/apps/app_chanspy.c +++ b/apps/app_chanspy.c @@ -69,18 +69,27 @@ static const char *desc = " Chanspy([<scanspec>][|<options>])\n\n" static const char *chanspy_spy_type = "ChanSpy"; -#define OPTION_QUIET (1 << 0) /* Quiet, no announcement */ -#define OPTION_BRIDGED (1 << 1) /* Only look at bridged calls */ -#define OPTION_VOLUME (1 << 2) /* Specify initial volume */ -#define OPTION_GROUP (1 << 3) /* Only look at channels in group */ -#define OPTION_RECORD (1 << 4) /* Record */ - -AST_DECLARE_OPTIONS(chanspy_opts,{ - ['q'] = { OPTION_QUIET }, - ['b'] = { OPTION_BRIDGED }, - ['v'] = { OPTION_VOLUME, 1 }, - ['g'] = { OPTION_GROUP, 2 }, - ['r'] = { OPTION_RECORD, 3 }, +enum { + OPTION_QUIET = (1 << 0), /* Quiet, no announcement */ + OPTION_BRIDGED = (1 << 1), /* Only look at bridged calls */ + OPTION_VOLUME = (1 << 2), /* Specify initial volume */ + OPTION_GROUP = (1 << 3), /* Only look at channels in group */ + OPTION_RECORD = (1 << 4), /* Record */ +} chanspy_opt_flags; + +enum { + OPT_ARG_VOLUME = 0, + OPT_ARG_GROUP, + OPT_ARG_RECORD, + OPT_ARG_ARRAY_SIZE, +} chanspy_opt_args; + +AST_APP_OPTIONS(chanspy_opts, { + AST_APP_OPTION('q', OPTION_QUIET), + AST_APP_OPTION('b', OPTION_BRIDGED), + AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME), + AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP), + AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD), }); STANDARD_LOCAL_USER; @@ -384,7 +393,7 @@ static int chanspy_exec(struct ast_channel *chan, void *data) ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ - if ((argc = ast_separate_app_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) { + if ((argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) { spec = argv[0]; if ( argc > 1) { options = argv[1]; @@ -395,8 +404,8 @@ static int chanspy_exec(struct ast_channel *chan, void *data) } if (options) { - char *opts[3]; - ast_parseoptions(chanspy_opts, &flags, opts, options); + char *opts[OPT_ARG_ARRAY_SIZE]; + ast_app_parse_options(chanspy_opts, &flags, opts, options); if (ast_test_flag(&flags, OPTION_GROUP)) { mygroup = opts[1]; } diff --git a/apps/app_controlplayback.c b/apps/app_controlplayback.c index 21320ac9da..0c56c926f5 100755 --- a/apps/app_controlplayback.c +++ b/apps/app_controlplayback.c @@ -91,7 +91,7 @@ static int controlplayback_exec(struct ast_channel *chan, void *data) tmp = ast_strdupa(data); memset(argv, 0, sizeof(argv)); - argc = ast_separate_app_args(tmp, '|', argv, sizeof(argv) / sizeof(argv[0])); + argc = ast_app_separate_args(tmp, '|', argv, sizeof(argv) / sizeof(argv[0])); if (argc < 1) { ast_log(LOG_WARNING, "ControlPlayback requires an argument (filename)\n"); diff --git a/apps/app_cut.c b/apps/app_cut.c index 95b5b1ded1..ab41d34379 100755 --- a/apps/app_cut.c +++ b/apps/app_cut.c @@ -160,7 +160,7 @@ static int cut_internal(struct ast_channel *chan, char *data, char *buffer, size if (data) { s = ast_strdupa((char *)data); if (s) { - ast_separate_app_args(s, '|', args, 3); + ast_app_separate_args(s, '|', args, 3); varname = args[0]; delimiter = args[1]; field = args[2]; diff --git a/apps/app_dial.c b/apps/app_dial.c index 50b2761c00..bfaefba1e7 100755 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -670,31 +670,31 @@ enum { OPT_ARG_ARRAY_SIZE, } dial_exec_option_args; -AST_DECLARE_OPTIONS(dial_exec_options, { - ['A'] = { .flag = OPT_ANNOUNCE, .arg_index = OPT_ARG_ANNOUNCE + 1, }, - ['C'] = { .flag = OPT_RESETCDR, }, - ['d'] = { .flag = OPT_DTMF_EXIT, }, - ['D'] = { .flag = OPT_SENDDTMF, .arg_index = OPT_ARG_SENDDTMF + 1, }, - ['f'] = { .flag = OPT_FORCECLID, }, - ['g'] = { .flag = OPT_GO_ON, }, - ['G'] = { .flag = OPT_GOTO, .arg_index = OPT_ARG_GOTO + 1, }, - ['h'] = { .flag = OPT_CALLEE_HANGUP, }, - ['H'] = { .flag = OPT_CALLER_HANGUP, }, - ['j'] = { .flag = OPT_PRIORITY_JUMP, }, - ['L'] = { .flag = OPT_DURATION_LIMIT, .arg_index = OPT_ARG_DURATION_LIMIT + 1, }, - ['m'] = { .flag = OPT_MUSICBACK, .arg_index = OPT_ARG_MUSICBACK + 1, }, - ['M'] = { .flag = OPT_CALLEE_MACRO, .arg_index = OPT_ARG_CALLEE_MACRO + 1, }, - ['n'] = { .flag = OPT_SCREEN_NOINTRO, }, - ['N'] = { .flag = OPT_SCREEN_NOCLID, }, - ['o'] = { .flag = OPT_ORIGINAL_CLID, }, - ['p'] = { .flag = OPT_SCREENING, }, - ['P'] = { .flag = OPT_PRIVACY, .arg_index = OPT_ARG_PRIVACY + 1, }, - ['r'] = { .flag = OPT_RINGBACK, }, - ['S'] = { .flag = OPT_DURATION_STOP, .arg_index = OPT_ARG_DURATION_STOP + 1, }, - ['t'] = { .flag = OPT_CALLEE_TRANSFER, }, - ['T'] = { .flag = OPT_CALLER_TRANSFER, }, - ['w'] = { .flag = OPT_CALLEE_MONITOR, }, - ['W'] = { .flag = OPT_CALLER_MONITOR, }, +AST_APP_OPTIONS(dial_exec_options, { + AST_APP_OPTION_ARG('A', OPT_ANNOUNCE, OPT_ARG_ANNOUNCE), + AST_APP_OPTION('C', OPT_RESETCDR), + AST_APP_OPTION('d', OPT_DTMF_EXIT), + AST_APP_OPTION_ARG('D', OPT_SENDDTMF, OPT_ARG_SENDDTMF), + AST_APP_OPTION('f', OPT_FORCECLID), + AST_APP_OPTION('g', OPT_GO_ON), + AST_APP_OPTION_ARG('G', OPT_GOTO, OPT_ARG_GOTO), + AST_APP_OPTION('h', OPT_CALLEE_HANGUP), + AST_APP_OPTION('H', OPT_CALLER_HANGUP), + AST_APP_OPTION('j', OPT_PRIORITY_JUMP), + AST_APP_OPTION_ARG('L', OPT_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT), + AST_APP_OPTION_ARG('m', OPT_MUSICBACK, OPT_ARG_MUSICBACK), + AST_APP_OPTION_ARG('M', OPT_CALLEE_MACRO, OPT_ARG_CALLEE_MACRO), + AST_APP_OPTION('n', OPT_SCREEN_NOINTRO), + AST_APP_OPTION('N', OPT_SCREEN_NOCLID), + AST_APP_OPTION('o', OPT_ORIGINAL_CLID), + AST_APP_OPTION('p', OPT_SCREENING), + AST_APP_OPTION_ARG('P', OPT_PRIVACY, OPT_ARG_PRIVACY), + AST_APP_OPTION('r', OPT_RINGBACK), + AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP), + AST_APP_OPTION('t', OPT_CALLEE_TRANSFER), + AST_APP_OPTION('T', OPT_CALLER_TRANSFER), + AST_APP_OPTION('w', OPT_CALLEE_MONITOR), + AST_APP_OPTION('W', OPT_CALLER_MONITOR), }); static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags *peerflags) @@ -762,7 +762,7 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags AST_STANDARD_APP_ARGS(args, parse); if (!ast_strlen_zero(args.options)) { - if (ast_parseoptions(dial_exec_options, &opts, opt_args, args.options)) { + if (ast_app_parse_options(dial_exec_options, &opts, opt_args, args.options)) { LOCAL_USER_REMOVE(u); return -1; } diff --git a/apps/app_dictate.c b/apps/app_dictate.c index 0df5a56041..71c7fb8637 100755 --- a/apps/app_dictate.c +++ b/apps/app_dictate.c @@ -102,7 +102,7 @@ static int dictate_exec(struct ast_channel *chan, void *data) snprintf(dftbase, sizeof(dftbase), "%s/dictate", ast_config_AST_SPOOL_DIR); if (!ast_strlen_zero(data) && (mydata = ast_strdupa(data))) { - argc = ast_separate_app_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0])); + argc = ast_app_separate_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0])); } if (argc) { diff --git a/apps/app_meetme.c b/apps/app_meetme.c index 88e5b76ffd..742b6ec68a 100755 --- a/apps/app_meetme.c +++ b/apps/app_meetme.c @@ -219,28 +219,28 @@ static void *recordthread(void *args); #define CONFFLAG_ANNOUNCEUSERCOUNT (1 << 22) /* If set, when user joins the conference, they will be told the number of users that are already in */ -AST_DECLARE_OPTIONS(meetme_opts,{ - ['a'] = { CONFFLAG_ADMIN }, - ['c'] = { CONFFLAG_ANNOUNCEUSERCOUNT }, - ['T'] = { CONFFLAG_MONITORTALKER }, - ['i'] = { CONFFLAG_INTROUSER }, - ['m'] = { CONFFLAG_MONITOR }, - ['p'] = { CONFFLAG_POUNDEXIT }, - ['s'] = { CONFFLAG_STARMENU }, - ['t'] = { CONFFLAG_TALKER }, - ['q'] = { CONFFLAG_QUIET }, - ['M'] = { CONFFLAG_MOH }, - ['x'] = { CONFFLAG_MARKEDEXIT }, - ['X'] = { CONFFLAG_EXIT_CONTEXT }, - ['A'] = { CONFFLAG_MARKEDUSER }, - ['b'] = { CONFFLAG_AGI }, - ['w'] = { CONFFLAG_WAITMARKED }, - ['r'] = { CONFFLAG_RECORDCONF }, - ['d'] = { CONFFLAG_DYNAMIC }, - ['D'] = { CONFFLAG_DYNAMICPIN }, - ['e'] = { CONFFLAG_EMPTY }, - ['E'] = { CONFFLAG_EMPTYNOPIN }, - ['P'] = { CONFFLAG_ALWAYSPROMPT }, +AST_APP_OPTIONS(meetme_opts, { + AST_APP_OPTION('a', CONFFLAG_ADMIN ), + AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT ), + AST_APP_OPTION('T', CONFFLAG_MONITORTALKER ), + AST_APP_OPTION('i', CONFFLAG_INTROUSER ), + AST_APP_OPTION('m', CONFFLAG_MONITOR ), + AST_APP_OPTION('p', CONFFLAG_POUNDEXIT ), + AST_APP_OPTION('s', CONFFLAG_STARMENU ), + AST_APP_OPTION('t', CONFFLAG_TALKER ), + AST_APP_OPTION('q', CONFFLAG_QUIET ), + AST_APP_OPTION('M', CONFFLAG_MOH ), + AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT ), + AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT ), + AST_APP_OPTION('A', CONFFLAG_MARKEDUSER ), + AST_APP_OPTION('b', CONFFLAG_AGI ), + AST_APP_OPTION('w', CONFFLAG_WAITMARKED ), + AST_APP_OPTION('r', CONFFLAG_RECORDCONF ), + AST_APP_OPTION('d', CONFFLAG_DYNAMIC ), + AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN ), + AST_APP_OPTION('e', CONFFLAG_EMPTY ), + AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN ), + AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT ), }); static char *istalking(int x) @@ -1727,7 +1727,7 @@ static int conf_exec(struct ast_channel *chan, void *data) ast_copy_string(the_pin, inpin, sizeof(the_pin)); if (inflags) { - ast_parseoptions(meetme_opts, &confflags, NULL, inflags); + ast_app_parse_options(meetme_opts, &confflags, NULL, inflags); dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN); if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && !inpin) strcpy(the_pin, "q"); diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c index 554a02c8e2..5ad56e4fd2 100755 --- a/apps/app_mixmonitor.c +++ b/apps/app_mixmonitor.c @@ -85,19 +85,26 @@ struct mixmonitor { }; enum { - MUXFLAG_APPEND = (1 << 1), - MUXFLAG_BRIDGED = (1 << 2), - MUXFLAG_VOLUME = (1 << 3), - MUXFLAG_READVOLUME = (1 << 4), - MUXFLAG_WRITEVOLUME = (1 << 5), + MUXFLAG_APPEND = (1 << 1), + MUXFLAG_BRIDGED = (1 << 2), + MUXFLAG_VOLUME = (1 << 3), + MUXFLAG_READVOLUME = (1 << 4), + MUXFLAG_WRITEVOLUME = (1 << 5), } mixmonitor_flags; -AST_DECLARE_OPTIONS(mixmonitor_opts,{ - ['a'] = { MUXFLAG_APPEND }, - ['b'] = { MUXFLAG_BRIDGED }, - ['v'] = { MUXFLAG_READVOLUME, 1 }, - ['V'] = { MUXFLAG_WRITEVOLUME, 2 }, - ['W'] = { MUXFLAG_VOLUME, 3 }, +enum { + OPT_ARG_READVOLUME = 0, + OPT_ARG_WRITEVOLUME, + OPT_ARG_VOLUME, + OPT_ARG_ARRAY_SIZE, +} mixmonitor_args; + +AST_APP_OPTIONS(mixmonitor_opts, { + AST_APP_OPTION('a', MUXFLAG_APPEND), + AST_APP_OPTION('b', MUXFLAG_BRIDGED), + AST_APP_OPTION_ARG('v', MUXFLAG_READVOLUME, OPT_ARG_READVOLUME), + AST_APP_OPTION_ARG('V', MUXFLAG_WRITEVOLUME, OPT_ARG_WRITEVOLUME), + AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME), }); static void stopmon(struct ast_channel *chan, struct ast_channel_spy *spy) @@ -331,35 +338,35 @@ static int mixmonitor_exec(struct ast_channel *chan, void *data) } if (args.options) { - char *opts[3] = { NULL, }; + char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, }; - ast_parseoptions(mixmonitor_opts, &flags, opts, args.options); + ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options); if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) { - if (ast_strlen_zero(opts[0])) { + if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) { ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n"); - } else if ((sscanf(opts[0], "%d", &x) != 1) || (x < -4) || (x > 4)) { - ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[0]); + } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%d", &x) != 1) || (x < -4) || (x > 4)) { + ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]); } else { readvol = get_volfactor(x); } } if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) { - if (ast_strlen_zero(opts[1])) { + if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) { ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n"); - } else if ((sscanf(opts[1], "%d", &x) != 1) || (x < -4) || (x > 4)) { - ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[1]); + } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%d", &x) != 1) || (x < -4) || (x > 4)) { + ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]); } else { writevol = get_volfactor(x); } } if (ast_test_flag(&flags, MUXFLAG_VOLUME)) { - if (ast_strlen_zero(opts[2])) { + if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) { ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n"); - } else if ((sscanf(opts[2], "%d", &x) != 1) || (x < -4) || (x > 4)) { - ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[2]); + } else if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &x) != 1) || (x < -4) || (x > 4)) { + ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]); } else { readvol = writevol = get_volfactor(x); } diff --git a/apps/app_page.c b/apps/app_page.c index 921316d812..d2a65f4e84 100755 --- a/apps/app_page.c +++ b/apps/app_page.c @@ -61,12 +61,14 @@ STANDARD_LOCAL_USER; LOCAL_USER_DECL; -#define PAGE_DUPLEX (1 << 0) -#define PAGE_QUIET (1 << 1) - -AST_DECLARE_OPTIONS(page_opts,{ - ['d'] = { PAGE_DUPLEX }, - ['q'] = { PAGE_QUIET }, +enum { + PAGE_DUPLEX = (1 << 0), + PAGE_QUIET = (1 << 1), +} page_opt_flags; + +AST_APP_OPTIONS(page_opts, { + AST_APP_OPTION('d', PAGE_DUPLEX), + AST_APP_OPTION('q', PAGE_QUIET), }); struct calloutdata { @@ -142,7 +144,7 @@ static int page_exec(struct ast_channel *chan, void *data) tmp = strsep(&options, "|"); if (options) - ast_parseoptions(page_opts, &flags, NULL, options); + ast_app_parse_options(page_opts, &flags, NULL, options); snprintf(meetmeopts, sizeof(meetmeopts), "%ud|%sqxdw", confid, ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "m"); while ((tech = strsep(&tmp, "&"))) { diff --git a/apps/app_read.c b/apps/app_read.c index 0c4e2872b7..ed4272da6d 100755 --- a/apps/app_read.c +++ b/apps/app_read.c @@ -103,7 +103,7 @@ static int read_exec(struct ast_channel *chan, void *data) return -1; } - if (ast_separate_app_args(argcopy, '|', args, sizeof(args) / sizeof(args[0])) < 1) { + if (ast_app_separate_args(argcopy, '|', args, sizeof(args) / sizeof(args[0])) < 1) { ast_log(LOG_WARNING, "Cannot Parse Arguments.\n"); LOCAL_USER_REMOVE(u); return -1; diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index fab9015901..1ab7dceff6 100755 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -107,21 +107,25 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #define ERROR_LOCK_PATH -100 -#define OPT_SILENT (1 << 0) -#define OPT_BUSY_GREETING (1 << 1) -#define OPT_UNAVAIL_GREETING (1 << 2) -#define OPT_RECORDGAIN (1 << 3) -#define OPT_PREPEND_MAILBOX (1 << 4) - -#define OPT_ARG_RECORDGAIN 0 -#define OPT_ARG_ARRAY_SIZE 1 - -AST_DECLARE_OPTIONS(vm_app_options, { - ['s'] = { .flag = OPT_SILENT }, - ['b'] = { .flag = OPT_BUSY_GREETING }, - ['u'] = { .flag = OPT_UNAVAIL_GREETING }, - ['g'] = { .flag = OPT_RECORDGAIN, .arg_index = OPT_ARG_RECORDGAIN + 1}, - ['p'] = { .flag = OPT_PREPEND_MAILBOX }, +enum { + OPT_SILENT =(1 << 0), + OPT_BUSY_GREETING = (1 << 1), + OPT_UNAVAIL_GREETING = (1 << 2), + OPT_RECORDGAIN = (1 << 3), + OPT_PREPEND_MAILBOX = (1 << 4), +} vm_option_flags; + +enum { + OPT_ARG_RECORDGAIN = 0, + OPT_ARG_ARRAY_SIZE = 1, +} vm_option_args; + +AST_APP_OPTIONS(vm_app_options, { + AST_APP_OPTION('s', OPT_SILENT), + AST_APP_OPTION('b', OPT_BUSY_GREETING), + AST_APP_OPTION('u', OPT_UNAVAIL_GREETING), + AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN), + AST_APP_OPTION('p', OPT_PREPEND_MAILBOX), }); static int load_config(void); @@ -5033,9 +5037,9 @@ static int vm_execmain(struct ast_channel *chan, void *data) char *opts[OPT_ARG_ARRAY_SIZE]; tmp = ast_strdupa(data); - argc = ast_separate_app_args(tmp, '|', argv, sizeof(argv) / sizeof(argv[0])); + argc = ast_app_separate_args(tmp, '|', argv, sizeof(argv) / sizeof(argv[0])); if (argc == 2) { - if (ast_parseoptions(vm_app_options, &flags, opts, argv[1])) { + if (ast_app_parse_options(vm_app_options, &flags, opts, argv[1])) { LOCAL_USER_REMOVE(u); return -1; } @@ -5460,9 +5464,9 @@ static int vm_exec(struct ast_channel *chan, void *data) if (!ast_strlen_zero(data)) { ast_copy_string(tmp, data, sizeof(tmp)); - argc = ast_separate_app_args(tmp, '|', argv, sizeof(argv) / sizeof(argv[0])); + argc = ast_app_separate_args(tmp, '|', argv, sizeof(argv) / sizeof(argv[0])); if (argc == 2) { - if (ast_parseoptions(vm_app_options, &flags, opts, argv[1])) { + if (ast_app_parse_options(vm_app_options, &flags, opts, argv[1])) { LOCAL_USER_REMOVE(u); return -1; } diff --git a/channels/chan_agent.c b/channels/chan_agent.c index 8859afcbd7..812e87be0e 100755 --- a/channels/chan_agent.c +++ b/channels/chan_agent.c @@ -317,7 +317,7 @@ static struct agent_pvt *add_agent(char *agent, int pending) args = ast_strdupa(agent); // Extract username (agt), password and name from agent (args). - if ((argc = ast_separate_app_args(args, ',', argv, sizeof(argv) / sizeof(argv[0])))) { + if ((argc = ast_app_separate_args(args, ',', argv, sizeof(argv) / sizeof(argv[0])))) { agt = argv[0]; if (argc > 1) { password = argv[1]; diff --git a/funcs/func_cdr.c b/funcs/func_cdr.c index 1612d54eba..66bef45510 100755 --- a/funcs/func_cdr.c +++ b/funcs/func_cdr.c @@ -52,7 +52,7 @@ static char *builtin_function_cdr_read(struct ast_channel *chan, char *cmd, char return NULL; mydata = ast_strdupa(data); - argc = ast_separate_app_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0])); + argc = ast_app_separate_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0])); /* check for a trailing flags argument */ if (argc > 1) { @@ -77,7 +77,7 @@ static void builtin_function_cdr_write(struct ast_channel *chan, char *cmd, char return; mydata = ast_strdupa(data); - argc = ast_separate_app_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0])); + argc = ast_app_separate_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0])); /* check for a trailing flags argument */ if (argc > 1) { diff --git a/funcs/func_db.c b/funcs/func_db.c index 728bdb2188..a01af59c12 100755 --- a/funcs/func_db.c +++ b/funcs/func_db.c @@ -55,7 +55,7 @@ static char *function_db_read(struct ast_channel *chan, char *cmd, char *data, c } args = ast_strdupa(data); - argc = ast_separate_app_args(args, '/', argv, sizeof(argv) / sizeof(argv[0])); + argc = ast_app_separate_args(args, '/', argv, sizeof(argv) / sizeof(argv[0])); if (argc > 1) { family = argv[0]; @@ -88,7 +88,7 @@ static void function_db_write(struct ast_channel *chan, char *cmd, char *data, c } args = ast_strdupa(data); - argc = ast_separate_app_args(args, '/', argv, sizeof(argv) / sizeof(argv[0])); + argc = ast_app_separate_args(args, '/', argv, sizeof(argv) / sizeof(argv[0])); if (argc > 1) { family = argv[0]; @@ -134,7 +134,7 @@ static char *function_db_exists(struct ast_channel *chan, char *cmd, char *data, } args = ast_strdupa(data); - argc = ast_separate_app_args(args, '/', argv, sizeof(argv) / sizeof(argv[0])); + argc = ast_app_separate_args(args, '/', argv, sizeof(argv) / sizeof(argv[0])); if (argc > 1) { family = argv[0]; diff --git a/funcs/func_math.c b/funcs/func_math.c index 876fb22111..46085275d5 100755 --- a/funcs/func_math.c +++ b/funcs/func_math.c @@ -84,7 +84,7 @@ static char *builtin_function_math(struct ast_channel *chan, char *cmd, char *da } args = ast_strdupa(data); - argc = ast_separate_app_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])); + argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])); if (argc < 1) { ast_log(LOG_WARNING, "Syntax: Math(<number1><op><number 2>[,<type_of_result>]) - missing argument!\n"); diff --git a/funcs/func_md5.c b/funcs/func_md5.c index f320d07496..fed75722c3 100755 --- a/funcs/func_md5.c +++ b/funcs/func_md5.c @@ -64,7 +64,7 @@ static char *builtin_function_checkmd5(struct ast_channel *chan, char *cmd, char } args = ast_strdupa(data); - argc = ast_separate_app_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])); + argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])); if (argc < 2) { ast_log(LOG_WARNING, "Syntax: CHECK_MD5(<digest>,<data>) - missing argument!\n"); diff --git a/include/asterisk/app.h b/include/asterisk/app.h index 5f64f33916..7cc02163c5 100755 --- a/include/asterisk/app.h +++ b/include/asterisk/app.h @@ -73,17 +73,7 @@ struct ast_ivr_menu { #define AST_IVR_FLAG_AUTORESTART (1 << 0) -struct ast_option { - unsigned int flag; - int arg_index; -}; - -extern int ast_parseoptions(const struct ast_option *options, struct ast_flags *flags, char **args, char *optstr); - -#define AST_DECLARE_OPTIONS(holder,args...) \ - static struct ast_option holder[128] = args - -#define AST_IVR_DECLARE_MENU(holder,title,flags,foo...) \ +#define AST_IVR_DECLARE_MENU(holder, title, flags, foo...) \ static struct ast_ivr_option __options_##holder[] = foo;\ static struct ast_ivr_menu holder = { title, flags, __options_##holder } @@ -204,7 +194,7 @@ int ast_app_group_match_get_count(char *groupmatch, char *category); */ #define AST_DECLARE_APP_ARGS(name, arglist) \ struct { \ - int argc; \ + unsigned int argc; \ char *argv[0]; \ arglist \ } name; @@ -219,7 +209,7 @@ int ast_app_group_match_get_count(char *groupmatch, char *category); the argc argument counter field. */ #define AST_STANDARD_APP_ARGS(args, parse) \ - args.argc = ast_separate_app_args(parse, '|', args.argv, (sizeof(args) - sizeof(args.argc)) / sizeof(args.argv[0])) + args.argc = ast_app_separate_args(parse, '|', args.argv, (sizeof(args) - sizeof(args.argc)) / sizeof(args.argv[0])) /*! \brief Separate a string into arguments in an array @@ -235,7 +225,109 @@ int ast_app_group_match_get_count(char *groupmatch, char *category); \return The number of arguments found, or zero if the function arguments are not valid. */ -int ast_separate_app_args(char *buf, char delim, char **array, int arraylen); +unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen); + +/*! + \brief A structure to hold the description of an application 'option'. + + Application 'options' are single-character flags that can be supplied + to the application to affect its behavior; they can also optionally + accept arguments enclosed in parenthesis. + + These structures are used by the ast_app_parse_options function, uses + this data to fill in a flags structure (to indicate which options were + supplied) and array of argument pointers (for those options that had + arguments supplied). + */ +struct ast_app_option { + /*! \brief The flag bit that represents this option. */ + unsigned int flag; + /*! \brief The index of the entry in the arguments array + that should be used for this option's argument. */ + unsigned int arg_index; +}; + +/*! + \brief Declares an array of options for an application. + \param holder The name of the array to be created + \param options The actual options to be placed into the array + \sa ast_app_parse_options + + This macro declares a 'static const' array of \c struct \c ast_option + elements to hold the list of available options for an application. + Each option must be declared using either the AST_APP_OPTION() + or AST_APP_OPTION_ARG() macros. + + Example usage: + \code + enum { + OPT_JUMP = (1 << 0), + OPT_BLAH = (1 << 1), + OPT_BLORT = (1 << 2), + } my_app_option_flags; + + enum { + OPT_ARG_BLAH = 0, + OPT_ARG_BLORT, + !! this entry tells how many possible arguments there are, + and must be the last entry in the list + OPT_ARG_ARRAY_SIZE, + } my_app_option_args; + + AST_APP_OPTIONS(my_app_options, { + AST_APP_OPTION('j', OPT_JUMP), + AST_APP_OPTION_ARG('b', OPT_BLAH, OPT_ARG_BLAH), + AST_APP_OPTION_BLORT('B', OPT_BLORT, OPT_ARG_BLORT), + }); + + static int my_app_exec(struct ast_channel *chan, void *data) + { + char *options; + struct ast_flags opts = { 0, }; + char *opt_args[OPT_ARG_ARRAY_SIZE]; + + ... do any argument parsing here ... + + if (ast_parseoptions(my_app_options, &opts, opt_args, options)) { + LOCAL_USER_REMOVE(u); + return -1; + } + } + \endcode + */ +#define AST_APP_OPTIONS(holder, options...) \ + static const struct ast_app_option holder[128] = options + +/*! + \brief Declares an application option that does not accept an argument. + \param option The single character representing the option + \param flagno The flag index to be set if this option is present + \sa AST_APP_OPTIONS, ast_app_parse_options + */ +#define AST_APP_OPTION(option, flagno) \ + [option] = { .flag = flagno } + +/*! + \brief Declares an application option that accepts an argument. + \param option The single character representing the option + \param flagno The flag index to be set if this option is present + \param argno The index into the argument array where the argument should + be placed + \sa AST_APP_OPTIONS, ast_app_parse_options + */ +#define AST_APP_OPTION_ARG(option, flagno, argno) \ + [option] = { .flag = flagno, .arg_index = argno } + +/*! + \brief Parses a string containing application options and sets flags/arguments. + \param options The array of possible options declared with AST_APP_OPTIONS + \param flags The flag structure to have option flags set + \param args The array of argument pointers to hold arguments found + \param optstr The string containing the options to be parsed + \return zero for success, non-zero if an error occurs + \sa AST_APP_OPTIONS + */ +int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr); /*! Present a dialtone and collect a certain length extension. Returns 1 on valid extension entered, -1 on hangup, or 0 on invalid extension. Note that if 'collect' holds digits already, new digits will be appended, so be sure it's initialized properly */ int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect, size_t size, int maxlen, int timeout); diff --git a/pbx.c b/pbx.c index c5459886f6..0d721e1368 100755 --- a/pbx.c +++ b/pbx.c @@ -86,17 +86,17 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #define BACKGROUND_MATCHEXTEN (1 << 2) #define BACKGROUND_PLAYBACK (1 << 3) -AST_DECLARE_OPTIONS(background_opts,{ - ['s'] = { BACKGROUND_SKIP }, - ['n'] = { BACKGROUND_NOANSWER }, - ['m'] = { BACKGROUND_MATCHEXTEN }, - ['p'] = { BACKGROUND_PLAYBACK }, +AST_APP_OPTIONS(background_opts, { + AST_APP_OPTION('s', BACKGROUND_SKIP), + AST_APP_OPTION('n', BACKGROUND_NOANSWER), + AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN), + AST_APP_OPTION('p', BACKGROUND_PLAYBACK), }); #define WAITEXTEN_MOH (1 << 0) -AST_DECLARE_OPTIONS(waitexten_opts,{ - ['m'] = { WAITEXTEN_MOH, 1 }, +AST_APP_OPTIONS(waitexten_opts, { + AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 1), }); struct ast_context; @@ -5616,13 +5616,13 @@ static int pbx_builtin_waitexten(struct ast_channel *chan, void *data) char *args; char *argv[2]; char *options = NULL; - char *mohclass = NULL; char *timeout = NULL; struct ast_flags flags = {0}; + char *opts[1] = { NULL }; args = ast_strdupa(data); - if ((argc = ast_separate_app_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) { + if ((argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) { if (argc > 0) { timeout = argv[0]; if (argc > 1) @@ -5630,16 +5630,11 @@ static int pbx_builtin_waitexten(struct ast_channel *chan, void *data) } } - if (options) { - char *opts[1]; - ast_parseoptions(waitexten_opts, &flags, opts, options); - if (ast_test_flag(&flags, WAITEXTEN_MOH)) { - mohclass = opts[0]; - } - } + if (options) + ast_app_parse_options(waitexten_opts, &flags, opts, options); if (ast_test_flag(&flags, WAITEXTEN_MOH)) - ast_moh_start(chan, mohclass); + ast_moh_start(chan, opts[0]); /* Wait for "n" seconds */ if (timeout && atof((char *)timeout)) @@ -5685,7 +5680,7 @@ static int pbx_builtin_background(struct ast_channel *chan, void *data) parse = ast_strdupa(data); - if ((argc = ast_separate_app_args(parse, '|', argv, sizeof(argv) / sizeof(argv[0])))) { + if ((argc = ast_app_separate_args(parse, '|', argv, sizeof(argv) / sizeof(argv[0])))) { switch (argc) { case 4: context = argv[3]; @@ -5714,7 +5709,7 @@ static int pbx_builtin_background(struct ast_channel *chan, void *data) else if (!strcasecmp(options, "noanswer")) flags.flags = BACKGROUND_NOANSWER; else - ast_parseoptions(background_opts, &flags, NULL, options); + ast_app_parse_options(background_opts, &flags, NULL, options); } /* Answer if need be */ @@ -5948,7 +5943,7 @@ int pbx_builtin_setvar(struct ast_channel *chan, void *data) } mydata = ast_strdupa(data); - argc = ast_separate_app_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0])); + argc = ast_app_separate_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0])); /* check for a trailing flags argument */ if ((argc > 1) && !strchr(argv[argc-1], '=')) { -- GitLab