From 6891a0864bf3ab0ed80e09339f2a6562689a716d Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sat, 28 Mar 2015 18:42:38 +0100 Subject: ... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- src/libargparser/argparser.c | 179 ++++++++++++++++++++++++++++++++++++++++--- src/libargparser/argparser.h | 58 +++++++++++++- 2 files changed, 226 insertions(+), 11 deletions(-) diff --git a/src/libargparser/argparser.c b/src/libargparser/argparser.c index 39e5750..fc5772a 100644 --- a/src/libargparser/argparser.c +++ b/src/libargparser/argparser.c @@ -25,7 +25,9 @@ #include -#define xfree(s) (free(s), s = NULL) +#define xfree(s) (free(s), s = NULL) +#define xmalloc(s, n, t) ((s = malloc((n) * sizeof(t))) == NULL) +#define xgetenv(v) (getenv(v) ? getenv(v) : "") /** @@ -35,7 +37,7 @@ * @return Zero on success, -1 on error, `errno` will be set accordingly */ int args_initialise(args_parser_t* parser) -{ +{ parser->state->arguments = NULL; parser->state->files = NULL; parser->state->message = NULL; @@ -50,7 +52,7 @@ int args_initialise(args_parser_t* parser) parser->state->all_options_count = 0; parser->state->freeptr = 0; - parser->settings->linuxvt = getenv("TERM") ? !strcmp(getenv("TERM"), "linux") : 0; + parser->settings->linuxvt = !strcmp(xgetenv("TERM"), "linux"); parser->settings->alternative = 0; parser->settings->stop_at_first_file = 0; parser->settings->use_colours = AUTO; @@ -63,11 +65,11 @@ int args_initialise(args_parser_t* parser) parser->settings->help_out = stderr; parser->settings->abbreviations = args_standard_abbreviations; - if ((parser->state->arguments = malloc(1 * sizeof(char*))) == NULL) goto fail; - if ((parser->state->files = malloc(1 * sizeof(char*))) == NULL) goto fail; - if ((parser->state->options = malloc(1 * sizeof(args_option_t))) == NULL) goto fail; - if ((parser->state->all_options = malloc(1 * sizeof(char*))) == NULL) goto fail; - if ((parser->state->freequeue = malloc(1 * sizeof(void*))) == NULL) goto fail; + if (xmalloc(parser->state->arguments, 1, char*)) goto fail; + if (xmalloc(parser->state->files, 1, char*)) goto fail; + if (xmalloc(parser->state->options, 1, args_option_t)) goto fail; + if (xmalloc(parser->state->all_options, 1, char*)) goto fail; + if (xmalloc(parser->state->freequeue, 1, void*)) goto fail; return 0; fail: @@ -85,7 +87,7 @@ int args_initialise(args_parser_t* parser) * * @param parser The parser */ -void args_dispose(parser_t* parser) +void args_dispose(args_parser_t* parser) { size_t i; @@ -99,7 +101,10 @@ void args_dispose(parser_t* parser) xfree(parser->state->message); xfree(parser->state->files); for (i = 0; i < parser->state->options_count; i++) - free(parser->state->options[i].alternatives); + { + free(parser->state->options[i].alternatives); + free(parser->state->options[i].arguments); + } parser->state->options_count = 0; xfree(parser->state->options); xfree(parser->state->all_options); @@ -111,6 +116,28 @@ void args_dispose(parser_t* parser) } +/** + * Maps up options that are alternatives to the standard alternative for each option + * + * @param parser The parser + * @return Zero on success, -1 on error + */ +int args_support_alternatives(args_parser_t* parser) +{ + size_t i; + + for (i = 0; i < parser->state->all_options_count; i++) + { + const char* alternative = parser->state->all_options[i]; + const char* standard = parser->state->all_options_standard[i]; + + /* TODO map `alternative` to `standard` */ + } + + return 0; +} + + /** * Checks the correctness of the number of used non-option arguments * @@ -151,6 +178,138 @@ int args_test_files(args_parser_t* parser, size_t min, size_t max) } +/** + * Checks for out of context option usage + * + * @param parser The parser + * @param ...:const char* Allowed options + * @return Whether only allowed options was used, -1 on error + */ +int args_test_allowed(args_parser_t* parser, ...) +{ + size_t count = 0; + va_list args, cp; + const char** list; + const char* elem; + int rc; + + va_copy(cp, args); + va_start(cp, parser); + while (va_arg(cp, const char*) != NULL) + count++; + va_end(cp); + + if ((list = malloc(count * sizeof(const char*))) == NULL) + return -1; + + count = 0; + va_start(args, parser); + while ((elem = va_arg(args, const char*)) != NULL) + list[count++] = elem; + va_end(args); + + rc = args_test_allowed_l(parser, list, count); + free(list); + return rc; +} + + +/** + * Checks for out of context option usage + * + * @param parser The parser + * @param allowed Allowed options + * @param count The number of elements in `allowed` + * @return Whether only allowed options was used + */ +int args_test_allowed_l(args_parser_t* parser, const char** allowed, size_t count) +{ + /* TODO print warnings */ + size_t i, j, k; + + for (i = 0; i < parser->state->options_count; i++) + if (parser->state->options[i].arguments_count > 0) + { + for (j = 0; j < parser->state->options[i].alternatives_count; j++) + for (k = 0; k < count; k++) + if (!strcmp(parser->state->options[i].alternatives[j], allowed[k])) + goto allowed; + + return 0; + allowed: + continue; + } + + return 1; +} + + +/** + * Checks for option conflicts + * + * @param parser The parser + * @param ...:const char* Mutually exclusive options + * @return Whether at most one exclusive option was used, -1 on error + */ +int args_test_exclusiveness(args_parser_t* parser, ...) +{ + size_t count = 0; + va_list args, cp; + const char** list; + const char* elem; + int rc; + + va_copy(cp, args); + va_start(cp, parser); + while (va_arg(cp, const char*) != NULL) + count++; + va_end(cp); + + if ((list = malloc(count * sizeof(const char*))) == NULL) + return -1; + + count = 0; + va_start(args, parser); + while ((elem = va_arg(args, const char*)) != NULL) + list[count++] = elem; + va_end(args); + + rc = args_test_exclusiveness_l(parser, list, count); + free(list); + return rc; +} + + +/** + * Checks for option conflicts + * + * @param parser The parser + * @param exclusives Mutually exclusive options + * @param count The number of elements in `exclusives` + * @return Whether at most one exclusive option was used + */ +int args_test_exclusiveness_l(args_parser_t* parser, const char** exclusives, size_t count) +{ + /* TODO print warnings */ + size_t i, j, k, have_count; + + for (i = 0; i < parser->state->options_count; i++) + if (parser->state->options[i].arguments_count > 0) + { + for (j = 0; j < parser->state->options[i].alternatives_count; j++) + for (k = 0; k < count; k++) + if (!strcmp(parser->state->options[i].alternatives[j], exclusives[k])) + goto exclusive; + + continue; + exclusive: + have_count++; + } + + return have_count <= 1; +} + + /** * Dummy trigger * diff --git a/src/libargparser/argparser.h b/src/libargparser/argparser.h index 9809f7a..51feace 100644 --- a/src/libargparser/argparser.h +++ b/src/libargparser/argparser.h @@ -125,6 +125,16 @@ typedef struct args_option */ void* user_data; + /** + * Arguments passed to the option, `NULL` when argumentless + */ + char** arguments; + + /** + * The number of elements in `arguments` + */ + size_t arguments_count; + /** * Invoked when the option is used * @@ -350,7 +360,15 @@ int args_initialise(args_parser_t* parser); * * @param parser The parser */ -void args_dispose(parser_t* parser); +void args_dispose(args_parser_t* parser); + +/** + * Maps up options that are alternatives to the standard alternative for each option + * + * @param parser The parser + * @return Zero on success, -1 on error + */ +int args_support_alternatives(args_parser_t* parser); /** * Checks the correctness of the number of used non-option arguments @@ -380,6 +398,44 @@ int args_test_files_max(args_parser_t* parser, size_t max); */ int args_test_files(args_parser_t* parser, size_t min, size_t max); +/** + * Checks for out of context option usage + * + * @param parser The parser + * @param ...:const char* Allowed options + * @return Whether only allowed options was used, -1 on error + */ +int args_test_allowed(args_parser_t* parser, ...); + +/** + * Checks for out of context option usage + * + * @param parser The parser + * @param allowed Allowed options + * @param count The number of elements in `allowed` + * @return Whether only allowed options was used + */ +int args_test_allowed_l(args_parser_t* parser, const char** allowed, size_t count) ARGS_PURE; + +/** + * Checks for option conflicts + * + * @param parser The parser + * @param ...:const char* Mutually exclusive options + * @return Whether at most one exclusive option was used, -1 on error + */ +int args_test_exclusiveness(args_parser_t* parser, ...); + +/** + * Checks for option conflicts + * + * @param parser The parser + * @param exclusives Mutually exclusive options + * @param count The number of elements in `exclusives` + * @return Whether at most one exclusive option was used + */ +int args_test_exclusiveness_l(args_parser_t* parser, const char** exclusives, size_t count) ARGS_PURE; + /** * Dummy trigger * -- cgit v1.2.3-70-g09d2