]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - misc-utils/getopt.c
Merge branch 'hardlink' of https://github.com/rudimeier/util-linux into hardlink
[thirdparty/util-linux.git] / misc-utils / getopt.c
index c4144f63e42bf9068955707e9d2dda9eaafbb2fe..9b4f352795f5f006ba0645d4f09698f489015055 100644 (file)
@@ -54,6 +54,7 @@
 #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>
@@ -82,6 +83,7 @@ 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 */
@@ -95,8 +97,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
@@ -181,7 +183,7 @@ static void print_normalized(const struct getopt_control *ctl, const char *arg)
  * optstr must contain the short options, and longopts the long options.
  * Other settings are found in global variables.
  */
-static int generate_output(const struct getopt_control *ctl, char *argv[], int argc)
+static int generate_output(struct getopt_control *ctl, char *argv[], int argc)
 {
        int exit_code = EXIT_SUCCESS;   /* Assume everything will be OK */
        int opt;
@@ -195,8 +197,10 @@ static int generate_output(const struct getopt_control *ctl, char *argv[], int a
        optind = 0;
 
        while ((opt =
-               (getopt_long_fp(argc, argv, ctl->optstr, ctl->long_options, &longindex)))
-              != EOF)
+               (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) {
@@ -216,13 +220,18 @@ static int generate_output(const struct getopt_control *ctl, char *argv[], int a
                                        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;
 }
 
@@ -234,9 +243,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);
 }
 
 
@@ -244,6 +251,7 @@ 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;
@@ -253,10 +261,16 @@ static void add_longopt(struct getopt_control *ctl, const char *name, int has_ar
        }
        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;
        }
 }
 
@@ -294,10 +308,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)
@@ -313,33 +323,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);
+       printf(USAGE_HELP_OPTIONS(31));
+       printf(USAGE_MAN_TAIL("getopt(1)"));
+       exit(EXIT_SUCCESS);
 }
 
 int main(int argc, char *argv[])
@@ -348,7 +357,6 @@ int main(int argc, char *argv[])
                .shell = BASH,
                .quote = 1
        };
-       char *name = NULL;
        int opt;
 
        /* Stop scanning as soon as a non-option argument is found! */
@@ -373,9 +381,6 @@ int main(int argc, char *argv[])
        textdomain(PACKAGE);
        atexit(close_stdout);
 
-       add_longopt(&ctl, NULL, 0);     /* init */
-       getopt_long_fp = getopt_long;
-
        if (getenv("GETOPT_COMPATIBLE"))
                ctl.compatible = 1;
 
@@ -391,6 +396,9 @@ int main(int argc, char *argv[])
                        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);
@@ -406,7 +414,7 @@ int main(int argc, char *argv[])
                        getopt_long_fp = getopt_long_only;
                        break;
                case 'h':
-                       print_help();
+                       usage();
                case 'o':
                        free(ctl.optstr);
                        ctl.optstr = xstrdup(optarg);
@@ -415,8 +423,8 @@ int main(int argc, char *argv[])
                        add_long_options(&ctl, optarg);
                        break;
                case 'n':
-                       free(name);
-                       name = xstrdup(optarg);
+                       free(ctl.name);
+                       ctl.name = xstrdup(optarg);
                        break;
                case 'q':
                        ctl.quiet_errors = 1;
@@ -428,6 +436,7 @@ int main(int argc, char *argv[])
                        ctl.shell = shell_type(optarg);
                        break;
                case 'T':
+                       free(ctl.long_options);
                        return TEST_EXIT_CODE;
                case 'u':
                        ctl.quote = 0;
@@ -451,10 +460,10 @@ int main(int argc, char *argv[])
                }
        }
 
-       if (name) {
-               argv[optind - 1] = name;
-#if defined (BSD) || defined (__APPLE__)
-               setprogname(name);
+       if (ctl.name) {
+               argv[optind - 1] = ctl.name;
+#if defined (HAVE_SETPROGNAME) && !defined (__linux__)
+               setprogname(ctl.name);
 #endif
        } else
                argv[optind - 1] = argv[0];