From 86fdabc60e2791c6b93a8a893ddf7820e6f0a06f Mon Sep 17 00:00:00 2001 From: Tyge Løvset <60263450+tylo-work@users.noreply.github.com> Date: Tue, 31 Mar 2020 20:43:54 +0200 Subject: Rename cgetopt.h to copt.h --- ccl/cgetopt.h | 179 ---------------------------------------------------------- ccl/copt.h | 179 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+), 179 deletions(-) delete mode 100644 ccl/cgetopt.h create mode 100644 ccl/copt.h diff --git a/ccl/cgetopt.h b/ccl/cgetopt.h deleted file mode 100644 index 2e3aa73c..00000000 --- a/ccl/cgetopt.h +++ /dev/null @@ -1,179 +0,0 @@ -// MIT License -// -// Copyright (c) 2020 Tyge Løvset, NORCE, www.norceresearch.no -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// 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__ - -#include -#include - -enum { - copt_no_argument = 0, - copt_required_argument = 1, - copt_optional_argument = 2 -}; -typedef struct { - int ind; // equivalent to optind - int opt; // equivalent to optopt - char *arg; // equivalent to optarg - char *err; // points to the faulty option - int longidx; // index of a long option; or -1 if short - int _i, _pos, _nargs; - char _err[4]; -} copt_t; - -struct copt_option { - char *name; - int has_arg; - int val; -}; - -static const copt_t copt_init = {1, 0, NULL, NULL, -1, 1, 0, 0, {'-', 0, 0, 0}}; - -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) - argv[j - k] = argv[j - k - 1]; - argv[j - k] = p; -} - - -// 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. opt->arg points to the option -// argument if present. The function returns -1 when all command-line arguments -// 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 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 -// -static int copt_getopt(copt_t *opt, int argc, char *argv[], - const char *shortopts, const struct copt_option *longopts, - bool permute) { - int optc = -1, i0, j; - if (permute) { - while (opt->_i < argc && (argv[opt->_i][0] != '-' || argv[opt->_i][1] == '\0')) - ++opt->_i, ++opt->_nargs; - } - opt->arg = 0, opt->longidx = -1, i0 = opt->_i; - if (opt->_i >= argc || argv[opt->_i][0] != '-' || argv[opt->_i][1] == '\0') { - 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 "--" - _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 - 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 (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]; - else ++n_partial, o_partial = &longopts[k]; - } - opt->err = argv[opt->_i]; - if (n_exact > 1 || (n_exact == 0 && n_partial > 1)) return '?'; - o = n_exact == 1? o_exact : n_partial == 1? o_partial : 0; - if (o) { - opt->opt = optc = o->val, opt->longidx = o - longopts; - if (o->has_arg != copt_no_argument) { - if (argv[opt->_i][j] == '=') - opt->arg = &argv[opt->_i][j + 1]; - else if (argv[opt->_i][j] == '\0' && opt->_i < argc - 1 && (o->has_arg == copt_required_argument || argv[opt->_i + 1][0] != '-')) - opt->arg = argv[++opt->_i]; - else if (o->has_arg == copt_required_argument) - optc = ':'; // missing option argument - } - } - } - } else { // a short option - const char *p; - if (opt->_pos == 0) opt->_pos = 1; - optc = opt->opt = argv[opt->_i][opt->_pos++]; - opt->_err[1] = optc, opt->err = opt->_err; - p = strchr((char *) shortopts, optc); - if (p == 0) { - 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 && (p[2] != ':' || argv[opt->_i + 1][0] != '-')) - opt->arg = argv[++opt->_i]; - else if (p[2] != ':') - optc = ':'; - opt->_pos = -1; - } - } - if (opt->_pos < 0 || argv[opt->_i][opt->_pos] == 0) { - ++opt->_i, opt->_pos = 0; - if (opt->_nargs > 0) // permute - for (j = i0; j < opt->_i; ++j) - _copt_permute(argv, j, opt->_nargs); - } - opt->ind = opt->_i - opt->_nargs; - return optc; -} - -/* // demo: - int main(int argc, char *argv[]) - { - static struct copt_option longopts[] = { - {"foo", copt_no_argument, 'f'}, - {"bar", copt_required_argument, 'b'}, - {"opt", copt_optional_argument, 'o'}, - {NULL} - }; - const char* optstr = "xy:z::123"; - printf("program -x -y ARG -z [ARG] -1 -2 -3 --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) { - switch (c) { - case '?': printf("error: unknown option: %s\n", opt.err); break; - case ':': printf("error: missing argument for %s\n", opt.err); break; - default: printf("option: %c [%s]\n", c, opt.arg ? opt.arg : ""); break; - } - } - printf("\nNon-option arguments:"); - for (int i = opt.ind; i < argc; ++i) - printf(" %s", argv[i]); - putchar('\n'); - return 0; - } -*/ - -#endif diff --git a/ccl/copt.h b/ccl/copt.h new file mode 100644 index 00000000..2e3aa73c --- /dev/null +++ b/ccl/copt.h @@ -0,0 +1,179 @@ +// MIT License +// +// Copyright (c) 2020 Tyge Løvset, NORCE, www.norceresearch.no +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// 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__ + +#include +#include + +enum { + copt_no_argument = 0, + copt_required_argument = 1, + copt_optional_argument = 2 +}; +typedef struct { + int ind; // equivalent to optind + int opt; // equivalent to optopt + char *arg; // equivalent to optarg + char *err; // points to the faulty option + int longidx; // index of a long option; or -1 if short + int _i, _pos, _nargs; + char _err[4]; +} copt_t; + +struct copt_option { + char *name; + int has_arg; + int val; +}; + +static const copt_t copt_init = {1, 0, NULL, NULL, -1, 1, 0, 0, {'-', 0, 0, 0}}; + +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) + argv[j - k] = argv[j - k - 1]; + argv[j - k] = p; +} + + +// 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. opt->arg points to the option +// argument if present. The function returns -1 when all command-line arguments +// 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 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 +// +static int copt_getopt(copt_t *opt, int argc, char *argv[], + const char *shortopts, const struct copt_option *longopts, + bool permute) { + int optc = -1, i0, j; + if (permute) { + while (opt->_i < argc && (argv[opt->_i][0] != '-' || argv[opt->_i][1] == '\0')) + ++opt->_i, ++opt->_nargs; + } + opt->arg = 0, opt->longidx = -1, i0 = opt->_i; + if (opt->_i >= argc || argv[opt->_i][0] != '-' || argv[opt->_i][1] == '\0') { + 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 "--" + _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 + 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 (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]; + else ++n_partial, o_partial = &longopts[k]; + } + opt->err = argv[opt->_i]; + if (n_exact > 1 || (n_exact == 0 && n_partial > 1)) return '?'; + o = n_exact == 1? o_exact : n_partial == 1? o_partial : 0; + if (o) { + opt->opt = optc = o->val, opt->longidx = o - longopts; + if (o->has_arg != copt_no_argument) { + if (argv[opt->_i][j] == '=') + opt->arg = &argv[opt->_i][j + 1]; + else if (argv[opt->_i][j] == '\0' && opt->_i < argc - 1 && (o->has_arg == copt_required_argument || argv[opt->_i + 1][0] != '-')) + opt->arg = argv[++opt->_i]; + else if (o->has_arg == copt_required_argument) + optc = ':'; // missing option argument + } + } + } + } else { // a short option + const char *p; + if (opt->_pos == 0) opt->_pos = 1; + optc = opt->opt = argv[opt->_i][opt->_pos++]; + opt->_err[1] = optc, opt->err = opt->_err; + p = strchr((char *) shortopts, optc); + if (p == 0) { + 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 && (p[2] != ':' || argv[opt->_i + 1][0] != '-')) + opt->arg = argv[++opt->_i]; + else if (p[2] != ':') + optc = ':'; + opt->_pos = -1; + } + } + if (opt->_pos < 0 || argv[opt->_i][opt->_pos] == 0) { + ++opt->_i, opt->_pos = 0; + if (opt->_nargs > 0) // permute + for (j = i0; j < opt->_i; ++j) + _copt_permute(argv, j, opt->_nargs); + } + opt->ind = opt->_i - opt->_nargs; + return optc; +} + +/* // demo: + int main(int argc, char *argv[]) + { + static struct copt_option longopts[] = { + {"foo", copt_no_argument, 'f'}, + {"bar", copt_required_argument, 'b'}, + {"opt", copt_optional_argument, 'o'}, + {NULL} + }; + const char* optstr = "xy:z::123"; + printf("program -x -y ARG -z [ARG] -1 -2 -3 --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) { + switch (c) { + case '?': printf("error: unknown option: %s\n", opt.err); break; + case ':': printf("error: missing argument for %s\n", opt.err); break; + default: printf("option: %c [%s]\n", c, opt.arg ? opt.arg : ""); break; + } + } + printf("\nNon-option arguments:"); + for (int i = opt.ind; i < argc; ++i) + printf(" %s", argv[i]); + putchar('\n'); + return 0; + } +*/ + +#endif -- cgit v1.2.3