masqmail
diff src/masqmail.c @ 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 |
line diff
1.1 --- a/src/masqmail.c Mon Nov 01 14:53:26 2010 -0300 1.2 +++ b/src/masqmail.c Thu Nov 04 11:02:42 2010 -0300 1.3 @@ -91,19 +91,25 @@ 1.4 } 1.5 #endif 1.6 1.7 +/* 1.8 +argv: the original argv 1.9 +argp: number of arg (may get modified!) 1.10 +cp: pointing to the char after the option 1.11 + e.g. `-d 6' `-d6' 1.12 + ^ ^ 1.13 +*/ 1.14 gchar* 1.15 -get_optarg(char *argv[], gint argc, gint * argp, gint * pos) 1.16 +get_optarg(char* argv[], gint* argp, char* cp) 1.17 { 1.18 - if (argv[*argp][*pos]) 1.19 - return &(argv[*argp][*pos]); 1.20 - else { 1.21 - if (*argp + 1 < argc) { 1.22 - if (argv[(*argp) + 1][0] != '-') { 1.23 - (*argp)++; 1.24 - *pos = 0; 1.25 - return &(argv[*argp][*pos]); 1.26 - } 1.27 - } 1.28 + if (*cp) { 1.29 + /* this kind: -xval */ 1.30 + return cp; 1.31 + } 1.32 + cp = argv[*argp+1]; 1.33 + if (cp && (*cp != '-')) { 1.34 + /* this kind: -x val */ 1.35 + (*argp)++; 1.36 + return cp; 1.37 } 1.38 return NULL; 1.39 } 1.40 @@ -288,7 +294,8 @@ 1.41 { 1.42 /* cmd line flags */ 1.43 gchar *conf_file = CONF_FILE; 1.44 - gint arg = 1; 1.45 + char* opt; 1.46 + gint arg; 1.47 1.48 gboolean do_listen = FALSE; 1.49 gboolean do_runq = FALSE; 1.50 @@ -336,166 +343,124 @@ 1.51 } 1.52 1.53 /* parse cmd line */ 1.54 - while (arg < argc) { 1.55 - gint pos = 0; 1.56 - if ((argv[arg][pos] == '-') && (argv[arg][pos + 1] != '-')) { 1.57 - pos++; 1.58 - switch (argv[arg][pos++]) { 1.59 - case 'b': 1.60 - switch (argv[arg][pos++]) { 1.61 - case 'd': 1.62 - do_listen = TRUE; 1.63 - mta_mode = MODE_DAEMON; 1.64 - break; 1.65 - case 'i': 1.66 - /* ignored */ 1.67 - mta_mode = MODE_BI; 1.68 - break; 1.69 - case 's': 1.70 - mta_mode = MODE_SMTP; 1.71 - break; 1.72 - case 'p': 1.73 - mta_mode = MODE_LIST; 1.74 - break; 1.75 - case 'V': 1.76 - mta_mode = MODE_VERSION; 1.77 - break; 1.78 - default: 1.79 - fprintf(stderr, "unrecognized option '%s'\n", argv[arg]); 1.80 - exit(EXIT_FAILURE); 1.81 - } 1.82 - break; 1.83 - case 'B': 1.84 - /* we ignore this and throw the argument away */ 1.85 - get_optarg(argv, argc, &arg, &pos); 1.86 - break; 1.87 - case 'C': 1.88 - if (!(conf_file = get_optarg(argv, argc, &arg, &pos))) { 1.89 - fprintf(stderr, "-C requires a filename as argument.\n"); 1.90 - exit(EXIT_FAILURE); 1.91 - } 1.92 - break; 1.93 - case 'F': 1.94 - { 1.95 - full_sender_name = get_optarg(argv, argc, &arg, &pos); 1.96 - if (!full_sender_name) { 1.97 - fprintf(stderr, "-F requires a name as an argument\n"); 1.98 - exit(EXIT_FAILURE); 1.99 - } 1.100 - } 1.101 - break; 1.102 - case 'd': 1.103 - if (getuid() == 0) { 1.104 - char *lvl = get_optarg(argv, argc, &arg, &pos); 1.105 - if (lvl) 1.106 - debug_level = atoi(lvl); 1.107 - else { 1.108 - fprintf(stderr, "-d requires a number as an argument.\n"); 1.109 - exit(EXIT_FAILURE); 1.110 - } 1.111 - } else { 1.112 - fprintf(stderr, "only root may set the debug level.\n"); 1.113 - exit(EXIT_FAILURE); 1.114 - } 1.115 - break; 1.116 - case 'f': 1.117 - /* set return path */ 1.118 - { 1.119 - gchar *address; 1.120 - address = get_optarg(argv, argc, &arg, &pos); 1.121 - if (address) { 1.122 - f_address = g_strdup(address); 1.123 - } else { 1.124 - fprintf(stderr, "-f requires an address as an argument\n"); 1.125 - exit(EXIT_FAILURE); 1.126 - } 1.127 - } 1.128 - break; 1.129 - case 'i': 1.130 - if (argv[arg][pos] == 0) { 1.131 - opt_i = TRUE; 1.132 - exit_failure = FALSE; /* may override -oem */ 1.133 - } else { 1.134 - fprintf(stderr, "unrecognized option '%s'\n", argv[arg]); 1.135 - exit(EXIT_FAILURE); 1.136 - } 1.137 - break; 1.138 - case 'M': 1.139 - { 1.140 - mta_mode = MODE_MCMD; 1.141 - M_cmd = g_strdup(&(argv[arg][pos])); 1.142 - } 1.143 - break; 1.144 - case 'm': 1.145 - /* ignore -m (me too) switch (see man page) */ 1.146 - break; 1.147 - case 'o': 1.148 - char* oarg = argv[arg][pos+1]; 1.149 - if (strcmp(oarg, "oem") == 0) { 1.150 - if (!opt_i) { 1.151 - /* FIXME: this check needs to be done after 1.152 - option processing as -oi may come later */ 1.153 - exit_failure = TRUE; 1.154 - } 1.155 - } else if (strcmp(oarg, "odb") == 0) { 1.156 - /* ignore ``deliver in background'' switch */ 1.157 - } else if (strcmp(oarg, "odq") == 0) { 1.158 - do_queue = TRUE; 1.159 - } else if (strcmp(oarg, "oi") == 0) { 1.160 - exit_failure = FALSE; /* may override -oem */ 1.161 - } else if (strcmp(oarg, "om") == 0) { 1.162 - /* ignore ``me too'' switch */ 1.163 - } else { 1.164 - fprintf(stderr, "ignoring unrecognized option %s\n", 1.165 - argv[arg]); 1.166 - } 1.167 - break; 1.168 + for (arg=1; arg<argc && argv[arg][0]=='-'; arg++) { 1.169 + opt = argv[arg] + 1; 1.170 1.171 - case 'q': 1.172 - { 1.173 - gchar *optarg; 1.174 + if (strcmp(opt, "-") == 0) { 1.175 + /* everything after `--' are address arguments */ 1.176 + arg++; 1.177 + break; 1.178 1.179 - do_runq = TRUE; 1.180 - mta_mode = MODE_RUNQUEUE; 1.181 - if (argv[arg][pos] == 'o') { 1.182 - pos++; 1.183 - do_runq = FALSE; 1.184 - do_runq_online = TRUE; 1.185 - /* can be NULL, then we use online detection method */ 1.186 - route_name = get_optarg(argv, argc, &arg, &pos); 1.187 - } else 1.188 - if ((optarg = get_optarg(argv, argc, &arg, &pos))) { 1.189 - mta_mode = MODE_DAEMON; 1.190 - queue_interval = time_interval(optarg, &pos); 1.191 - } 1.192 - } 1.193 - break; 1.194 - case 't': 1.195 - if (argv[arg][pos] == '\0') { 1.196 - opt_t = TRUE; 1.197 - } else { 1.198 - fprintf(stderr, "unrecognized option '%s'\n", argv[arg]); 1.199 - exit(EXIT_FAILURE); 1.200 - } 1.201 - break; 1.202 - case 'v': 1.203 - do_verbose = TRUE; 1.204 - break; 1.205 - default: 1.206 - fprintf(stderr, "unrecognized option '%s'\n", argv[arg]); 1.207 + } else if (strcmp(opt, "bd") == 0) { 1.208 + do_listen = TRUE; 1.209 + mta_mode = MODE_DAEMON; 1.210 + 1.211 + } else if (strcmp(opt, "bi") == 0) { 1.212 + /* ignored */ 1.213 + mta_mode = MODE_BI; 1.214 + 1.215 + } else if (strcmp(opt, "bs") == 0) { 1.216 + mta_mode = MODE_SMTP; 1.217 + 1.218 + } else if (strcmp(opt, "bp") == 0) { 1.219 + mta_mode = MODE_LIST; 1.220 + 1.221 + } else if (strcmp(opt, "bV") == 0) { 1.222 + mta_mode = MODE_VERSION; 1.223 + 1.224 + } else if (strncmp(opt, "B", 1) == 0) { 1.225 + /* we ignore this and throw the argument away */ 1.226 + get_optarg(argv, &arg, opt+1); 1.227 + 1.228 + } else if (strncmp(opt, "C", 1) == 0) { 1.229 + if (!(conf_file = get_optarg(argv, &arg, opt+1))) { 1.230 + fprintf(stderr, "-C requires a filename as argument.\n"); 1.231 exit(EXIT_FAILURE); 1.232 } 1.233 + 1.234 + } else if (strncmp(opt, "d", 1) == 0) { 1.235 + if (getuid() != 0) { 1.236 + fprintf(stderr, "only root may set the debug level.\n"); 1.237 + exit(EXIT_FAILURE); 1.238 + } 1.239 + char *lvl = get_optarg(argv, &arg, opt+1); 1.240 + if (!lvl) { 1.241 + fprintf(stderr, "-d requires a number argument.\n"); 1.242 + exit(EXIT_FAILURE); 1.243 + } 1.244 + debug_level = atoi(lvl); 1.245 + 1.246 + } else if (strncmp(opt, "f", 1) == 0) { 1.247 + /* set return path */ 1.248 + gchar *address = get_optarg(argv, &arg, opt+1); 1.249 + if (!address) { 1.250 + fprintf(stderr, "-f requires an address argument\n"); 1.251 + exit(EXIT_FAILURE); 1.252 + } 1.253 + f_address = g_strdup(address); 1.254 + 1.255 + } else if (strncmp(opt, "F", 1) == 0) { 1.256 + full_sender_name = get_optarg(argv, &arg, opt+1); 1.257 + if (!full_sender_name) { 1.258 + fprintf(stderr, "-F requires a name argument\n"); 1.259 + exit(EXIT_FAILURE); 1.260 + } 1.261 + 1.262 + } else if (strcmp(opt, "i") == 0) { 1.263 + opt_i = TRUE; 1.264 + exit_failure = FALSE; /* may override -oem */ 1.265 + 1.266 + } else if (strcmp(opt, "m") == 0) { 1.267 + /* ignore -m (me too) switch (see man page) */ 1.268 + 1.269 + } else if (strcmp(opt, "Mrm") == 0) { 1.270 + mta_mode = MODE_MCMD; 1.271 + M_cmd = "rm"; 1.272 + 1.273 + } else if (strcmp(opt, "odq") == 0) { 1.274 + do_queue = TRUE; 1.275 + 1.276 + } else if (strcmp(opt, "oem") == 0) { 1.277 + if (!opt_i) { 1.278 + /* TODO: Why is this related to -i in any way? */ 1.279 + exit_failure = TRUE; 1.280 + } 1.281 + 1.282 + } else if (strcmp(opt, "oi") == 0) { 1.283 + exit_failure = FALSE; /* may override -oem */ 1.284 + 1.285 + } else if (strncmp(opt, "o", 1) == 0) { 1.286 + /* ignore all other -oXXX options */ 1.287 + 1.288 + } else if (strncmp(opt, "qo", 2) == 0) { 1.289 + mta_mode = MODE_RUNQUEUE; 1.290 + do_runq = FALSE; 1.291 + do_runq_online = TRUE; 1.292 + /* can be NULL, then we use online detection method */ 1.293 + route_name = get_optarg(argv, &arg, opt+2); 1.294 + 1.295 + } else if (strncmp(opt, "q", 1) == 0) { 1.296 + /* must be after the `qo' check */ 1.297 + gchar *optarg; 1.298 + int dummy; 1.299 + 1.300 + do_runq = TRUE; 1.301 + mta_mode = MODE_RUNQUEUE; 1.302 + if ((optarg = get_optarg(argv, &arg, opt+1))) { 1.303 + mta_mode = MODE_DAEMON; 1.304 + queue_interval = time_interval(optarg, &dummy); 1.305 + } 1.306 + 1.307 + } else if (strcmp(opt, "t") == 0) { 1.308 + opt_t = TRUE; 1.309 + 1.310 + } else if (strcmp(opt, "v") == 0) { 1.311 + do_verbose = TRUE; 1.312 + 1.313 } else { 1.314 - if (argv[arg][pos + 1] == '-') { 1.315 - if (argv[arg][pos + 2] != '\0') { 1.316 - fprintf(stderr, "unrecognized option '%s'\n", argv[arg]); 1.317 - exit(EXIT_FAILURE); 1.318 - } 1.319 - arg++; 1.320 - } 1.321 - break; 1.322 + fprintf(stderr, "unrecognized option `-%s'\n", opt); 1.323 + exit(EXIT_FAILURE); 1.324 } 1.325 - arg++; 1.326 } 1.327 1.328 if (mta_mode == MODE_VERSION) {