diff options
Diffstat (limited to 'getopt-ul/getopt.c')
-rw-r--r-- | getopt-ul/getopt.c | 472 |
1 files changed, 0 insertions, 472 deletions
diff --git a/getopt-ul/getopt.c b/getopt-ul/getopt.c deleted file mode 100644 index 01a2df6..0000000 --- a/getopt-ul/getopt.c +++ /dev/null @@ -1,472 +0,0 @@ -/* - * getopt.c - Enhanced implementation of BSD getopt(1) - * Copyright (c) 1997-2014 Frodo Looijaard <frodo@frodo.looijaard.name> - * - * 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. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -/* - * Version 1.0-b4: Tue Sep 23 1997. First public release. - * Version 1.0: Wed Nov 19 1997. - * Bumped up the version number to 1.0 - * Fixed minor typo (CSH instead of TCSH) - * Version 1.0.1: Tue Jun 3 1998 - * Fixed sizeof instead of strlen bug - * Bumped up the version number to 1.0.1 - * Version 1.0.2: Thu Jun 11 1998 (not present) - * Fixed gcc-2.8.1 warnings - * Fixed --version/-V option (not present) - * Version 1.0.5: Tue Jun 22 1999 - * Make -u option work (not present) - * Version 1.0.6: Tue Jun 27 2000 - * No important changes - * Version 1.1.0: Tue Jun 30 2000 - * Added NLS support (partly written by Arkadiusz MiĆkiewicz - * <misiek@pld.org.pl>) - * Version 1.1.4: Mon Nov 7 2005 - * Fixed a few type's in the manpage - * Version 1.1.5: Sun Aug 12 2012 - * Sync with util-linux-2.21, fixed build problems, many new translations - * Version 1.1.6: Mon Nov 24 2014 - * Sync with util-linux git 20141120, detect ambiguous long options, fix - * backslash problem in tcsh - */ - -/* Exit codes: - * 0) No errors, successful operation. - * 1) getopt(3) returned an error. - * 2) A problem with parameter parsing for getopt(1). - * 3) Internal error, out of memory - * 4) Returned for -T - */ -#define GETOPT_EXIT_CODE 1 -#define PARAMETER_EXIT_CODE 2 -#define XALLOC_EXIT_CODE 3 -#define CLOSE_EXIT_CODE XALLOC_EXIT_CODE -#define TEST_EXIT_CODE 4 - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <ctype.h> -#include <getopt.h> -#ifdef HAVE_SYS_PARAM_H -# include <sys/param.h> /* BSD */ -#endif - -#include "closestream.h" -#include "nls.h" -#include "xalloc.h" - -/* NON_OPT is the code that is returned getopt(3) when a non-option is - * found in 'char optstring[]="-abc...";', e.g., it begins by '-' */ -#define NON_OPT 1 -/* LONG_OPT is the code that is returned when a long option is found. */ -#define LONG_OPT 0 - -/* The shells recognized. */ -typedef enum { BASH, TCSH } shell_t; - -struct getopt_control { - shell_t shell; /* the shell we generate output for */ - char *optstr; /* getopt(3) optstring */ - char *name; - struct option *long_options; /* long options */ - int long_options_length; /* length of options array */ - int long_options_nr; /* number of used elements in array */ - unsigned int - compatible:1, /* compatibility mode for 'difficult' programs */ - quiet_errors:1, /* print errors */ - quiet_output:1, /* print output */ - quote:1; /* quote output */ -}; - -enum { REALLOC_INCREMENT = 8 }; - -/* Allow changing which getopt is in use with function pointer. */ -static int (*getopt_long_fp) (int argc, char *const *argv, const char *optstr, - const struct option * longopts, int *longindex); - -/* - * This function 'normalizes' a single argument: it puts single quotes - * around it and escapes other special characters. If quote is false, it - * just returns its argument. - * - * Bash only needs special treatment for single quotes; tcsh also recognizes - * exclamation marks within single quotes, and nukes whitespace. This - * function returns a pointer to a buffer that is overwritten by each call. - */ -static void print_normalized(const struct getopt_control *ctl, const char *arg) -{ - char *buf; - const char *argptr = arg; - char *bufptr; - - if (!ctl->quote) { - printf(" %s", arg); - return; - } - - /* - * Each character in arg may take up to four characters in the - * result: For a quote we need a closing quote, a backslash, a quote - * and an opening quote! We need also the global opening and closing - * quote, and one extra character for '\0'. - */ - buf = xmalloc(strlen(arg) * 4 + 3); - bufptr = buf; - - for (*bufptr++ = '\''; *argptr; argptr++) { - if (ctl->shell == TCSH) { - switch (*argptr) { - case '\\': - /* Backslash: replace it with: '\\' */ - *bufptr++ = '\\'; - *bufptr++ = '\\'; - continue; - case '!': - /* Exclamation mark: replace it with: \! */ - *bufptr++ = '\''; - *bufptr++ = '\\'; - *bufptr++ = '!'; - *bufptr++ = '\''; - continue; - case '\n': - /* Newline: replace it with: \n */ - *bufptr++ = '\\'; - *bufptr++ = 'n'; - continue; - } - if (isspace(*argptr)) { - /* Non-newline whitespace: replace it with \<ws> */ - *bufptr++ = '\''; - *bufptr++ = '\\'; - *bufptr++ = *argptr; - *bufptr++ = '\''; - continue; - } - } - if (*argptr == '\'') { - /* Quote: replace it with: '\'' */ - *bufptr++ = '\''; - *bufptr++ = '\\'; - *bufptr++ = '\''; - *bufptr++ = '\''; - } else - /* Just copy */ - *bufptr++ = *argptr; - } - - *bufptr++ = '\''; - *bufptr++ = '\0'; - printf(" %s", buf); - free(buf); -} - -/* - * Generate the output. argv[0] is the program name (used for reporting errors). - * argv[1..] contains the options to be parsed. argc must be the number of - * elements in argv (ie. 1 if there are no options, only the program name), - * optstr must contain the short options, and longopts the long options. - * Other settings are found in global variables. - */ -static int generate_output(struct getopt_control *ctl, char *argv[], int argc) -{ - int exit_code = EXIT_SUCCESS; /* Assume everything will be OK */ - int opt; - int longindex; - const char *charptr; - - if (ctl->quiet_errors) - /* No error reporting from getopt(3) */ - opterr = 0; - /* Reset getopt(3) */ - optind = 0; - - while ((opt = - (getopt_long_fp - (argc, argv, ctl->optstr, - (const struct option *)ctl->long_options, &longindex))) - != EOF) { - if (opt == '?' || opt == ':') - exit_code = GETOPT_EXIT_CODE; - else if (!ctl->quiet_output) { - switch (opt) { - case LONG_OPT: - printf(" --%s", ctl->long_options[longindex].name); - if (ctl->long_options[longindex].has_arg) - print_normalized(ctl, optarg ? optarg : ""); - break; - case NON_OPT: - print_normalized(ctl, optarg ? optarg : ""); - break; - default: - printf(" -%c", opt); - charptr = strchr(ctl->optstr, opt); - if (charptr != NULL && *++charptr == ':') - print_normalized(ctl, optarg ? optarg : ""); - } - } - } - if (!ctl->quiet_output) { - printf(" --"); - while (optind < argc) - print_normalized(ctl, argv[optind++]); - printf("\n"); - } - for (longindex = 0; longindex < ctl->long_options_nr; longindex++) - free((char *)ctl->long_options[longindex].name); - free(ctl->long_options); - free(ctl->optstr); - free(ctl->name); - return exit_code; -} - -/* - * Report an error when parsing getopt's own arguments. If message is NULL, - * we already sent a message, we just exit with a helpful hint. - */ -static void __attribute__ ((__noreturn__)) parse_error(const char *message) -{ - if (message) - warnx("%s", message); - errtryhelp(PARAMETER_EXIT_CODE); -} - - -/* Register a long option. The contents of name is copied. */ -static void add_longopt(struct getopt_control *ctl, const char *name, int has_arg) -{ - static int flag; - int nr = ctl->long_options_nr; - - if (ctl->long_options_nr == ctl->long_options_length) { - ctl->long_options_length += REALLOC_INCREMENT; - ctl->long_options = xrealloc(ctl->long_options, - sizeof(struct option) * - ctl->long_options_length); - } - if (name) { - /* Not for init! */ - ctl->long_options[nr].has_arg = has_arg; - ctl->long_options[nr].flag = &flag; - ctl->long_options[nr].val = ctl->long_options_nr; - ctl->long_options[nr].name = xstrdup(name); - } else { - /* lets use add_longopt(ct, NULL, 0) to terminate the array */ - ctl->long_options[nr].name = NULL; - ctl->long_options[nr].has_arg = 0; - ctl->long_options[nr].flag = NULL; - ctl->long_options[nr].val = 0; - } -} - - -/* - * Register several long options. options is a string of long options, - * separated by commas or whitespace. This nukes options! - */ -static void add_long_options(struct getopt_control *ctl, char *options) -{ - int arg_opt; - char *tokptr = strtok(options, ", \t\n"); - - while (tokptr) { - size_t len = strlen(tokptr); - - arg_opt = no_argument; - if (len > 0) { - if (tokptr[len - 1] == ':') { - if (tokptr[len - 2] == ':') { - tokptr[len - 2] = '\0'; - arg_opt = optional_argument; - } else { - tokptr[len - 1] = '\0'; - arg_opt = required_argument; - } - if (!*tokptr) - parse_error(_ - ("empty long option after " - "-l or --long argument")); - } - add_longopt(ctl, tokptr, arg_opt); - ctl->long_options_nr++; - } - tokptr = strtok(NULL, ", \t\n"); - } - add_longopt(ctl, NULL, 0); /* ensure long_options[] is not full */ -} - -static shell_t shell_type(const char *new_shell) -{ - if (!strcmp(new_shell, "bash")) - return BASH; - if (!strcmp(new_shell, "sh")) - return BASH; - if (!strcmp(new_shell, "tcsh")) - return TCSH; - if (!strcmp(new_shell, "csh")) - return TCSH; - parse_error(_("unknown shell after -s or --shell argument")); -} - -static void __attribute__((__noreturn__)) usage(void) -{ - fputs(USAGE_HEADER, stdout); - printf(_( - " %1$s <optstring> <parameters>\n" - " %1$s [options] [--] <optstring> <parameters>\n" - " %1$s [options] -o|--options <optstring> [options] [--] <parameters>\n"), - program_invocation_short_name); - - fputs(USAGE_SEPARATOR, stdout); - fputs(_("Parse command options.\n"), stdout); - - fputs(USAGE_OPTIONS, stdout); - fputs(_(" -a, --alternative allow long options starting with single -\n"), stdout); - fputs(_(" -l, --longoptions <longopts> the long options to be recognized\n"), stdout); - fputs(_(" -n, --name <progname> the name under which errors are reported\n"), stdout); - fputs(_(" -o, --options <optstring> the short options to be recognized\n"), stdout); - fputs(_(" -q, --quiet disable error reporting by getopt(3)\n"), stdout); - fputs(_(" -Q, --quiet-output no normal output\n"), stdout); - fputs(_(" -s, --shell <shell> set quoting conventions to those of <shell>\n"), stdout); - fputs(_(" -T, --test test for getopt(1) version\n"), stdout); - fputs(_(" -u, --unquoted do not quote the output\n"), stdout); - fputs(USAGE_SEPARATOR, stdout); - printf(USAGE_HELP_OPTIONS(31)); - printf(USAGE_MAN_TAIL("getopt(1)")); - exit(EXIT_SUCCESS); -} - -int main(int argc, char *argv[]) -{ - struct getopt_control ctl = { - .shell = BASH, - .quote = 1 - }; - int opt; - - /* Stop scanning as soon as a non-option argument is found! */ - static const char *shortopts = "+ao:l:n:qQs:TuhV"; - static const struct option longopts[] = { - {"options", required_argument, NULL, 'o'}, - {"longoptions", required_argument, NULL, 'l'}, - {"quiet", no_argument, NULL, 'q'}, - {"quiet-output", no_argument, NULL, 'Q'}, - {"shell", required_argument, NULL, 's'}, - {"test", no_argument, NULL, 'T'}, - {"unquoted", no_argument, NULL, 'u'}, - {"help", no_argument, NULL, 'h'}, - {"alternative", no_argument, NULL, 'a'}, - {"name", required_argument, NULL, 'n'}, - {"version", no_argument, NULL, 'V'}, - {NULL, 0, NULL, 0} - }; - - setlocale(LC_ALL, ""); - bindtextdomain(PACKAGE, LOCALEDIR); - textdomain(PACKAGE); - close_stdout_atexit(); - - if (getenv("GETOPT_COMPATIBLE")) - ctl.compatible = 1; - - if (argc == 1) { - if (ctl.compatible) { - /* - * For some reason, the original getopt gave no - * error when there were no arguments. - */ - printf(" --\n"); - return EXIT_SUCCESS; - } - parse_error(_("missing optstring argument")); - } - - add_longopt(&ctl, NULL, 0); /* init */ - getopt_long_fp = getopt_long; - - if (argv[1][0] != '-' || ctl.compatible) { - ctl.quote = 0; - ctl.optstr = xmalloc(strlen(argv[1]) + 1); - strcpy(ctl.optstr, argv[1] + strspn(argv[1], "-+")); - argv[1] = argv[0]; - return generate_output(&ctl, argv + 1, argc - 1); - } - - while ((opt = - getopt_long(argc, argv, shortopts, longopts, NULL)) != EOF) - switch (opt) { - case 'a': - getopt_long_fp = getopt_long_only; - break; - case 'o': - free(ctl.optstr); - ctl.optstr = xstrdup(optarg); - break; - case 'l': - add_long_options(&ctl, optarg); - break; - case 'n': - free(ctl.name); - ctl.name = xstrdup(optarg); - break; - case 'q': - ctl.quiet_errors = 1; - break; - case 'Q': - ctl.quiet_output = 1; - break; - case 's': - ctl.shell = shell_type(optarg); - break; - case 'T': - free(ctl.long_options); - return TEST_EXIT_CODE; - case 'u': - ctl.quote = 0; - break; - - case 'V': - print_version(EXIT_SUCCESS); - case '?': - case ':': - parse_error(NULL); - case 'h': - usage(); - default: - parse_error(_("internal error, contact the author.")); - } - - if (!ctl.optstr) { - if (optind >= argc) - parse_error(_("missing optstring argument")); - else { - ctl.optstr = xstrdup(argv[optind]); - optind++; - } - } - - if (ctl.name) { - argv[optind - 1] = ctl.name; -#if defined (HAVE_SETPROGNAME) && !defined (__linux__) - setprogname(ctl.name); -#endif - } else - argv[optind - 1] = argv[0]; - - return generate_output(&ctl, argv + optind - 1, argc - optind + 1); -} |