From 0e6df6e921c94390a2386b54941baa53cc67d7d7 Mon Sep 17 00:00:00 2001 From: Tyge Løvset <60263450+tylo-work@users.noreply.github.com> Date: Mon, 30 Mar 2020 21:41:38 +0200 Subject: Add files via upload --- c_lib/cgetopt.h | 50 ++++++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/c_lib/cgetopt.h b/c_lib/cgetopt.h index ae154603..1013cd05 100644 --- a/c_lib/cgetopt.h +++ b/c_lib/cgetopt.h @@ -20,6 +20,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +// Inspired by https://attractivechaos.wordpress.com/2018/08/31/a-survey-of-argument-parsing-libraries-in-c-c +// Fixed major bugs with option arguments (both long and short), and shows a useful demo of the features. +// Has a more consistent API, written in C99. + #ifndef CGETOPT__H__ #define CGETOPT__H__ @@ -32,10 +36,10 @@ enum { copt_optional_argument = 2 }; typedef struct { - int ind; /* equivalent to optind */ - int opt; /* equivalent to optopt */ - char *arg; /* equivalent to optarg */ - int longidx; /* index of a long option; or -1 if short */ + int ind; // equivalent to optind + int opt; // equivalent to optopt + char *arg; // equivalent to optarg + int longidx; // index of a long option; or -1 if short int _i, _pos, _nargs; } copt_t; @@ -47,7 +51,7 @@ struct copt_option { static const copt_t copt_init = {1, 0, 0, -1, 1, 0, 0}; -static void _copt_permute(char *argv[], int j, int n) { /* move argv[j] over n elements to the left */ +static void _copt_permute(char *argv[], int j, int n) { // move argv[j] over n elements to the left int k; char *p = argv[j]; for (k = 0; k < n; ++k) @@ -57,20 +61,15 @@ static void _copt_permute(char *argv[], int j, int n) { /* move argv[j] over n e // Parse command-line options and arguments -// +// // This fuction has a similar interface to GNU's getopt_long(). Each call -// parses one option and returns the option name. st->arg points to the option +// parses one option and returns the option name. opt->arg points to the option // argument if present. The function returns -1 when all command-line arguments -// are parsed. In this case, st->ind is the index of the first non-option +// are parsed. In this case, opt->ind is the index of the first non-option // argument. // -// @param opt output; must be initialized to copt_init before first call -// @param argc length of argv[] -// @param argv list of command-line arguments; argv[0] is ignored -// @param shortopts short options string -// @param longopts long options struct +// @param opt output; must be initialized to copt_init on first call // @param permute true: move options ahead of non-option arguments -// // @return ASCII val for a short option; longopt.val for a long option; // -1 if argv[] is fully processed; '?' for an unknown option or // an ambiguous long option; ':' if an option argument is missing @@ -88,17 +87,17 @@ static int copt_getopt(copt_t *opt, int argc, char *argv[], opt->ind = opt->_i - opt->_nargs; return -1; } - if (argv[opt->_i][0] == '-' && argv[opt->_i][1] == '-') { /* "--" or a long option */ - if (argv[opt->_i][2] == '\0') { /* a bare "--" */ + if (argv[opt->_i][0] == '-' && argv[opt->_i][1] == '-') { // "--" or a long option + if (argv[opt->_i][2] == '\0') { // a bare "--" _copt_permute(argv, opt->_i, opt->_nargs); ++opt->_i, opt->ind = opt->_i - opt->_nargs; return -1; } opt->opt = 0, optc = '?', opt->_pos = -1; - if (longopts) { /* parse long options */ + if (longopts) { // parse long options int k, n_exact = 0, n_partial = 0; const struct copt_option *o = 0, *o_exact = 0, *o_partial = 0; - for (j = 2; argv[opt->_i][j] != '\0' && argv[opt->_i][j] != '='; ++j) {} /* find the end of the option name */ + for (j = 2; argv[opt->_i][j] != '\0' && argv[opt->_i][j] != '='; ++j) {} // find the end of the option name for (k = 0; longopts[k].name != 0; ++k) if (strncmp(&argv[opt->_i][2], longopts[k].name, j - 2) == 0) { if (longopts[k].name[j - 2] == 0) ++n_exact, o_exact = &longopts[k]; @@ -114,30 +113,30 @@ static int copt_getopt(copt_t *opt, int argc, char *argv[], else if (argv[opt->_i][j] == '\0' && opt->_i < argc - 1 && argv[opt->_i + 1][0] != '-') opt->arg = argv[++opt->_i]; else if (o->has_arg == copt_required_argument) - optc = ':'; /* missing option argument */ + optc = ':'; // missing option argument } } } - } else { /* a short option */ + } else { // a short option const char *p; if (opt->_pos == 0) opt->_pos = 1; optc = opt->opt = argv[opt->_i][opt->_pos++]; p = strchr((char *) shortopts, optc); if (p == 0) { - optc = '?'; /* unknown option */ + optc = '?'; // unknown option } else if (p[1] == ':') { if (argv[opt->_i][opt->_pos] != '\0') opt->arg = &argv[opt->_i][opt->_pos]; else if (opt->_i < argc - 1 && argv[opt->_i + 1][0] != '-') opt->arg = argv[++opt->_i]; else if (p[2] != ':') - optc = ':'; // missing option argument + optc = ':'; opt->_pos = -1; } } if (opt->_pos < 0 || argv[opt->_i][opt->_pos] == 0) { ++opt->_i, opt->_pos = 0; - if (opt->_nargs > 0) /* permute */ + if (opt->_nargs > 0) // permute for (j = i0; j < opt->_i; ++j) _copt_permute(argv, j, opt->_nargs); } @@ -154,8 +153,8 @@ static int copt_getopt(copt_t *opt, int argc, char *argv[], {"opt", copt_optional_argument, 'o'}, {NULL} }; - const char* optstr = "a:b::c"; - printf("program -a arg -b [arg] -c --opt [arg] --foo --bar arg [arguments]\n"); + const char* optstr = "ab:c::"; + printf("program -a -b ARG -c [ARG] --foo --bar ARG --opt [ARG] [ARGUMENTS]\n"); int c; copt_t opt = copt_init; while ((c = copt_getopt(&opt, argc, argv, optstr, longopts, true)) != -1) { @@ -176,5 +175,4 @@ static int copt_getopt(copt_t *opt, int argc, char *argv[], } */ - #endif -- cgit v1.2.3