[PATCH weston v2 2/7] shared/option-parser: Rework option parsing

Bill Spitzak spitzak at gmail.com
Fri Apr 26 12:02:55 PDT 2013


This looks good to me, especially with all the automatic tests added.

Quentin Glidic wrote:

> -static void
> -handle_option(const struct weston_option *option, char *value)
> +enum state {
> +	OK,
> +	EATEN,
> +	ERROR
> +};
> +
> +static enum state
> +handle_option(const struct weston_option *option, const char *value)
>  {
>  	switch (option->type) {
>  	case WESTON_OPTION_INTEGER:
> +		if (value == NULL || value[0] == '\0')
> +			return ERROR;
>  		* (int32_t *) option->data = strtol(value, NULL, 0);

Since you already checked for a zero-length string, you can detect 
non-numbers with:

	        const char* p;
		... option->data = strtol(value, 0, &p);
		if (*p) return ERROR;

> -		return;
> +		return EATEN;
>  	case WESTON_OPTION_UNSIGNED_INTEGER:
> +		if (value == NULL || value[0] == '\0')
> +			return ERROR;
>  		* (uint32_t *) option->data = strtoul(value, NULL, 0);
> -		return;
> +		return EATEN;
>  	case WESTON_OPTION_STRING:
> +		if (value == NULL)
> +			return ERROR;
>  		* (char **) option->data = strdup(value);
> -		return;
> +		return EATEN;
>  	case WESTON_OPTION_BOOLEAN:
>  		* (int32_t *) option->data = 1;
> -		return;
> +		return OK;
>  	default:
>  		assert(0);
>  	}
> @@ -54,26 +66,89 @@ parse_options(const struct weston_option *options,
>  	      int count, int *argc, char *argv[])
>  {
>  	int i, j, k, len = 0;
> +	const char *arg, *value;
>  
>  	for (i = 1, j = 1; i < *argc; i++) {
> -		for (k = 0; k < count; k++) {
> -			if (options[k].name)
> +		arg = argv[i];
> +		value = argv[i+1];
> +
> +		if (arg[0] != '-')
> +		{
> +			/* Not an option, just skip it */
> +			argv[j++] = argv[i];
> +			continue;
> +		}
> +		++arg; /* Skip the first dash */
> +
> +		/* We have an option, check for which one */
> +		if (arg[0] == '-') {
> +			/* Long option */
> +			++arg; /* Skip the second dash */
> +			for (k = 0; k < count; k++) {
> +				if (!options[k].name)
> +					/* No long variant for this option */
> +					continue;
> +
>  				len = strlen(options[k].name);
> -			if (options[k].name &&
> -			    argv[i][0] == '-' &&
> -			    argv[i][1] == '-' &&
> -			    strncmp(options[k].name, &argv[i][2], len) == 0 &&
> -			    (argv[i][len + 2] == '=' || argv[i][len + 2] == '\0')) {
> -				handle_option(&options[k], &argv[i][len + 3]);
> +				if (strncmp(options[k].name, arg, len) != 0)
> +					/* Not matching */
> +					continue;
> +
> +				switch (arg[len]) {
> +				case '=': value = arg + (len+1);
> +				case '\0': break;
> +				default: continue; /* Not fully matching */
> +				}
> +
> +				switch (handle_option(&options[k], value)) {
> +				case OK: break;
> +				case EATEN:
> +					if (arg[len] == '\0')
> +						++i;
> +					break;
> +				case ERROR: return -1;
> +				}
> +
>  				break;
> -			} else if (options[k].short_name &&
> -				   argv[i][0] == '-' &&
> -				   options[k].short_name == argv[i][1]) {
> -				handle_option(&options[k], &argv[i][2]);
> +			}
> +		} else {
> +			/* Short option */
> +			for (k = 0; k < count; k++) {
> +				if (!options[k].short_name)
> +					/* no short variant for this option */
> +					continue;
> +
> +				if (options[k].short_name != arg[0])
> +					/* Not matching */
> +					continue;
> +
> +				if (arg[1] != '\0')
> +					value = arg+1;
> +
> +				switch (arg[1]) {
> +				case '\0': break;
> +				case '=': value = arg + 2; break;
> +				default: value = arg + 1;
> +				}
> +				//fprintf(stderr, "arg = %s, value = '%s'\n", arg, value);
> +
> +				switch (handle_option(&options[k], value)) {
> +				case OK:
> +					if (arg[1] != '\0')
> +						/* Do not support merged short options */
> +						return -1;

Good idea, leave this possibility open without deciding on it now.

> +					break;
> +				case EATEN:
> +					if (arg[1] == '\0')
> +						++i;
> +					break;
> +				case ERROR: return -1;
> +				}
>  				break;
>  			}
>  		}
>  		if (k == count)
> +			/* None matched */
>  			argv[j++] = argv[i];
>  	}
>  	argv[j] = NULL;


More information about the wayland-devel mailing list