Mercurial > masqmail
changeset 249:f9da5a7caeda
refactored the cmdline argument processing
I replaced the nested switch statements with one single
large else-if construct. Instead of char comparision now
str(n)cmp(3) is used. Although this is slower it is much
more readable and covers corner-cases which were uncovered
before (e.g. -bdxxx).
As always: Readability and simplicity matter, not performance.
author | markus schnalke <meillo@marmaro.de> |
---|---|
date | Thu, 04 Nov 2010 11:02:42 -0300 |
parents | 018cfd163f5c |
children | a41c013c8458 |
files | src/masqmail.c |
diffstat | 1 files changed, 131 insertions(+), 166 deletions(-) [+] |
line wrap: on
line diff
--- a/src/masqmail.c Mon Nov 01 14:53:26 2010 -0300 +++ b/src/masqmail.c Thu Nov 04 11:02:42 2010 -0300 @@ -91,19 +91,25 @@ } #endif +/* +argv: the original argv +argp: number of arg (may get modified!) +cp: pointing to the char after the option + e.g. `-d 6' `-d6' + ^ ^ +*/ gchar* -get_optarg(char *argv[], gint argc, gint * argp, gint * pos) +get_optarg(char* argv[], gint* argp, char* cp) { - if (argv[*argp][*pos]) - return &(argv[*argp][*pos]); - else { - if (*argp + 1 < argc) { - if (argv[(*argp) + 1][0] != '-') { - (*argp)++; - *pos = 0; - return &(argv[*argp][*pos]); - } - } + if (*cp) { + /* this kind: -xval */ + return cp; + } + cp = argv[*argp+1]; + if (cp && (*cp != '-')) { + /* this kind: -x val */ + (*argp)++; + return cp; } return NULL; } @@ -288,7 +294,8 @@ { /* cmd line flags */ gchar *conf_file = CONF_FILE; - gint arg = 1; + char* opt; + gint arg; gboolean do_listen = FALSE; gboolean do_runq = FALSE; @@ -336,166 +343,124 @@ } /* parse cmd line */ - while (arg < argc) { - gint pos = 0; - if ((argv[arg][pos] == '-') && (argv[arg][pos + 1] != '-')) { - pos++; - switch (argv[arg][pos++]) { - case 'b': - switch (argv[arg][pos++]) { - case 'd': - do_listen = TRUE; - mta_mode = MODE_DAEMON; - break; - case 'i': - /* ignored */ - mta_mode = MODE_BI; - break; - case 's': - mta_mode = MODE_SMTP; - break; - case 'p': - mta_mode = MODE_LIST; - break; - case 'V': - mta_mode = MODE_VERSION; - break; - default: - fprintf(stderr, "unrecognized option '%s'\n", argv[arg]); - exit(EXIT_FAILURE); - } - break; - case 'B': - /* we ignore this and throw the argument away */ - get_optarg(argv, argc, &arg, &pos); - break; - case 'C': - if (!(conf_file = get_optarg(argv, argc, &arg, &pos))) { - fprintf(stderr, "-C requires a filename as argument.\n"); - exit(EXIT_FAILURE); - } - break; - case 'F': - { - full_sender_name = get_optarg(argv, argc, &arg, &pos); - if (!full_sender_name) { - fprintf(stderr, "-F requires a name as an argument\n"); - exit(EXIT_FAILURE); - } - } - break; - case 'd': - if (getuid() == 0) { - char *lvl = get_optarg(argv, argc, &arg, &pos); - if (lvl) - debug_level = atoi(lvl); - else { - fprintf(stderr, "-d requires a number as an argument.\n"); - exit(EXIT_FAILURE); - } - } else { - fprintf(stderr, "only root may set the debug level.\n"); - exit(EXIT_FAILURE); - } - break; - case 'f': - /* set return path */ - { - gchar *address; - address = get_optarg(argv, argc, &arg, &pos); - if (address) { - f_address = g_strdup(address); - } else { - fprintf(stderr, "-f requires an address as an argument\n"); - exit(EXIT_FAILURE); - } - } - break; - case 'i': - if (argv[arg][pos] == 0) { - opt_i = TRUE; - exit_failure = FALSE; /* may override -oem */ - } else { - fprintf(stderr, "unrecognized option '%s'\n", argv[arg]); - exit(EXIT_FAILURE); - } - break; - case 'M': - { - mta_mode = MODE_MCMD; - M_cmd = g_strdup(&(argv[arg][pos])); - } - break; - case 'm': - /* ignore -m (me too) switch (see man page) */ - break; - case 'o': - char* oarg = argv[arg][pos+1]; - if (strcmp(oarg, "oem") == 0) { - if (!opt_i) { - /* FIXME: this check needs to be done after - option processing as -oi may come later */ - exit_failure = TRUE; - } - } else if (strcmp(oarg, "odb") == 0) { - /* ignore ``deliver in background'' switch */ - } else if (strcmp(oarg, "odq") == 0) { - do_queue = TRUE; - } else if (strcmp(oarg, "oi") == 0) { - exit_failure = FALSE; /* may override -oem */ - } else if (strcmp(oarg, "om") == 0) { - /* ignore ``me too'' switch */ - } else { - fprintf(stderr, "ignoring unrecognized option %s\n", - argv[arg]); - } - break; + for (arg=1; arg<argc && argv[arg][0]=='-'; arg++) { + opt = argv[arg] + 1; + + if (strcmp(opt, "-") == 0) { + /* everything after `--' are address arguments */ + arg++; + break; + + } else if (strcmp(opt, "bd") == 0) { + do_listen = TRUE; + mta_mode = MODE_DAEMON; + + } else if (strcmp(opt, "bi") == 0) { + /* ignored */ + mta_mode = MODE_BI; + + } else if (strcmp(opt, "bs") == 0) { + mta_mode = MODE_SMTP; + + } else if (strcmp(opt, "bp") == 0) { + mta_mode = MODE_LIST; + + } else if (strcmp(opt, "bV") == 0) { + mta_mode = MODE_VERSION; - case 'q': - { - gchar *optarg; + } else if (strncmp(opt, "B", 1) == 0) { + /* we ignore this and throw the argument away */ + get_optarg(argv, &arg, opt+1); + + } else if (strncmp(opt, "C", 1) == 0) { + if (!(conf_file = get_optarg(argv, &arg, opt+1))) { + fprintf(stderr, "-C requires a filename as argument.\n"); + exit(EXIT_FAILURE); + } - do_runq = TRUE; - mta_mode = MODE_RUNQUEUE; - if (argv[arg][pos] == 'o') { - pos++; - do_runq = FALSE; - do_runq_online = TRUE; - /* can be NULL, then we use online detection method */ - route_name = get_optarg(argv, argc, &arg, &pos); - } else - if ((optarg = get_optarg(argv, argc, &arg, &pos))) { - mta_mode = MODE_DAEMON; - queue_interval = time_interval(optarg, &pos); - } - } - break; - case 't': - if (argv[arg][pos] == '\0') { - opt_t = TRUE; - } else { - fprintf(stderr, "unrecognized option '%s'\n", argv[arg]); - exit(EXIT_FAILURE); - } - break; - case 'v': - do_verbose = TRUE; - break; - default: - fprintf(stderr, "unrecognized option '%s'\n", argv[arg]); + } else if (strncmp(opt, "d", 1) == 0) { + if (getuid() != 0) { + fprintf(stderr, "only root may set the debug level.\n"); + exit(EXIT_FAILURE); + } + char *lvl = get_optarg(argv, &arg, opt+1); + if (!lvl) { + fprintf(stderr, "-d requires a number argument.\n"); + exit(EXIT_FAILURE); + } + debug_level = atoi(lvl); + + } else if (strncmp(opt, "f", 1) == 0) { + /* set return path */ + gchar *address = get_optarg(argv, &arg, opt+1); + if (!address) { + fprintf(stderr, "-f requires an address argument\n"); exit(EXIT_FAILURE); } + f_address = g_strdup(address); + + } else if (strncmp(opt, "F", 1) == 0) { + full_sender_name = get_optarg(argv, &arg, opt+1); + if (!full_sender_name) { + fprintf(stderr, "-F requires a name argument\n"); + exit(EXIT_FAILURE); + } + + } else if (strcmp(opt, "i") == 0) { + opt_i = TRUE; + exit_failure = FALSE; /* may override -oem */ + + } else if (strcmp(opt, "m") == 0) { + /* ignore -m (me too) switch (see man page) */ + + } else if (strcmp(opt, "Mrm") == 0) { + mta_mode = MODE_MCMD; + M_cmd = "rm"; + + } else if (strcmp(opt, "odq") == 0) { + do_queue = TRUE; + + } else if (strcmp(opt, "oem") == 0) { + if (!opt_i) { + /* TODO: Why is this related to -i in any way? */ + exit_failure = TRUE; + } + + } else if (strcmp(opt, "oi") == 0) { + exit_failure = FALSE; /* may override -oem */ + + } else if (strncmp(opt, "o", 1) == 0) { + /* ignore all other -oXXX options */ + + } else if (strncmp(opt, "qo", 2) == 0) { + mta_mode = MODE_RUNQUEUE; + do_runq = FALSE; + do_runq_online = TRUE; + /* can be NULL, then we use online detection method */ + route_name = get_optarg(argv, &arg, opt+2); + + } else if (strncmp(opt, "q", 1) == 0) { + /* must be after the `qo' check */ + gchar *optarg; + int dummy; + + do_runq = TRUE; + mta_mode = MODE_RUNQUEUE; + if ((optarg = get_optarg(argv, &arg, opt+1))) { + mta_mode = MODE_DAEMON; + queue_interval = time_interval(optarg, &dummy); + } + + } else if (strcmp(opt, "t") == 0) { + opt_t = TRUE; + + } else if (strcmp(opt, "v") == 0) { + do_verbose = TRUE; + } else { - if (argv[arg][pos + 1] == '-') { - if (argv[arg][pos + 2] != '\0') { - fprintf(stderr, "unrecognized option '%s'\n", argv[arg]); - exit(EXIT_FAILURE); - } - arg++; - } - break; + fprintf(stderr, "unrecognized option `-%s'\n", opt); + exit(EXIT_FAILURE); } - arg++; } if (mta_mode == MODE_VERSION) {