diff options
-rw-r--r-- | src/argparser.c | 2 | ||||
-rw-r--r-- | src/libargparser/argparser.c | 169 | ||||
-rw-r--r-- | src/libargparser/argparser.h | 185 |
3 files changed, 315 insertions, 41 deletions
diff --git a/src/argparser.c b/src/argparser.c index b3111e4..527b40e 100644 --- a/src/argparser.c +++ b/src/argparser.c @@ -125,7 +125,7 @@ void args_init(const char* description, const char* usage, const char* longdescr { char* term = getenv("TERM"); args_linuxvt = 0; - if (term == null) + if (term != null) if (*(term + 0) == 'l') if (*(term + 1) == 'i') if (*(term + 2) == 'n') diff --git a/src/libargparser/argparser.c b/src/libargparser/argparser.c index d0aa957..415ae88 100644 --- a/src/libargparser/argparser.c +++ b/src/libargparser/argparser.c @@ -19,6 +19,137 @@ #include "argparser.h" +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> + + +#define xfree(s) (free(s), s = NULL) + + +/** + * Initialise an argument parser + * + * @param parser The memory address of the parser to initialise + * @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; + parser->state->options = NULL; + parser->state->all_options = NULL; + parser->state->freequeue = NULL; + + parser->state->arguments_count = 0; + parser->state->unrecognised_count = 0; + parser->state->files_count = 0; + parser->state->options_count = 0; + parser->state->all_options_count = 0; + parser->state->freeptr = 0; + + parser->settings->linuxvt = getenv("TERM") ? !strcmp(getenv("TERM"), "linux") : 0; + parser->settings->alternative = 0; + parser->settings->stop_at_first_file = 0; + parser->settings->use_colours = AUTO; + parser->settings->program = NULL; + parser->settings->description = NULL; + parser->settings->usage = NULL; + parser->settings->longdescription = NULL; + parser->settings->error_out = stderr; + parser->settings->warning_out = stderr; + 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; + + return 0; + fail: + xfree(parser->state->arguments); + xfree(parser->state->files); + xfree(parser->state->options); + xfree(parser->state->all_options); + xfree(parser->state->freequeue); + return -1; +} + + +/** + * Disposes of all resources, run this when you are done + * + * @param parser The parser + */ +void args_dispose(parser_t* parser) +{ + size_t i; + + parser->state->arguments_count = 0; + parser->state->unrecognised_count = 0; + parser->state->files_count = 0; + parser->state->all_options_count = 0; + + xfree(parser->settings->program); + xfree(parser->state->arguments); + xfree(parser->state->message); + xfree(parser->state->files); + for (i = 0; i < parser->state->options_count; i++) + free(parser->state->options[i].alternatives); + parser->state->options_count = 0; + xfree(parser->state->options); + xfree(parser->state->all_options); + xfree(parser->state->all_options_standard); + for (i = 0; i < parser->state->freeptr; i++) + free(parser->state->freequeue[i]); + parser->state->freeptr = 0; + xfree(parser->state->freequeue); +} + + +/** + * Checks the correctness of the number of used non-option arguments + * + * @param parser The parser + * @param min The minimum number of files + * @return Whether the usage was correct + */ +int args_test_files_min(args_parser_t* restrictparser, size_t min) +{ + return min <= parser->state->files_count; +} + + +/** + * Checks the correctness of the number of used non-option arguments + * + * @param parser The parser + * @param max The maximum number of files + * @return Whether the usage was correct + */ +int args_test_files_max(args_parser_t* parser, size_t max) +{ + return parser->state->files_count <= max; +} + + +/** + * Checks the correctness of the number of used non-option arguments + * + * @param parser The parser + * @param min The minimum number of files + * @param max The maximum number of files + * @return Whether the usage was correct + */ +int args_test_files(args_parser_t* parser, size_t min, size_t max) +{ + return (min <= parser->state->files_count) && (parser->state->files_count <= max); +} + /** * Dummy trigger @@ -77,7 +208,7 @@ int args_no_stickless(void* user_data, const char* value) int args_default_stickless(void* user_data, const char* argument) { (void) user_data; - return (*argument != '-') && (*argument != '+'); + return (argument[0] != '-') && (argument[0] != '+'); } @@ -99,28 +230,26 @@ int args_no_variadic_end(void* user_data, char* value) /** * The standard abbrevation expander * - * @param argument The option that not recognised - * @param options All recognised options - * @param count The number of elements in `options` - * @return The only possible expansion, otherwise `null` + * @param argument The option that not recognised + * @param options All recognised options + * @param standards The corresponding standard option for options in `options` + * @param count The number of elements in `options` and `standards` + * @return The only possible expansion, otherwise `NULL` */ -const char* args_standard_abbreviations(const char* argument, const char** options, size_t count) +const char* args_standard_abbreviations(const char* argument, const char** options, const char** standards, size_t count) { - const char* rc = null; + const char* found = NULL; size_t i; + for (i = 0; i < count; i++) - { - size_t match = 0; - const char* opt = *(options + i); - while (*(argument + match) && (*(opt + match) == *(argument + match))) - match++; - if (*(argument + match) == 0) - { - if (rc) - return null; - rc = opt; - } - } - return rc; + if (strstr(options[i], argument) == options[i]) + { + if (found == NULL) + found = standards[i]; + else + return NULL; + } + + return found; } diff --git a/src/libargparser/argparser.h b/src/libargparser/argparser.h index af8477a..9809f7a 100644 --- a/src/libargparser/argparser.h +++ b/src/libargparser/argparser.h @@ -21,6 +21,17 @@ #include <stddef.h> +#include <stdio.h> + + + +#ifndef ARGS_CONST +# define ARGS_CONST __attribute__((const)) +#endif + +#ifndef ARGS_PURE +# define ARGS_PURE __attribute__((pure)) +#endif @@ -54,6 +65,29 @@ typedef enum args_option_type +/** + * Tristate type + */ +typedef enum args_tristate + { + /** + * False + */ + FALSE, + + /** + * True + */ + TRUE, + + /** + * Automatic + */ + AUTO + + } args_tristate_t; + + typedef struct args_option { /** @@ -147,6 +181,17 @@ typedef struct args_settings int alternative; /** + * Whether to all arguments after the first file + * should also be parsed as files + */ + int stop_at_first_file; + + /** + * Whether to use colours + */ + args_tristate_t use_colours; + + /** * The name of the executed command, will be freed by the parser */ char* program; @@ -182,14 +227,17 @@ typedef struct args_settings FILE* help_out; /** - * Abbreviated option expander, `null` for disabled + * Abbreviated option expander, `NULL` for disabled * - * @param argument The option that not recognised - * @param options All recognised options - * @param count The number of elements in `options` - * @return The only possible expansion, otherwise `NULL` + * @param argument The option that not recognised + * @param options All recognised options, order by order of appearance in the help, i.e. by inclusion + * @param standards The corresponding standard option for options in `options`, as a consequence of + * the order in `options` all identical values (will have identical address) in + * `standards` will directly follow eachother + * @param count The number of elements in `options` and `standards` + * @return The only possible expansion, otherwise `NULL` */ - const char* (*abbreviations)(const char* stub, const char** options, size_t count); + const char* (*abbreviations)(const char* stub, const char** options, const char** standards, size_t count); } args_settings_t; @@ -215,7 +263,7 @@ typedef struct args_state size_t unrecognised_count; /** - * The concatenation of `files` with blankspaces as delimiters, `null` if no files + * The concatenation of `files` with blankspaces as delimiters, `NULL` if no files */ char* message; @@ -225,13 +273,112 @@ typedef struct args_state char** files; /** - * The number of elements in `args_files` + * The number of elements in `files` */ size_t files_count; + /** + * Options, in order + */ + args_option* options; + + /** + * Number of elements in `options` + */ + size_t options_count; + + /** + * All recognised options + */ + const char** all_options; + + /** + * The standard argument for all recognised options, + * if `all_options_standard[i] == all_options_standard[j]`, + * then `all_options[i]` and `all_options[j]` are synonyms + */ + const char** all_options_standard; + + /** + * Number of elements in `all_options` and `all_options_standard` + */ + size_t all_options_count; + + /** + * Queue of objects that needs to be freed on dispose + */ + void** freequeue; + + /** + * The number of elements in `freequeue` + */ + ssize_t freeptr; + } args_state_t; +/** + * Argument parser class + */ +typedef struct args_parser +{ + /** + * Settings for argument parser + */ + args_settings_t settings; + + /** + * The state of the parser + */ + args_state_t state; + +} args_parser_t; + + + + +/** + * Initialise an argument parser + * + * @param parser The memory address of the parser to initialise + * @return Zero on success, -1 on error, `errno` will be set accordingly + */ +int args_initialise(args_parser_t* parser); + +/** + * Disposes of all resources, run this when you are done + * + * @param parser The parser + */ +void args_dispose(parser_t* parser); + +/** + * Checks the correctness of the number of used non-option arguments + * + * @param parser The parser + * @param min The minimum number of files + * @return Whether the usage was correct + */ +int args_test_files_min(args_parser_t* parser, size_t min); + +/** + * Checks the correctness of the number of used non-option arguments + * + * @param parser The parser + * @param max The maximum number of files + * @return Whether the usage was correct + */ +int args_test_files_max(args_parser_t* parser, size_t max); + +/** + * Checks the correctness of the number of used non-option arguments + * + * @param parser The parser + * @param min The minimum number of files + * @param max The maximum number of files + * @return Whether the usage was correct + */ +int args_test_files(args_parser_t* parser, size_t min, size_t max); /** * Dummy trigger @@ -240,7 +387,7 @@ typedef struct args_state * @param used The used option alternative * @param standard The standard option alternative */ -void args_noop_trigger(void* user_data, const char* used, const char* standard); +void args_noop_trigger(void* user_data, const char* used, const char* standard) ARGS_CONST; /** * Dummy trigger @@ -250,7 +397,7 @@ void args_noop_trigger(void* user_data, const char* used, const char* standard); * @param standard The standard option alternative * @param value The used value */ -void args_noop_trigger_v(void* user_data, const char* used, const char* standard, char* value); +void args_noop_trigger_v(void* user_data, const char* used, const char* standard, char* value) ARGS_CONST; /** * Stickless evaluator to always evaluates to false @@ -259,7 +406,7 @@ void args_noop_trigger_v(void* user_data, const char* used, const char* standard * @param argument The next argument * @return Whether the argument can be used without being sticky */ -int args_no_stickless(void* user_data, const char* value); +int args_no_stickless(void* user_data, const char* value) ARGS_CONST; /** * Default stickless evaluator @@ -268,7 +415,7 @@ int args_no_stickless(void* user_data, const char* value); * @param argument The next argument * @return Whether the argument can be used without being sticky */ -int args_default_stickless(void* user_data, const char* argument); +int args_default_stickless(void* user_data, const char* argument) ARGS_CONST; /** * Evalutator for end argument of variadic options that always evalutes to false @@ -277,20 +424,18 @@ int args_default_stickless(void* user_data, const char* argument); * @param value The next argument * @return Whether the argument can be used without being sticky */ -int args_no_variadic_end(void* user_data, char* value); +int args_no_variadic_end(void* user_data, char* value) ARGS_CONST; /** * The standard abbrevation expander * - * @param argument The option that not recognised - * @param options All recognised options - * @param count The number of elements in `options` - * @return The only possible expansion, otherwise `null` + * @param argument The option that not recognised + * @param standards The corresponding standard option for options in `options` + * @param count The number of elements in `options` and `standards` + * @return The only possible expansion, otherwise `NULL` */ -const char* args_standard_abbreviations(const char* argument, const char** options, size_t count); +const char* args_standard_abbreviations(const char* argument, const char** options, const char** standards, size_t count); #endif - - |