]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - getopt-1.0.3a/getopt.c
2 getopt.c - Enhanced implementation of BSD getopt(1)
3 Copyright (c) 1997, 1998 Frodo Looijaard <frodol@dds.nl>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * Version 1.0-b4: Tue Sep 23 1997. First public release.
22 * Version 1.0: Wed Nov 19 1997.
23 * Bumped up the version number to 1.0
24 * Fixed minor typo (CSH instead of TCSH)
25 * Version 1.0.1: Tue Jun 3 1998
26 * Fixed sizeof instead of strlen bug
27 * Bumped up the version number to 1.0.1
28 * Version 1.0.2: Thu Jun 11 1998 (not present)
29 * Fixed gcc-2.8.1 warnings
30 * Fixed --version/-V option (not present)
45 /* NON_OPT is the code that is returned when a non-option is found in '+'
48 /* LONG_OPT is the code that is returned when a long option is found. */
51 /* The shells recognized. */
52 typedef enum {BASH
,TCSH
} shell_t
;
55 /* Some global variables that tells us how to parse. */
56 shell_t shell
=BASH
; /* The shell we generate output for. */
57 int quiet_errors
=0; /* 0 is not quiet. */
58 int quiet_output
=0; /* 0 is not quiet. */
59 int quote
=1; /* 1 is do quote. */
60 int alternative
=0; /* 0 is getopt_long, 1 is getopt_long_only */
62 /* Function prototypes */
63 void *our_malloc(size_t size
);
64 void *our_realloc(void *ptr
, size_t size
);
65 const char *normalize(const char *arg
);
66 int generate_output(char * argv
[],int argc
,const char *optstr
,
67 const struct option
*longopts
);
68 int main(int argc
, char *argv
[]);
69 void parse_error(const char *message
);
70 void add_long_options(char *options
);
71 void add_longopt(const char *name
,int has_arg
);
72 void print_help(void);
73 void set_shell(const char *new_shell
);
74 void set_initial_shell(void);
76 void *our_malloc(size_t size
)
78 void *ret
=malloc(size
);
80 fputs("getopt: Out of memory!",stderr
);
86 void *our_realloc(void *ptr
, size_t size
)
88 void *ret
=realloc(ptr
,size
);
90 fputs("getopt: Out of memory!",stderr
);
97 * This function 'normalizes' a single argument: it puts single quotes around
98 * it and escapes other special characters. If quote is false, it just
99 * returns its argument.
100 * Bash only needs special treatment for single quotes; tcsh also recognizes
101 * exclamation marks within single quotes, and nukes whitespace.
102 * This function returns a pointer to a buffer that is overwritten by
105 const char *normalize(const char *arg
)
107 static char *BUFFER
=NULL
;
108 const char *argptr
=arg
;
114 if (!quote
) { /* Just copy arg */
115 BUFFER
=our_malloc(strlen(arg
)+1);
121 /* Each character in arg may take upto four characters in the result:
122 For a quote we need a closing quote, a backslash, a quote and an
123 opening quote! We need also the global opening and closing quote,
124 and one extra character for '\0'. */
125 BUFFER
=our_malloc(strlen(arg
)*4+3);
131 if (*argptr
== '\'') {
132 /* Quote: replace it with: '\'' */
137 } else if (shell
==TCSH
&& *argptr
=='!') {
138 /* Exclamation mark: replace it with: \! */
143 } else if (shell
==TCSH
&& *argptr
=='\n') {
144 /* Newline: replace it with: \n */
147 } else if (shell
==TCSH
&& isspace(*argptr
)) {
148 /* Non-newline whitespace: replace it with \<ws> */
164 * Generate the output. argv[0] is the program name (used for reporting errors).
165 * argv[1..] contains the options to be parsed. argc must be the number of
166 * elements in argv (ie. 1 if there are no options, only the program name),
167 * optstr must contain the short options, and longopts the long options.
168 * Other settings are found in global variables.
170 int generate_output(char * argv
[],int argc
,const char *optstr
,
171 const struct option
*longopts
)
173 int exit_code
= 0; /* We assume everything will be OK */
178 if (quiet_errors
) /* No error reporting from getopt(3) */
180 optind
=0; /* Reset getopt(3) */
182 while ((opt
= (alternative
?
183 getopt_long_only(argc
,argv
,optstr
,longopts
,&longindex
):
184 getopt_long(argc
,argv
,optstr
,longopts
,&longindex
)))
186 if (opt
== '?' || opt
== ':' )
188 else if (!quiet_output
)
190 if (opt
== LONG_OPT
) {
191 printf(" --%s",longopts
[longindex
].name
);
192 if (longopts
[longindex
].has_arg
)
194 normalize(optarg
?optarg
:""));
195 } else if (opt
== NON_OPT
)
196 printf(" %s",normalize(optarg
));
199 charptr
= strchr(optstr
,opt
);
200 if (charptr
!= NULL
&& *++charptr
== ':')
202 normalize(optarg
?optarg
:""));
206 if (! quiet_output
) {
208 while (optind
< argc
)
209 printf(" %s",normalize(argv
[optind
++]));
216 * Report an error when parsing getopt's own arguments.
217 * If message is NULL, we already sent a message, we just exit with a helpful
220 void parse_error(const char *message
)
223 fprintf(stderr
,"getopt: %s\n",message
);
224 fputs("Try `getopt --help' for more information.\n",stderr
);
228 static struct option
*long_options
=NULL
;
229 static int long_options_length
=0; /* Length of array */
230 static int long_options_nr
=0; /* Nr of used elements in array */
231 #define LONG_OPTIONS_INCR 10
232 #define init_longopt() add_longopt(NULL,0)
234 /* Register a long option. The contents of name is copied. */
235 void add_longopt(const char *name
,int has_arg
)
238 if (!name
) { /* init */
241 long_options_length
=0;
245 if (long_options_nr
== long_options_length
) {
246 long_options_length
+= LONG_OPTIONS_INCR
;
247 long_options
=our_realloc(long_options
,
248 sizeof(struct option
) *
249 long_options_length
);
252 long_options
[long_options_nr
].name
=NULL
;
253 long_options
[long_options_nr
].has_arg
=0;
254 long_options
[long_options_nr
].flag
=NULL
;
255 long_options
[long_options_nr
].val
=0;
257 if (long_options_nr
) { /* Not for init! */
258 long_options
[long_options_nr
-1].has_arg
=has_arg
;
259 long_options
[long_options_nr
-1].flag
=NULL
;
260 long_options
[long_options_nr
-1].val
=LONG_OPT
;
261 tmp
= our_malloc(strlen(name
)+1);
263 long_options
[long_options_nr
-1].name
=tmp
;
270 * Register several long options. options is a string of long options,
271 * separated by commas or whitespace.
272 * This nukes options!
274 void add_long_options(char *options
)
277 char *tokptr
=strtok(options
,", \t\n");
280 if (strlen(tokptr
) > 0) {
281 if (tokptr
[strlen(tokptr
)-1] == ':') {
282 if (tokptr
[strlen(tokptr
)-2] == ':') {
283 tokptr
[strlen(tokptr
)-2]='\0';
284 arg_opt
=optional_argument
;
286 tokptr
[strlen(tokptr
)-1]='\0';
287 arg_opt
=required_argument
;
289 if (strlen(tokptr
) == 0)
290 parse_error("empty long option after "
291 "-l or --long argument");
293 add_longopt(tokptr
,arg_opt
);
295 tokptr
=strtok(NULL
,", \t\n");
299 void set_shell(const char *new_shell
)
301 if (!strcmp(new_shell
,"bash"))
303 else if (!strcmp(new_shell
,"tcsh"))
305 else if (!strcmp(new_shell
,"sh"))
307 else if (!strcmp(new_shell
,"csh"))
310 parse_error("unknown shell after -s or --shell argument");
313 void print_help(void)
315 fputs("Usage: getopt optstring parameters\n",stderr
);
316 fputs(" getopt [options] [--] optstring parameters\n",stderr
);
317 fputs(" getopt [options] -o|--options optstring [options] [--]\n",stderr
);
318 fputs(" parameters\n",stderr
);
319 fputs(" -a, --alternative Allow long options starting with single -\n",stderr
);
320 fputs(" -h, --help This small usage guide\n",stderr
);
321 fputs(" -l, --longoptions=longopts Long options to be recognized\n",stderr
);
322 fputs(" -n, --name=progname The name under which errors are reported\n",stderr
);
323 fputs(" -o, --options=optstring Short options to be recognized\n",stderr
);
324 fputs(" -q, --quiet Disable error reporting by getopt(3)\n",stderr
);
325 fputs(" -Q, --quiet-output No normal output\n",stderr
);
326 fputs(" -s, --shell=shell Set shell quoting conventions\n",stderr
);
327 fputs(" -T, --test Test for getopt(1) version\n",stderr
);
328 fputs(" -V, --version Output version information\n",stderr
);
333 * 0) No errors, succesful operation.
334 * 1) getopt(3) returned an error.
335 * 2) A problem with parameter parsing for getopt(1).
336 * 3) Internal error, out of memory
340 static struct option longopts
[]={ {"options",required_argument
,NULL
,'o'},
341 {"longoptions",required_argument
,NULL
,'l'},
342 {"quiet",no_argument
,NULL
,'q'},
343 {"quiet-output",no_argument
,NULL
,'Q'},
344 {"shell",required_argument
,NULL
,'s'},
345 {"test",no_argument
,NULL
,'T'},
346 {"unquoted",no_argument
,NULL
,'u'},
347 {"help",no_argument
,NULL
,'h'},
348 {"alternative",no_argument
,NULL
,'a'},
349 {"name",required_argument
,NULL
,'n'},
350 {"version",no_argument
,NULL
,'V'},
354 /* Stop scanning as soon as a non-option argument is found! */
355 static const char *shortopts
="+ao:l:n:qQs:TuhV";
357 int main(int argc
, char *argv
[])
366 if (getenv("GETOPT_COMPATIBLE"))
372 /* For some reason, the original getopt gave no error
373 when there were no arguments. */
378 parse_error("missing optstring argument");
381 if (argv
[1][0] != '-' || compatible
) {
383 optstr
=our_malloc(strlen(argv
[1])+1);
384 strcpy(optstr
,argv
[1]+strspn(argv
[1],"-+"));
386 exit(generate_output(argv
+1,argc
-1,optstr
,long_options
));
389 while ((opt
=getopt_long(argc
,argv
,shortopts
,longopts
,NULL
)) != EOF
)
400 optstr
=our_malloc(strlen(optarg
)+1);
401 strcpy(optstr
,optarg
);
404 add_long_options(optarg
);
409 name
=our_malloc(strlen(optarg
)+1);
424 printf("getopt (enhanced) 1.0.3\n");
430 parse_error("internal error, contact the author.");
436 parse_error("missing optstring argument");
438 optstr
=our_malloc(strlen(argv
[optind
])+1);
439 strcpy(optstr
,argv
[optind
]);
446 argv
[optind
-1]=argv
[0];
447 exit(generate_output(argv
+optind
-1,argc
-optind
+1,optstr
,long_options
));