]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - misc-utils/getopt.c
Merge branch 'PR/libmount-utab-event' of github.com:karelzak/util-linux-work
[thirdparty/util-linux.git] / misc-utils / getopt.c
index 01b58832b73024686bd20dd053cb7d97ede3e759..f989461a7647bae8d199d88a549068bb326769aa 100644 (file)
@@ -69,6 +69,7 @@
 
 #include "closestream.h"
 #include "nls.h"
+#include "strutils.h"
 #include "xalloc.h"
 
 /* NON_OPT is the code that is returned getopt(3) when a non-option is
@@ -97,8 +98,8 @@ struct getopt_control {
 enum { REALLOC_INCREMENT = 8 };
 
 /* 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);
+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
@@ -243,9 +244,7 @@ static void __attribute__ ((__noreturn__)) parse_error(const char *message)
 {
        if (message)
                warnx("%s", message);
-       fprintf(stderr, _("Try `%s --help' for more information.\n"),
-               program_invocation_short_name);
-       exit(PARAMETER_EXIT_CODE);
+       errtryhelp(PARAMETER_EXIT_CODE);
 }
 
 
@@ -253,23 +252,42 @@ static void __attribute__ ((__noreturn__)) parse_error(const char *message)
 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);
+               ctl->long_options = xreallocarray(ctl->long_options,
+                                                 ctl->long_options_length,
+                                                 sizeof(struct option));
        }
        if (name) {
                /* Not for init! */
-               ctl->long_options[ctl->long_options_nr].has_arg = has_arg;
-               ctl->long_options[ctl->long_options_nr].flag = &flag;
-               ctl->long_options[ctl->long_options_nr].val = ctl->long_options_nr;
-               ctl->long_options[ctl->long_options_nr].name = xstrdup(name);
+               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;
        }
 }
 
 
+static void add_short_options(struct getopt_control *ctl, char *options)
+{
+       free(ctl->optstr);
+       if (*options != '+' && getenv("POSIXLY_CORRECT"))
+               ctl->optstr = strconcat("+", options);
+       else
+               ctl->optstr = xstrdup(options);
+       if (!ctl->optstr)
+               err_oom();
+}
+
+
 /*
  * Register several long options. options is a string of long options,
  * separated by commas or whitespace. This nukes options!
@@ -303,10 +321,6 @@ static void add_long_options(struct getopt_control *ctl, char *options)
                tokptr = strtok(NULL, ", \t\n");
        }
        add_longopt(ctl, NULL, 0);      /* ensure long_options[] is not full */
-       ctl->long_options[ctl->long_options_nr].name = NULL;
-       ctl->long_options[ctl->long_options_nr].has_arg = 0;
-       ctl->long_options[ctl->long_options_nr].flag = NULL;
-       ctl->long_options[ctl->long_options_nr].val = 0;
 }
 
 static shell_t shell_type(const char *new_shell)
@@ -322,33 +336,32 @@ static shell_t shell_type(const char *new_shell)
        parse_error(_("unknown shell after -s or --shell argument"));
 }
 
-static void __attribute__ ((__noreturn__)) print_help(void)
+static void __attribute__((__noreturn__)) usage(void)
 {
-       fputs(USAGE_HEADER, stderr);
-       fprintf(stderr, _(
+       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, stderr);
-       fputs(_("Parse command options.\n"), stderr);
-
-       fputs(USAGE_OPTIONS, stderr);
-       fputs(_(" -a, --alternative             allow long options starting with single -\n"), stderr);
-       fputs(_(" -l, --longoptions <longopts>  the long options to be recognized\n"), stderr);
-       fputs(_(" -n, --name <progname>         the name under which errors are reported\n"), stderr);
-       fputs(_(" -o, --options <optstring>     the 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 quoting conventions to those of <shell>\n"), stderr);
-       fputs(_(" -T, --test                    test for getopt(1) version\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);
+       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);
+       fprintf(stdout, USAGE_HELP_OPTIONS(31));
+       fprintf(stdout, USAGE_MAN_TAIL("getopt(1)"));
+       exit(EXIT_SUCCESS);
 }
 
 int main(int argc, char *argv[])
@@ -379,7 +392,7 @@ int main(int argc, char *argv[])
        setlocale(LC_ALL, "");
        bindtextdomain(PACKAGE, LOCALEDIR);
        textdomain(PACKAGE);
-       atexit(close_stdout);
+       close_stdout_atexit();
 
        if (getenv("GETOPT_COMPATIBLE"))
                ctl.compatible = 1;
@@ -392,8 +405,8 @@ int main(int argc, char *argv[])
                         */
                        printf(" --\n");
                        return EXIT_SUCCESS;
-               } else
-                       parse_error(_("missing optstring argument"));
+               }
+               parse_error(_("missing optstring argument"));
        }
 
        add_longopt(&ctl, NULL, 0);     /* init */
@@ -413,11 +426,8 @@ int main(int argc, char *argv[])
                case 'a':
                        getopt_long_fp = getopt_long_only;
                        break;
-               case 'h':
-                       print_help();
                case 'o':
-                       free(ctl.optstr);
-                       ctl.optstr = xstrdup(optarg);
+                       add_short_options(&ctl, optarg);
                        break;
                case 'l':
                        add_long_options(&ctl, optarg);
@@ -441,12 +451,14 @@ int main(int argc, char *argv[])
                case 'u':
                        ctl.quote = 0;
                        break;
+
                case 'V':
-                       printf(UTIL_LINUX_VERSION);
-                       return EXIT_SUCCESS;
+                       print_version(EXIT_SUCCESS);
                case '?':
                case ':':
                        parse_error(NULL);
+               case 'h':
+                       usage();
                default:
                        parse_error(_("internal error, contact the author."));
                }
@@ -455,7 +467,7 @@ int main(int argc, char *argv[])
                if (optind >= argc)
                        parse_error(_("missing optstring argument"));
                else {
-                       ctl.optstr = xstrdup(argv[optind]);
+                       add_short_options(&ctl, argv[optind]);
                        optind++;
                }
        }