From aaf8c093191c94cfa2af7d0853a7da10462b81de Mon Sep 17 00:00:00 2001 From: Phuntsok Drak-pa Date: Sun, 29 Apr 2018 14:11:56 +0200 Subject: [PATCH] Added portable getopt --- CMakeLists.txt | 2 +- includes/getopt.c | 244 ++++++++++++++++++++++++++++++++++++++++++++++ includes/getopt.h | 54 ++++++++++ 3 files changed, 299 insertions(+), 1 deletion(-) create mode 100644 includes/getopt.c create mode 100644 includes/getopt.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ac461b..9cfe5ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "../debug/") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_COVERAGE_COMPILE_FLAGS}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${CXX_COVERAGE_COMPILE_FLAGS}") -include_directories(include) +include_directories(includes) file(GLOB SOURCES "src/*.cc") add_executable(${TGT} ${SOURCES}) diff --git a/includes/getopt.c b/includes/getopt.c new file mode 100644 index 0000000..b2a08a5 --- /dev/null +++ b/includes/getopt.c @@ -0,0 +1,244 @@ +/* + Copyright 2005-2014 Rich Felker, et al. + + 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. +*/ + +#include "getopt.h" +#include +#include +#include + +char *optarg; +int optind = 1, opterr = 1, optopt, __optpos, optreset = 0; + +#define optpos __optpos + +static void __getopt_msg(const char *a, const char *b, const char *c, + size_t l) { + FILE *f = stderr; + flockfile(f); + fputs(a, f) >= 0 && fwrite(b, strlen(b), 1, f) && + fwrite(c, 1, l, f) == l &&putc('\n', f); + funlockfile(f); +} + +int getopt(int argc, char *const argv[], const char *optstring) { + int i, c, d; + int k, l; + char *optchar; + + if (!optind || optreset) { + optreset = 0; + __optpos = 0; + optind = 1; + } + + if (optind >= argc || !argv[optind]) + return -1; + + if (argv[optind][0] != '-') { + if (optstring[0] == '-') { + optarg = argv[optind++]; + return 1; + } + return -1; + } + + if (!argv[optind][1]) + return -1; + + if (argv[optind][1] == '-' && !argv[optind][2]) + return optind++, -1; + + if (!optpos) + optpos++; + c = argv[optind][optpos], k = 1; + optchar = argv[optind] + optpos; + optopt = c; + optpos += k; + + if (!argv[optind][optpos]) { + optind++; + optpos = 0; + } + + if (optstring[0] == '-' || optstring[0] == '+') + optstring++; + + i = 0; + d = 0; + do { + d = optstring[i], l = 1; + if (l > 0) + i += l; + else + i++; + } while (l && d != c); + + if (d != c) { + if (optstring[0] != ':' && opterr) + __getopt_msg(argv[0], ": unrecognized option: ", optchar, k); + return '?'; + } + if (optstring[i] == ':') { + if (optstring[i + 1] == ':') + optarg = 0; + else if (optind >= argc) { + if (optstring[0] == ':') + return ':'; + if (opterr) + __getopt_msg(argv[0], ": option requires an argument: ", optchar, k); + return '?'; + } + if (optstring[i + 1] != ':' || optpos) { + optarg = argv[optind++] + optpos; + optpos = 0; + } + } + return c; +} + +static void permute(char *const *argv, int dest, int src) { + char **av = (char **)argv; + char *tmp = av[src]; + int i; + for (i = src; i > dest; i--) + av[i] = av[i - 1]; + av[dest] = tmp; +} + +static int __getopt_long_core(int argc, char *const *argv, + const char *optstring, + const struct option *longopts, int *idx, + int longonly) { + optarg = 0; + if (longopts && argv[optind][0] == '-' && + ((longonly && argv[optind][1] && argv[optind][1] != '-') || + (argv[optind][1] == '-' && argv[optind][2]))) { + int colon = optstring[optstring[0] == '+' || optstring[0] == '-'] == ':'; + int i, cnt, match; + char *opt; + for (cnt = i = 0; longopts[i].name; i++) { + const char *name = longopts[i].name; + opt = argv[optind] + 1; + if (*opt == '-') + opt++; + for (; *name && *name == *opt; name++, opt++) + ; + if (*opt && *opt != '=') + continue; + match = i; + if (!*name) { + cnt = 1; + break; + } + cnt++; + } + if (cnt == 1) { + i = match; + optind++; + optopt = longopts[i].val; + if (*opt == '=') { + if (!longopts[i].has_arg) { + if (colon || !opterr) + return '?'; + __getopt_msg(argv[0], + ": option does not take an argument: ", longopts[i].name, + strlen(longopts[i].name)); + return '?'; + } + optarg = opt + 1; + } else if (longopts[i].has_arg == required_argument) { + if (!(optarg = argv[optind])) { + if (colon) + return ':'; + if (!opterr) + return '?'; + __getopt_msg(argv[0], + ": option requires an argument: ", longopts[i].name, + strlen(longopts[i].name)); + return '?'; + } + optind++; + } + if (idx) + *idx = i; + if (longopts[i].flag) { + *longopts[i].flag = longopts[i].val; + return 0; + } + return longopts[i].val; + } + if (argv[optind][1] == '-') { + if (!colon && opterr) + __getopt_msg(argv[0], + cnt ? ": option is ambiguous: " + : ": unrecognized option: ", + argv[optind] + 2, strlen(argv[optind] + 2)); + optind++; + return '?'; + } + } + return getopt(argc, argv, optstring); +} + +static int __getopt_long(int argc, char *const *argv, const char *optstring, + const struct option *longopts, int *idx, + int longonly) { + int ret, skipped, resumed; + if (!optind || optreset) { + optreset = 0; + __optpos = 0; + optind = 1; + } + if (optind >= argc || !argv[optind]) + return -1; + skipped = optind; + if (optstring[0] != '+' && optstring[0] != '-') { + int i; + for (i = optind;; i++) { + if (i >= argc || !argv[i]) + return -1; + if (argv[i][0] == '-' && argv[i][1]) + break; + } + optind = i; + } + resumed = optind; + ret = __getopt_long_core(argc, argv, optstring, longopts, idx, longonly); + if (resumed > skipped) { + int i, cnt = optind - resumed; + for (i = 0; i < cnt; i++) + permute(argv, skipped, optind - 1); + optind = skipped + cnt; + } + return ret; +} + +int getopt_long(int argc, char *const *argv, const char *optstring, + const struct option *longopts, int *idx) { + return __getopt_long(argc, argv, optstring, longopts, idx, 0); +} + +int getopt_long_only(int argc, char *const *argv, const char *optstring, + const struct option *longopts, int *idx) { + return __getopt_long(argc, argv, optstring, longopts, idx, 1); +} diff --git a/includes/getopt.h b/includes/getopt.h new file mode 100644 index 0000000..5c8545d --- /dev/null +++ b/includes/getopt.h @@ -0,0 +1,54 @@ +/* + Copyright 2005-2014 Rich Felker, et al. + + 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. +*/ + +#ifndef _GETOPT_H +#define _GETOPT_H + +#ifdef __cplusplus +extern "C" { +#endif + +int getopt(int, char *const[], const char *); +extern char *optarg; +extern int optind, opterr, optopt, optreset; + +struct option { + const char *name; + int has_arg; + int *flag; + int val; +}; + +int getopt_long(int, char *const *, const char *, const struct option *, int *); +int getopt_long_only(int, char *const *, const char *, const struct option *, + int *); + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#ifdef __cplusplus +} +#endif + +#endif