diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/simple-opt.h | 126 |
1 files changed, 98 insertions, 28 deletions
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"); |