aboutsummaryrefslogtreecommitdiff
path: root/util-linux/getopt.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-04-07 10:25:04 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-04-07 10:25:04 +0000
commit9c146a91d3c1ae3b561be39b792bbd45447b904c (patch)
tree498ea2fc84be4966ebf210fdb4d995d16b23c9f8 /util-linux/getopt.c
parentfdf63a30fe4f5f0d5dac2899b50996ca7088f1bf (diff)
downloadbusybox-9c146a91d3c1ae3b561be39b792bbd45447b904c.tar.gz
getopt: use getopt32 for option parsing - inspired by patch by
Mats Erik Andersson <mats.andersson64@comhem.se> function old new delta getopt_main 809 810 +1 static.BUFFER 4 - -4 shell 8 4 -4 quote 4 - -4 quiet_output 4 - -4 quiet_errors 4 - -4 long_options_nr 4 - -4 long_options_length 4 - -4 long_options 388 384 -4 alternative 4 - -4 shortopts 15 - -15 normalize 243 220 -23 .rodata 131832 131800 -32 add_longopt 200 - -200 ------------------------------------------------------------------------------ (add/remove: 0/9 grow/shrink: 1/4 up/down: 1/-306) Total: -305 bytes
Diffstat (limited to 'util-linux/getopt.c')
-rw-r--r--util-linux/getopt.c353
1 files changed, 158 insertions, 195 deletions
diff --git a/util-linux/getopt.c b/util-linux/getopt.c
index 74e7235ea..fefa02206 100644
--- a/util-linux/getopt.c
+++ b/util-linux/getopt.c
@@ -42,25 +42,29 @@ enum {
LONG_OPT = 2
};
-/* The shells recognized. */
-typedef enum {BASH,TCSH} shell_t;
-
-
-/* Some global variables that tells us how to parse. */
-static shell_t shell=BASH; /* The shell we generate output for. */
-static int quiet_errors; /* 0 is not quiet. */
-static int quiet_output; /* 0 is not quiet. */
-static int quote=1; /* 1 is do quote. */
-static int alternative; /* 0 is getopt_long, 1 is getopt_long_only */
+/* For finding activated option flags. Must match getopt32 call! */
+enum {
+ OPT_o = 0x1, // -o
+ OPT_n = 0x2, // -n
+ OPT_q = 0x4, // -q
+ OPT_Q = 0x8, // -Q
+ OPT_s = 0x10, // -s
+ OPT_T = 0x20, // -T
+ OPT_u = 0x40, // -u
+#if ENABLE_GETOPT_LONG
+ OPT_a = 0x80, // -a
+ OPT_l = 0x100, // -l
+#endif
+ SHELL_IS_TCSH = 0x8000, /* hijack this bit for other purposes */
+};
-/* Function prototypes */
-static const char *normalize(const char *arg);
-static int generate_output(char **argv,int argc,const char *optstr,
- const struct option *longopts);
-static void add_long_options(char *options);
-static void add_longopt(const char *name,int has_arg);
-static void set_shell(const char *new_shell);
+/* 0 is getopt_long, 1 is getopt_long_only */
+#define alternative (option_mask32 & OPT_a)
+#define quiet_errors (option_mask32 & OPT_q)
+#define quiet_output (option_mask32 & OPT_Q)
+#define quote (!(option_mask32 & OPT_u))
+#define shell_TCSH (option_mask32 & SHELL_IS_TCSH)
/*
* This function 'normalizes' a single argument: it puts single quotes around
@@ -71,16 +75,18 @@ static void set_shell(const char *new_shell);
* 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 ENABLE_FEATURE_CLEAN_UP
+ static char *BUFFER = NULL;
free(BUFFER);
+#else
+ char *BUFFER;
+#endif
if (!quote) { /* Just copy arg */
- BUFFER=xstrdup(arg);
+ BUFFER = xstrdup(arg);
return BUFFER;
}
@@ -88,41 +94,41 @@ const char *normalize(const char *arg)
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=xmalloc(strlen(arg)*4+3);
+ BUFFER = xmalloc(strlen(arg)*4 + 3);
- bufptr=BUFFER;
- *bufptr++='\'';
+ bufptr = BUFFER;
+ *bufptr ++= '\'';
- while (*argptr) {
- if (*argptr == '\'') {
+ while (*arg) {
+ if (*arg == '\'') {
/* Quote: replace it with: '\'' */
- *bufptr++='\'';
- *bufptr++='\\';
- *bufptr++='\'';
- *bufptr++='\'';
- } else if (shell==TCSH && *argptr=='!') {
+ *bufptr ++= '\'';
+ *bufptr ++= '\\';
+ *bufptr ++= '\'';
+ *bufptr ++= '\'';
+ } else if (shell_TCSH && *arg == '!') {
/* Exclamation mark: replace it with: \! */
- *bufptr++='\'';
- *bufptr++='\\';
- *bufptr++='!';
- *bufptr++='\'';
- } else if (shell==TCSH && *argptr=='\n') {
+ *bufptr ++= '\'';
+ *bufptr ++= '\\';
+ *bufptr ++= '!';
+ *bufptr ++= '\'';
+ } else if (shell_TCSH && *arg == '\n') {
/* Newline: replace it with: \n */
- *bufptr++='\\';
- *bufptr++='n';
- } else if (shell==TCSH && isspace(*argptr)) {
+ *bufptr ++= '\\';
+ *bufptr ++= 'n';
+ } else if (shell_TCSH && isspace(*arg)) {
/* Non-newline whitespace: replace it with \<ws> */
- *bufptr++='\'';
- *bufptr++='\\';
- *bufptr++=*argptr;
- *bufptr++='\'';
+ *bufptr ++= '\'';
+ *bufptr ++= '\\';
+ *bufptr ++= *arg;
+ *bufptr ++= '\'';
} else
/* Just copy */
- *bufptr++=*argptr;
- argptr++;
+ *bufptr ++= *arg;
+ arg++;
}
- *bufptr++='\'';
- *bufptr++='\0';
+ *bufptr ++= '\'';
+ *bufptr ++= '\0';
return BUFFER;
}
@@ -133,132 +139,102 @@ const char *normalize(const char *arg)
* 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,
+static int generate_output(char * argv[],int argc,const char *optstr,
const struct option *longopts)
{
int exit_code = 0; /* We assume everything will be OK */
- int opt;
+ unsigned opt;
int longindex;
const char *charptr;
if (quiet_errors) /* No error reporting from getopt(3) */
- opterr=0;
- optind=0; /* Reset getopt(3) */
+ opterr = 0;
+ optind = 0; /* Reset getopt(3) */
- while ((opt = (alternative?
- getopt_long_only(argc,argv,optstr,longopts,&longindex):
+ while ((opt = (alternative ?
+ getopt_long_only(argc,argv,optstr,longopts,&longindex) :
getopt_long(argc,argv,optstr,longopts,&longindex)))
!= EOF)
if (opt == '?' || opt == ':' )
exit_code = 1;
else if (!quiet_output) {
if (opt == LONG_OPT) {
- printf(" --%s",longopts[longindex].name);
+ printf(" --%s", longopts[longindex].name);
if (longopts[longindex].has_arg)
printf(" %s",
- normalize(optarg?optarg:""));
+ normalize(optarg ? optarg : ""));
} else if (opt == NON_OPT)
- printf(" %s",normalize(optarg));
+ printf(" %s", normalize(optarg));
else {
- printf(" -%c",opt);
+ printf(" -%c", opt);
charptr = strchr(optstr,opt);
if (charptr != NULL && *++charptr == ':')
printf(" %s",
- normalize(optarg?optarg:""));
+ normalize(optarg ? optarg : ""));
}
}
- if (! quiet_output) {
+ if (!quiet_output) {
printf(" --");
while (optind < argc)
- printf(" %s",normalize(argv[optind++]));
+ printf(" %s", normalize(argv[optind++]));
puts("");
}
return exit_code;
}
-static struct option *long_options;
-static int long_options_length; /* Length of array */
-static int long_options_nr; /* Nr of used elements in array */
-enum { LONG_OPTIONS_INCR = 10 };
-#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)
-{
- if (!name) { /* init */
- free(long_options);
- long_options=NULL;
- long_options_length=0;
- long_options_nr=0;
- }
-
- if (long_options_nr == long_options_length) {
- long_options_length += LONG_OPTIONS_INCR;
- long_options=xrealloc(long_options,
- sizeof(struct option) *
- long_options_length);
- }
-
- long_options[long_options_nr].name=NULL;
- long_options[long_options_nr].has_arg=0;
- long_options[long_options_nr].flag=NULL;
- long_options[long_options_nr].val=0;
-
- if (long_options_nr) { /* 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;
- long_options[long_options_nr-1].name=xstrdup(name);
- }
- long_options_nr++;
-}
-
-
/*
* 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 struct option *add_long_options(struct option *long_options, char *options)
{
+ int long_nr = 0;
int arg_opt, tlen;
- char *tokptr=strtok(options,", \t\n");
+ char *tokptr = strtok(options, ", \t\n");
+
+ if (long_options)
+ while (long_options[long_nr].name)
+ long_nr++;
+
while (tokptr) {
- arg_opt=no_argument;
- tlen=strlen(tokptr);
- if (tlen > 0) {
- if (tokptr[tlen-1] == ':') {
- if (tlen > 1 && tokptr[tlen-2] == ':') {
- tokptr[tlen-2]='\0';
- tlen -= 2;
- arg_opt=optional_argument;
- } else {
- tokptr[tlen-1]='\0';
- tlen -= 1;
- arg_opt=required_argument;
+ arg_opt = no_argument;
+ tlen = strlen(tokptr);
+ if (tlen) {
+ tlen--;
+ if (tokptr[tlen] == ':') {
+ arg_opt = required_argument;
+ if (tlen && tokptr[tlen-1] == ':') {
+ tlen--;
+ arg_opt = optional_argument;
}
+ tokptr[tlen] = '\0';
if (tlen == 0)
- bb_error_msg("empty long option after -l or --long argument");
+ bb_error_msg_and_die("empty long option specified");
}
- add_longopt(tokptr,arg_opt);
+ long_options = xrealloc(long_options,
+ sizeof(long_options[0]) * (long_nr+2));
+ long_options[long_nr].has_arg = arg_opt;
+ long_options[long_nr].flag = NULL;
+ long_options[long_nr].val = LONG_OPT;
+ long_options[long_nr].name = xstrdup(tokptr);
+ long_nr++;
+ memset(&long_options[long_nr], 0, sizeof(long_options[0]));
}
- tokptr=strtok(NULL,", \t\n");
+ tokptr = strtok(NULL, ", \t\n");
}
+ return long_options;
}
-void set_shell(const char *new_shell)
+static void set_shell(const char *new_shell)
{
- if (!strcmp(new_shell,"bash"))
- shell=BASH;
- else if (!strcmp(new_shell,"tcsh"))
- shell=TCSH;
- else if (!strcmp(new_shell,"sh"))
- shell=BASH;
- else if (!strcmp(new_shell,"csh"))
- shell=TCSH;
+ if (!strcmp(new_shell,"bash") || !strcmp(new_shell,"sh"))
+ return;
+ if (!strcmp(new_shell,"tcsh") || !strcmp(new_shell,"csh"))
+ option_mask32 |= SHELL_IS_TCSH;
else
- bb_error_msg("unknown shell after -s or --shell argument");
+ bb_error_msg("unknown shell '%s', assuming bash", new_shell);
}
@@ -270,36 +246,35 @@ void set_shell(const char *new_shell)
* 4) Returned for -T
*/
-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'},
- {"alternative",no_argument,NULL,'a'},
- {"name",required_argument,NULL,'n'},
- {NULL,0,NULL,0}
+#if ENABLE_GETOPT_LONG
+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' },
+ { "alternative", no_argument, NULL, 'a' },
+ { "name", required_argument, NULL, 'n' },
+ { NULL, 0, NULL, 0 }
};
+#endif
-/* Stop scanning as soon as a non-option argument is found! */
-static const char shortopts[]="+ao:l:n:qQs:Tu";
-
-
-int getopt_main(int argc, char **argv);
-int getopt_main(int argc, char **argv)
+int getopt_main(int argc, char *argv[]);
+int getopt_main(int argc, char *argv[])
{
- const char *optstr = NULL;
+ struct option *long_options = NULL;
+ char *optstr = NULL;
char *name = NULL;
- int opt;
- int compatible=0;
+ unsigned opt;
+ const char *compatible;
+ char *s_arg;
+#if ENABLE_GETOPT_LONG
+ llist_t *l_arg = NULL;
+#endif
- init_longopt();
-
- if (getenv("GETOPT_COMPATIBLE"))
- compatible=1;
+ compatible = getenv("GETOPT_COMPATIBLE"); /* used as yes/no flag */
if (argc == 1) {
if (compatible) {
@@ -307,60 +282,48 @@ int getopt_main(int argc, char **argv)
when there were no arguments. */
printf(" --\n");
return 0;
- } else
- bb_error_msg_and_die("missing optstring argument");
+ }
+ bb_error_msg_and_die("missing optstring argument");
}
if (argv[1][0] != '-' || compatible) {
char *s;
- quote=0;
- s=xmalloc(strlen(argv[1])+1);
- strcpy(s,argv[1]+strspn(argv[1],"-+"));
- argv[1]=argv[0];
- return generate_output(argv+1,argc-1,s,long_options);
+ option_mask32 |= OPT_u; /* quoting off */
+ s = xstrdup(argv[1] + strspn(argv[1], "-+"));
+ argv[1] = argv[0];
+ return generate_output(argv+1, argc-1, s, long_options);
}
- while ((opt = getopt_long(argc,argv,shortopts,longopts,NULL)) != EOF)
- switch (opt) {
- case 'a':
- alternative=1;
- break;
- case 'o':
- optstr = optarg;
- break;
- case 'l':
- add_long_options(optarg);
- break;
- case 'n':
- name = optarg;
- break;
- case 'q':
- quiet_errors=1;
- break;
- case 'Q':
- quiet_output=1;
- break;
- case 's':
- set_shell(optarg);
- break;
- case 'T':
- return 4;
- case 'u':
- quote=0;
- break;
- default:
- bb_show_usage();
- }
+#if !ENABLE_GETOPT_LONG
+ opt = getopt32(argc, argv, "+o:n:qQs:Tu", &optstr, &name, &s_arg);
+#else
+ applet_long_options = longopts;
+ opt_complementary = "?:l::";
+ opt = getopt32(argc, argv, "+o:n:qQs:Tual:",
+ &optstr, &name, &s_arg, &l_arg);
+ /* Effectuate the read options for the applet itself */
+ while (l_arg) {
+ long_options = add_long_options(long_options, l_arg->data);
+ l_arg = l_arg->link;
+ }
+#endif
+
+ if (opt & OPT_s) {
+ set_shell(s_arg);
+ }
+ if (opt & OPT_T) {
+ return 4;
+ }
+
+ /* All options controlling the applet have now been parsed */
if (!optstr) {
if (optind >= argc)
bb_error_msg_and_die("missing optstring argument");
- else optstr=argv[optind++];
+ optstr = argv[optind++];
}
- if (name)
- argv[optind-1]=name;
- else
- argv[optind-1]=argv[0];
- return generate_output(argv+optind-1,argc-optind+1,optstr,long_options);
+
+ argv[optind-1] = name ? name : argv[0];
+ return generate_output(argv+optind-1, argc-optind+1, optstr, long_options);
}