aboutsummaryrefslogtreecommitdiffstats
path: root/src/libargparser
diff options
context:
space:
mode:
Diffstat (limited to 'src/libargparser')
-rw-r--r--src/libargparser/argparser.c169
-rw-r--r--src/libargparser/argparser.h185
2 files changed, 314 insertions, 40 deletions
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
-
-