#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 <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 "strutils.h"
#include "xalloc.h"
/* NON_OPT is the code that is returned getopt(3) when a non-option is
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 */
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);
+/* 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 'print_normalizeds' a single argument: it puts single quotes
+ * 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.
*
* 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;
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) {
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;
}
{
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);
}
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!
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)
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, _(
- " %1$s optstring parameters\n"
- " %1$s [options] [--] optstring parameters\n"
- " %1$s [options] -o|--options optstring [options] [--] parameters\n"),
+ 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_OPTIONS, stderr);
- fputs(_(" -a, --alternative Allow long options starting with single -\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(_(" -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(_(" -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[])
.shell = BASH,
.quote = 1
};
- char *name = NULL;
int opt;
/* Stop scanning as soon as a non-option argument is found! */
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
- atexit(close_stdout);
-
- add_longopt(&ctl, NULL, 0); /* init */
- getopt_long_fp = getopt_long;
+ close_stdout_atexit();
if (getenv("GETOPT_COMPATIBLE"))
ctl.compatible = 1;
*/
printf(" --\n");
return EXIT_SUCCESS;
- } else
- parse_error(_("missing optstring argument"));
+ }
+ 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);
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);
break;
case 'n':
- free(name);
- name = xstrdup(optarg);
+ free(ctl.name);
+ ctl.name = xstrdup(optarg);
break;
case 'q':
ctl.quiet_errors = 1;
ctl.shell = shell_type(optarg);
break;
case 'T':
+ free(ctl.long_options);
return TEST_EXIT_CODE;
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."));
}
if (optind >= argc)
parse_error(_("missing optstring argument"));
else {
- ctl.optstr = xstrdup(argv[optind]);
+ add_short_options(&ctl, argv[optind]);
optind++;
}
}
- if (name)
- argv[optind - 1] = name;
- else
+
+ 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);