Anastasia Klimchuk has submitted this change. ( https://review.coreboot.org/c/flashrom/+/73102 )
(
10 is the latest approved patch-set. No files were changed between the latest approved patch-set and the submitted one. )Change subject: cli_classic: include a fallback inplementation of getopt ......................................................................
cli_classic: include a fallback inplementation of getopt
Some systems, DJGPP/DOS for now, may not provide getopt and their gnu extensions. So provide a fallback implementation. The code is based on musl libc.
Change-Id: I6ebbde075014e3b45b0f9e04b34b72aa969e1197 Signed-off-by: Thomas Heijligen thomas.heijligen@secunet.com Reviewed-on: https://review.coreboot.org/c/flashrom/+/73102 Reviewed-by: Anastasia Klimchuk aklm@chromium.org Tested-by: build bot (Jenkins) no-reply@coreboot.org --- M cli_classic.c A cli_getopt.c A include/cli_classic.h M meson.build 4 files changed, 336 insertions(+), 6 deletions(-)
Approvals: build bot (Jenkins): Verified Anastasia Klimchuk: Looks good to me, approved
diff --git a/cli_classic.c b/cli_classic.c index e4db913..d804cae 100644 --- a/cli_classic.c +++ b/cli_classic.c @@ -24,7 +24,7 @@ #include <string.h> #include <stdbool.h> #include <stdlib.h> -#include <getopt.h> +#include <cli_classic.h> #include "flash.h" #include "flashchips.h" #include "fmap.h" diff --git a/cli_getopt.c b/cli_getopt.c new file mode 100644 index 0000000..fc51fcf --- /dev/null +++ b/cli_getopt.c @@ -0,0 +1,263 @@ +/* + * This file is part of the flashrom project. + * It comes originally from the musl libc project and is licensed under the + * terms of the MIT license. + * + * Copyringht (C) 2023 Rich Felker and the musl authors + * Adjusted for flashrom by Thomas Heijligenthomas.heijligen@secunet.com + * + * 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 <unistd.h> +#include <wchar.h> +#include <string.h> +#include <limits.h> +#include <stdlib.h> +#include "cli_classic.h" +#include "flash.h" + +char *optarg; +int optind=1, opterr=1, optopt, optpos; + +static void getopt_msg(const char *a, const char *b, const char *c, size_t l) +{ + msg_gerr("%s%s%*c\n", a, b, l, c); +} + +int getopt(int argc, char * const argv[], const char *optstring) +{ + int i; + wchar_t c, d; + int k, l; + char *optchar; + + if (!optind) { + optind = 1; + optpos = 0; + } + + 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++; + if ((k = mbtowc(&c, argv[optind]+optpos, MB_LEN_MAX)) < 0) { + k = 1; + c = 0xfffd; /* replacement char */ + } + optchar = argv[optind]+optpos; + optpos += k; + + if (!argv[optind][optpos]) { + optind++; + optpos = 0; + } + + if (optstring[0] == '-' || optstring[0] == '+') + optstring++; + + i = 0; + d = 0; + do { + l = mbtowc(&d, optstring+i, MB_LEN_MAX); + if (l>0) i+=l; else i++; + } while (l && d != c); + + if (d != c || c == ':') { + optopt = c; + if (optstring[0] != ':' && opterr) + getopt_msg(argv[0], ": unrecognized option: ", optchar, k); + return '?'; + } + if (optstring[i] == ':') { + optarg = 0; + if (optstring[i+1] != ':' || optpos) { + optarg = argv[optind++] + optpos; + optpos = 0; + } + if (optind > argc) { + optopt = c; + if (optstring[0] == ':') + return ':'; + if (opterr) getopt_msg(argv[0], + ": option requires an argument: ", + optchar, k); + return '?'; + } + } + return c; +} + +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 = 0; + char *arg = NULL, *opt, *start = argv[optind]+1; + for (cnt=i=0; longopts[i].name; i++) { + const char *name = longopts[i].name; + opt = start; + if (*opt == '-') opt++; + while (*opt && *opt != '=' && *opt == *name) + name++, opt++; + if (*opt && *opt != '=') continue; + arg = opt; + match = i; + if (!*name) { + cnt = 1; + break; + } + cnt++; + } + if (cnt==1 && longonly && arg-start == mblen(start, MB_LEN_MAX)) { + int l = arg-start; + for (i=0; optstring[i]; i++) { + int j; + for (j=0; j<l && start[j]==optstring[i+j]; j++); + if (j==l) { + cnt++; + break; + } + } + } + if (cnt==1) { + i = match; + opt = arg; + optind++; + if (*opt == '=') { + if (!longopts[i].has_arg) { + optopt = longopts[i].val; + 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])) { + optopt = longopts[i].val; + 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] == '-') { + optopt = 0; + 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 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(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly) +{ + int ret, skipped, resumed; + if (!optind) { + optind = 1; + optpos = 0; + } + + 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/include/cli_classic.h b/include/cli_classic.h new file mode 100644 index 0000000..e651cc6 --- /dev/null +++ b/include/cli_classic.h @@ -0,0 +1,43 @@ +/* + * This file is part of the flashrom project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef CLI_CLASSIC_H +#define CLI_CLASSIC_H + +#if __has_include(<getopt.h>) +#include <getopt.h> +#else + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +extern char *optarg; +extern int optind, opterr, optopt; + +struct option { + const char *name; + int has_arg; + int *flag; + int val; +}; + +int getopt (int argc, char *const *argv, const char *shortopts); +int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +int getopt_long_only (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); + +#endif /* __has_include() */ +#endif /* CLI_CLASSIC_H */ diff --git a/meson.build b/meson.build index 4341ccf..b7d578f 100644 --- a/meson.build +++ b/meson.build @@ -633,13 +633,20 @@ )
if get_option('classic_cli').enabled() or get_option('classic_cli').auto() and not get_option('default_library') == 'shared' + + cli_srcs = files( + 'cli_classic.c', + 'cli_common.c', + 'cli_output.c' + ) + + if not cc.has_function('getopt_long') + cli_srcs += files('cli_getopt.c') + endif + classic_cli = executable( 'flashrom', - files( - 'cli_classic.c', - 'cli_common.c', - 'cli_output.c', - ), + cli_srcs, c_args : cargs, include_directories : include_dir, install : true,