--- getopt/trunk/getopt.c 2012/07/14 22:22:44 320 +++ getopt/trunk/getopt.c 2014/11/24 12:23:18 374 @@ -1,6 +1,6 @@ /* * getopt.c - Enhanced implementation of BSD getopt(1) - * Copyright (c) 1997-2005 Frodo Looijaard + * Copyright (c) 1997-2014 Frodo Looijaard * * 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 @@ -12,14 +12,14 @@ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * 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. + * 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 @@ -33,14 +33,19 @@ * 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 Mikiewicz + * Added NLS support (partly written by Arkadiusz Miƛkiewicz * ) * 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: ??? 2014 + * Sync with util-linux git 20141120, detect ambiguous long options, fix + * backslash problem in tcsh */ /* Exit codes: - * 0) No errors, succesful operation. + * 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 @@ -63,60 +68,39 @@ #include "getopt.h" #endif +#include "util-linux-compat.h" #include "nls.h" +#include "xalloc.h" -/* NON_OPT is the code that is returned when a non-option is found in '+' +/* NON_OPT is the code that is returned when a non-option is found in '+' * mode */ #define NON_OPT 1 /* LONG_OPT is the code that is returned when a long option is found. */ -#define LONG_OPT 2 +#define LONG_OPT 0 /* The shells recognized. */ typedef enum { BASH, TCSH } shell_t; /* Some global variables that tells us how to parse. */ -shell_t shell = BASH; /* The shell we generate output for. */ -int quiet_errors = 0; /* 0 is not quiet. */ -int quiet_output = 0; /* 0 is not quiet. */ -int quote = 1; /* 1 is do quote. */ +static shell_t shell = BASH; /* The shell we generate output for. */ +static int quiet_errors = 0; /* 0 is not quiet. */ +static int quiet_output = 0; /* 0 is not quiet. */ +static int quote = 1; /* 1 is do quote. */ +/* Allow changing which getopt is in use with function pointer */ int (*getopt_long_fp) (int argc, char *const *argv, const char *optstr, const struct option * longopts, int *longindex); /* Function prototypes */ -void *our_malloc(size_t size); -void *our_realloc(void *ptr, size_t size); -const char *normalize(const char *arg); -int generate_output(char * argv[], int argc, const char *optstr, - const struct option *longopts); -int main(int argc, char *argv[]); -void parse_error(const char *message); -void add_long_options(char *options); -void add_longopt(const char *name, int has_arg); -void print_help(void); -void set_shell(const char *new_shell); -void set_initial_shell(void); - -void *our_malloc(size_t size) -{ - void *ret=malloc(size); - if (! ret) { - fprintf(stderr, ("%s: Out of memory!\n"), "getopt"); - exit(XALLOC_EXIT_CODE); - } - return(ret); -} - -void *our_realloc(void *ptr, size_t size) -{ - void *ret=realloc(ptr, size); - if (! ret && size) { - fprintf(stderr, ("%s: Out of memory!\n"), "getopt"); - exit(XALLOC_EXIT_CODE); - } - return(ret); -} +static const char *normalize(const char *arg); +static int generate_output(char *argv[], int argc, const char *optstr, + const struct option *longopts); +static void parse_error(const char *message); +static void add_long_options(char *options); +static void add_longopt(const char *name, int has_arg); +static void print_help(void); +static void set_shell(const char *new_shell); /* * This function 'normalizes' a single argument: it puts single quotes @@ -127,30 +111,28 @@ * exclamation marks within single quotes, and nukes whitespace. This * function returns a pointer to a buffer that is overwritten by each call. */ -const char *normalize(const char *arg) +static const char *normalize(const char *arg) { static char *BUFFER = NULL; const char *argptr = arg; char *bufptr; - if (BUFFER != NULL) - free(BUFFER); + free(BUFFER); if (!quote) { /* Just copy arg */ - BUFFER = our_malloc(strlen(arg)+1); - + BUFFER = xmalloc(strlen(arg) + 1); strcpy(BUFFER, arg); return BUFFER; } /* - * Each character in arg may take upto four characters in the + * 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'. */ - BUFFER = our_malloc(strlen(arg)*4+3); + BUFFER = xmalloc(strlen(arg) * 4 + 3); bufptr = BUFFER; *bufptr++ = '\''; @@ -162,6 +144,10 @@ *bufptr++ = '\\'; *bufptr++ = '\''; *bufptr++ = '\''; + } else if (shell == TCSH && *argptr == '\\') { + /* Backslash: replace it with: '\\' */ + *bufptr++ = '\\'; + *bufptr++ = '\\'; } else if (shell == TCSH && *argptr == '!') { /* Exclamation mark: replace it with: \! */ *bufptr++ = '\''; @@ -188,15 +174,15 @@ return BUFFER; } -/* +/* * 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. */ -int generate_output(char * argv[], int argc, const char *optstr, - const struct option *longopts) +static int generate_output(char *argv[], int argc, const char *optstr, + const struct option *longopts) { int exit_code = EXIT_SUCCESS; /* Assume everything will be OK */ int opt; @@ -220,7 +206,7 @@ if (longopts[longindex].has_arg) printf(" %s", normalize(optarg ? optarg : "")); } else if (opt == NON_OPT) - printf(" %s", normalize(optarg)); + printf(" %s", normalize(optarg ? optarg : "")); else { printf(" -%c", opt); charptr = strchr(optstr, opt); @@ -242,11 +228,12 @@ * 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. */ -void parse_error(const char *message) +static void __attribute__ ((__noreturn__)) parse_error(const char *message) { if (message) - fprintf(stderr, "getopt: %s\n", message); - fputs(_("Try `getopt --help' for more information.\n"), stderr); + warnx("%s", message); + fprintf(stderr, _("Try `%s --help' for more information.\n"), + program_invocation_short_name); exit(PARAMETER_EXIT_CODE); } @@ -257,9 +244,11 @@ #define init_longopt() add_longopt(NULL,0) /* Register a long option. The contents of name is copied. */ -void add_longopt(const char *name, int has_arg) +static void add_longopt(const char *name, int has_arg) { char *tmp; + static int flag; + if (!name) { /* init */ free(long_options); @@ -270,9 +259,9 @@ if (long_options_nr == long_options_length) { long_options_length += LONG_OPTIONS_INCR; - long_options = our_realloc(long_options, - sizeof(struct option) * - long_options_length); + long_options = xrealloc(long_options, + sizeof(struct option) * + long_options_length); } long_options[long_options_nr].name = NULL; @@ -280,12 +269,12 @@ long_options[long_options_nr].flag = NULL; long_options[long_options_nr].val = 0; - if (long_options_nr) { + if (long_options_nr && name) { /* Not for init! */ long_options[long_options_nr - 1].has_arg = has_arg; - long_options[long_options_nr - 1].flag = NULL; - long_options[long_options_nr - 1].val = LONG_OPT; - tmp = our_malloc(strlen(name) + 1); + long_options[long_options_nr - 1].flag = &flag; + long_options[long_options_nr - 1].val = long_options_nr; + tmp = xmalloc(strlen(name) + 1); strcpy(tmp, name); long_options[long_options_nr - 1].name = tmp; } @@ -293,11 +282,11 @@ } -/* +/* * Register several long options. options is a string of long options, * separated by commas or whitespace. This nukes options! */ -void add_long_options(char *options) +static void add_long_options(char *options) { int arg_opt; char *tokptr = strtok(options, ", \t\n"); @@ -323,7 +312,7 @@ } } -void set_shell(const char *new_shell) +static void set_shell(const char *new_shell) { if (!strcmp(new_shell, "bash")) shell = BASH; @@ -338,27 +327,42 @@ ("unknown shell after -s or --shell argument")); } -void print_help(void) +static void __attribute__ ((__noreturn__)) print_help(void) { - fputs(_("Usage: getopt optstring parameters\n"), stderr); - fputs(_(" getopt [options] [--] optstring parameters\n"), stderr); - fputs(_(" getopt [options] -o|--options optstring [options] [--]\n"), stderr); - fputs(_(" parameters\n"), stderr); + fputs(USAGE_HEADER, stderr); + fprintf(stderr, _( + " %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_OPTIONS, stderr); fputs(_(" -a, --alternative Allow long options starting with single -\n"), stderr); - fputs(_(" -h, --help This small usage guide\n"), stderr); - fputs(_(" -l, --longoptions=longopts Long options to be recognized\n"), stderr); - fputs(_(" -n, --name=progname The name under which errors are reported\n"), stderr); - fputs(_(" -o, --options=optstring Short options to be recognized\n"), stderr); + fputs(_(" -l, --longoptions Long options to be recognized\n"), stderr); + fputs(_(" -n, --name The name under which errors are reported\n"), stderr); + fputs(_(" -o, --options Short options to be recognized\n"), stderr); fputs(_(" -q, --quiet Disable error reporting by getopt(3)\n"), stderr); fputs(_(" -Q, --quiet-output No normal output\n"), stderr); - fputs(_(" -s, --shell=shell Set shell quoting conventions\n"), stderr); + fputs(_(" -s, --shell Set shell quoting conventions\n"), stderr); fputs(_(" -T, --test Test for getopt(1) version\n"), stderr); - fputs(_(" -u, --unqote Do not quote the output\n"), stderr); - fputs(_(" -V, --version Output version information\n"), stderr); + fputs(_(" -u, --unquoted Do not quote the output\n"), stderr); + fputs(USAGE_SEPARATOR, stderr); + fputs(USAGE_HELP, stderr); + fputs(USAGE_VERSION, stderr); + fprintf(stderr, USAGE_MAN_TAIL("getopt(1)")); exit(PARAMETER_EXIT_CODE); } -static struct option longopts[] = { +int main(int argc, char *argv[]) +{ + char *optstr = NULL; + char *name = NULL; + int opt; + int compatible = 0; + + /* 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'}, @@ -373,22 +377,9 @@ {NULL, 0, NULL, 0} }; -/* Stop scanning as soon as a non-option argument is found! */ -static const char *shortopts = "+ao:l:n:qQs:TuhV"; - -int main(int argc, char *argv[]) -{ - char *optstr = NULL; - char *name = NULL; - int opt; - int compatible = 0; - -#if WITHOUT_GETTEXT -#else setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); -#endif init_longopt(); getopt_long_fp = getopt_long; @@ -408,10 +399,9 @@ parse_error(_("missing optstring argument")); } - if (argv[1][0] != '-' || compatible) { quote = 0; - optstr = our_malloc(strlen(argv[1]) + 1); + optstr = xmalloc(strlen(argv[1]) + 1); strcpy(optstr, argv[1] + strspn(argv[1], "-+")); argv[1] = argv[0]; return generate_output(argv + 1, argc - 1, optstr, @@ -427,18 +417,16 @@ case 'h': print_help(); case 'o': - if (optstr) - free(optstr); - optstr = our_malloc(strlen(optarg)+1); + free(optstr); + optstr = xmalloc(strlen(optarg) + 1); strcpy(optstr, optarg); break; case 'l': add_long_options(optarg); break; case 'n': - if (name) - free(name); - name = our_malloc(strlen(optarg)+1); + free(name); + name = xmalloc(strlen(optarg) + 1); strcpy(name, optarg); break; case 'q': @@ -456,7 +444,7 @@ quote = 0; break; case 'V': - printf(_("getopt (enhanced) 1.1.4\n")); + printf(UTIL_LINUX_VERSION); return EXIT_SUCCESS; case '?': case ':': @@ -464,12 +452,12 @@ default: parse_error(_("internal error, contact the author.")); } - + if (!optstr) { if (optind >= argc) parse_error(_("missing optstring argument")); else { - optstr=our_malloc(strlen(argv[optind])+1); + optstr = xmalloc(strlen(argv[optind]) + 1); strcpy(optstr, argv[optind]); optind++; } @@ -478,6 +466,7 @@ argv[optind - 1] = name; else argv[optind - 1] = argv[0]; + return generate_output(argv + optind - 1, argc-optind + 1, optstr, long_options); }