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) {