diff options
| -rw-r--r-- | doc/example.c | 42 | ||||
| -rw-r--r-- | src/simple-opt.h | 126 | 
2 files changed, 131 insertions, 37 deletions
| diff --git a/doc/example.c b/doc/example.c index fee399b..08a9d7f 100644 --- a/doc/example.c +++ b/doc/example.c @@ -2,20 +2,32 @@  int main(int argc, char **argv)  { +	const char *set[] = { "choice_a", "choice_b", NULL }; +  	/* array containing all options and their types / attributes */  	struct simple_opt options[] = {  		{ SIMPLE_OPT_FLAG, 'h', "help", false,  			"print this help message and exit" }, +		{ SIMPLE_OPT_BOOL, 'b', "bool", false, +			"(optionally) takes a boolean arg!" },  		{ SIMPLE_OPT_INT, '\0', "int", true, -			"this thing needs an integer!" }, +			"requires an integer. has no short_name!" },  		{ SIMPLE_OPT_UNSIGNED, 'u', "uns", true,  			"this one has a custom_arg_string. normally it would say"   				" \"UNSIGNED\" rather than \"NON-NEG-INT\"",  			"NON-NEG-INT" }, +		{ SIMPLE_OPT_DOUBLE, 'd', "double", true, +			"a floating point number" },  		{ SIMPLE_OPT_STRING, 's', NULL, true, -			"this one doesn't have a long opt version" }, -		{ SIMPLE_OPT_BOOL, 'b', "bool", false, -			"(optionally) takes a boolean arg!" }, +			"this one doesn't have a long_name version" }, +		{ SIMPLE_OPT_STRING_SET, '\0', "set-choice", true, +			"a choice of one string from a NULL-terminated array." +				" note that, in order to maintain redability, the description" +				" indentation does not accomodate the full width of an" +				" overly-wide custom_arg_string like (choice_a|choice_b)", +			"(choice_a|choice_b)", set }, +		{ SIMPLE_OPT_CHAR, 'c', "char", false, +			"(optionally) takes a character argument" },  		{ SIMPLE_OPT_END },  	}; @@ -82,22 +94,34 @@ int main(int argc, char **argv)  		if (options[i].arg_is_stored) {  			switch (options[i].type) { +			case SIMPLE_OPT_BOOL: +				printf(", val: %s", options[i].val_bool ? "true" : "false"); +				break; +				  			case SIMPLE_OPT_INT: -				printf(", val: %d", options[i].val_int); +				printf(", val: %ld", options[i].val_int);  				break;  			case SIMPLE_OPT_UNSIGNED: -				printf(", val: %u", options[i].val_unsigned); +				printf(", val: %lu", options[i].val_unsigned); +				break; + +			case SIMPLE_OPT_DOUBLE: +				printf(", val: %lf", options[i].val_double); +				break; + +			case SIMPLE_OPT_CHAR: +				printf(", val: %c", options[i].val_char);  				break;  			case SIMPLE_OPT_STRING:  				printf(", val: %s", options[i].val_string);  				break; -			case SIMPLE_OPT_BOOL: -				printf(", val: %s", options[i].val_bool ? "true" : "false"); +			case SIMPLE_OPT_STRING_SET: +				printf(", val: %s", set[options[i].val_string_set_idx]);  				break; -				 +  			default:  				break;  			} diff --git a/src/simple-opt.h b/src/simple-opt.h index 2a3564d..7bbb8b8 100644 --- a/src/simple-opt.h +++ b/src/simple-opt.h @@ -6,6 +6,7 @@  #include <string.h>  #include <stdio.h>  #include <ctype.h> +#include <errno.h>  /* the maximum number of options that can be passed on the cli */  #ifndef SIMPLE_OPT_MAX_ARGC @@ -33,7 +34,10 @@ enum simple_opt_type {  	SIMPLE_OPT_BOOL,  	SIMPLE_OPT_INT,  	SIMPLE_OPT_UNSIGNED, +	SIMPLE_OPT_DOUBLE, +	SIMPLE_OPT_CHAR,  	SIMPLE_OPT_STRING, +	SIMPLE_OPT_STRING_SET,  	SIMPLE_OPT_END,  }; @@ -43,21 +47,28 @@ struct simple_opt {  	const char *long_name;  	bool arg_is_required; -	/* optional, used for usage printing */ +	/* optional, a description of the option used for usage printing */  	const char *description;  	/* optional, a custom string describing the arg, used for usage printing */  	const char *custom_arg_string; +	/* for type SIMPLE_OPT_STRING_SET, a NULL-terminated array of string +	 * possibilities against which an option's argument is matched */ +	const char **string_set; +  	/* values assigned upon successful option parse */  	bool was_seen;  	bool arg_is_stored;  	union {  		bool val_bool; -		int val_int; -		unsigned val_unsigned; +		long val_int; +		unsigned long val_unsigned; +		double val_double; +		char val_char;  		char val_string[SIMPLE_OPT_OPT_ARG_MAX_WIDTH]; +		int val_string_set_idx;  	};  }; @@ -95,7 +106,7 @@ static void simple_opt_print_usage(FILE *f, unsigned width, char *usage_name,  static bool sub_simple_opt_parse(struct simple_opt *o, char *s)  {  	int i, j; -	char *str; +	char *str, *cp;  	bool match;  	switch (o->type) { @@ -148,35 +159,40 @@ strmatch_out:  	case SIMPLE_OPT_INT: +		errno = 0; +		o->val_int = strtol(s, &cp, 0); -		if (s[0] == '-' || s[0] == '+') { -			if (strlen(s) < 2) -				return false; -			j = 1; -		} else { -			j = 0; -		} +		if (cp == s || *cp != '\0' || errno) +			return false; -		for (i = j; s[i] != '\0'; i++) { -			if ( !isdigit(s[i]) ) -				return false; -		} +		return true; -		if (s[0] == '-') -			o->val_int = -atoi(s+j); -		else -			o->val_int = atoi(s+j); +	case SIMPLE_OPT_UNSIGNED: +		if (s[0] == '-' || s[0] == '+') +			return false; + +		errno = 0; +		o->val_unsigned = strtoul(s, &cp, 0); + +		if (cp == s || *cp != '\0' || errno) +			return false;  		return true; -	case SIMPLE_OPT_UNSIGNED: +	case SIMPLE_OPT_DOUBLE: +		errno = 0; +		o->val_double = strtod(s, &cp); -		for (i = 0; s[i] != '\0'; i++) { -			if ( !isdigit(s[i]) ) -				return false; -		} +		if (cp == s || *cp != '\0' || errno) +			return false; -		o->val_int = atoi(s); +		return true; + +	case SIMPLE_OPT_CHAR: +		if (strlen(s) != 1) +			return false; + +		o->val_char = s[0];  		return true;  	case SIMPLE_OPT_STRING: @@ -186,6 +202,16 @@ strmatch_out:  		strcpy(o->val_string, s);  		return true; +	case SIMPLE_OPT_STRING_SET: +		for (i = 0; o->string_set[i] != NULL; i++) { +			if (!strcmp(s, o->string_set[i])) { +				o->val_string_set_idx = i; +				return true; +			} +		} + +		return false; +  	default:  		return false;  	} @@ -398,8 +424,15 @@ static int sub_simple_opt_wrap_print(FILE *f, unsigned width, int col,  		add_newline = true;  	} -	if (add_newline) +	if (add_newline) {  		fprintf(f, "\n"); +		col = 0; + +		if (width > 20) { +			fprintf(f, "  "); +			col += 2; +		} +	}  	/* print out the message, trying to wrap at words */  	word_start = 0; @@ -426,12 +459,20 @@ static int sub_simple_opt_wrap_print(FILE *f, unsigned width, int col,  		if (width != 0 && col + (word_end - word_start) + (first_word ? 0 : 1)  				> width && first_word == false) {  			fprintf(f, "\n"); -			/* buffer up to line_start with spaces */  			col = 0; + +			/* buffer up to line_start with spaces */  			while (col < line_start) {  				fprintf(f, " ");  				col++;  			} + +			/* newline indentation, for readability */ +			if (width > 20) { +				fprintf(f, "  "); +				col += 2; +			} +  			first_word = true;  		}  @@ -522,9 +563,18 @@ static void simple_opt_print_usage(FILE *f, unsigned width, char *usage_name,  				case SIMPLE_OPT_UNSIGNED:  					j += 8;  					break; +				case SIMPLE_OPT_DOUBLE: +					j += 6; +					break; +				case SIMPLE_OPT_CHAR: +					j += 4; +					break;  				case SIMPLE_OPT_STRING:  					j += 6;  					break; +				case SIMPLE_OPT_STRING_SET: +					j += 10; +					break;  				default:  					break;  				} @@ -542,6 +592,11 @@ static void simple_opt_print_usage(FILE *f, unsigned width, char *usage_name,  		return;  	} +	/* if the desc_line_start is so far over it threatens readability, move it +	 * back a bit and just let the offending longer args be offset */ +	if (desc_line_start > (width / 2 < 30 ? width / 2 : 30)) +		desc_line_start = (width / 2 < 30 ? width / 2 : 30); +  	/*   	 * printing  @@ -631,10 +686,22 @@ static void simple_opt_print_usage(FILE *f, unsigned width, char *usage_name,  					sprintf(print_buffer + print_buffer_offset, "UNSIGNED");  					print_buffer_offset += 8;  					break; +				case SIMPLE_OPT_DOUBLE: +					sprintf(print_buffer + print_buffer_offset, "DOUBLE"); +					print_buffer_offset += 6; +					break; +				case SIMPLE_OPT_CHAR: +					sprintf(print_buffer + print_buffer_offset, "CHAR"); +					print_buffer_offset += 4; +					break;  				case SIMPLE_OPT_STRING:  					sprintf(print_buffer + print_buffer_offset, "STRING");  					print_buffer_offset += 6;  					break; +				case SIMPLE_OPT_STRING_SET: +					sprintf(print_buffer + print_buffer_offset, "STRING-SET"); +					print_buffer_offset += 10; +					break;  				default:  					break;  				} @@ -649,9 +716,12 @@ static void simple_opt_print_usage(FILE *f, unsigned width, char *usage_name,  		col = sub_simple_opt_wrap_print(f, width, col, 5, print_buffer);  		/* print option description */ -		if (options[i].description != NULL) +		if (options[i].description != NULL) { +			fprintf(f, "  "); +			col += 2;  			sub_simple_opt_wrap_print(f, width, col, desc_line_start,  					options[i].description); +		}  		/* end of this option */  		fprintf(f, "\n"); | 
