]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - getopt/getopt.c
2 getopt.c - Enhanced implementation of BSD getopt(1)
3 Copyright (c) 1997, 1998, 1999, 2000 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)
31 * Version 1.0.5: Tue Jun 22 1999
32 * Make -u option work (not present)
33 * Version 1.0.6: Tue Jun 27 2000
34 * No important changes
35 * Version 1.1.0: Tue Jun 30 2000
36 * Added NLS support (partly written by Arkadiusz Mi<B6>kiewicz
37 * <misiek@pld.org.pl>)
54 /* NON_OPT is the code that is returned when a non-option is found in '+'
57 /* LONG_OPT is the code that is returned when a long option is found. */
60 /* The shells recognized. */
61 typedef enum {BASH
,TCSH
} shell_t
;
64 /* Some global variables that tells us how to parse. */
65 shell_t shell
=BASH
; /* The shell we generate output for. */
66 int quiet_errors
=0; /* 0 is not quiet. */
67 int quiet_output
=0; /* 0 is not quiet. */
68 int quote
=1; /* 1 is do quote. */
69 int alternative
=0; /* 0 is getopt_long, 1 is getopt_long_only */
71 /* Function prototypes */
72 void *our_malloc(size_t size
);
73 void *our_realloc(void *ptr
, size_t size
);
74 const char *normalize(const char *arg
);
75 int generate_output(char * argv
[],int argc
,const char *optstr
,
76 const struct option
*longopts
);
77 int main(int argc
, char *argv
[]);
78 void parse_error(const char *message
);
79 void add_long_options(char *options
);
80 void add_longopt(const char *name
,int has_arg
);
81 void print_help(void);
82 void set_shell(const char *new_shell
);
83 void set_initial_shell(void);
85 void *our_malloc(size_t size
)
87 void *ret
=malloc(size
);
89 fprintf(stderr
,_("%s: Out of memory!\n"),"getopt");
95 void *our_realloc(void *ptr
, size_t size
)
97 void *ret
=realloc(ptr
,size
);
99 fprintf(stderr
,_("%s: Out of memory!\n"),"getopt");
106 * This function 'normalizes' a single argument: it puts single quotes around
107 * it and escapes other special characters. If quote is false, it just
108 * returns its argument.
109 * Bash only needs special treatment for single quotes; tcsh also recognizes
110 * exclamation marks within single quotes, and nukes whitespace.
111 * This function returns a pointer to a buffer that is overwritten by
114 const char *normalize(const char *arg
)
116 static char *BUFFER
=NULL
;
117 const char *argptr
=arg
;
123 if (!quote
) { /* Just copy arg */
124 BUFFER
=our_malloc(strlen(arg
)+1);
130 /* Each character in arg may take upto four characters in the result:
131 For a quote we need a closing quote, a backslash, a quote and an
132 opening quote! We need also the global opening and closing quote,
133 and one extra character for '\0'. */
134 BUFFER
=our_malloc(strlen(arg
)*4+3);
140 if (*argptr
== '\'') {
141 /* Quote: replace it with: '\'' */
146 } else if (shell
==TCSH
&& *argptr
=='!') {
147 /* Exclamation mark: replace it with: \! */
152 } else if (shell
==TCSH
&& *argptr
=='\n') {
153 /* Newline: replace it with: \n */
156 } else if (shell
==TCSH
&& isspace(*argptr
)) {
157 /* Non-newline whitespace: replace it with \<ws> */
173 * Generate the output. argv[0] is the program name (used for reporting errors).
174 * argv[1..] contains the options to be parsed. argc must be the number of
175 * elements in argv (ie. 1 if there are no options, only the program name),
176 * optstr must contain the short options, and longopts the long options.
177 * Other settings are found in global variables.
179 int generate_output(char * argv
[],int argc
,const char *optstr
,
180 const struct option
*longopts
)
182 int exit_code
= 0; /* We assume everything will be OK */
187 if (quiet_errors
) /* No error reporting from getopt(3) */
189 optind
=0; /* Reset getopt(3) */
191 while ((opt
= (alternative
?
192 getopt_long_only(argc
,argv
,optstr
,longopts
,&longindex
):
193 getopt_long(argc
,argv
,optstr
,longopts
,&longindex
)))
195 if (opt
== '?' || opt
== ':' )
197 else if (!quiet_output
)
199 if (opt
== LONG_OPT
) {
200 printf(" --%s",longopts
[longindex
].name
);
201 if (longopts
[longindex
].has_arg
)
203 normalize(optarg
?optarg
:""));
204 } else if (opt
== NON_OPT
)
205 printf(" %s",normalize(optarg
));
208 charptr
= strchr(optstr
,opt
);
209 if (charptr
!= NULL
&& *++charptr
== ':')
211 normalize(optarg
?optarg
:""));
215 if (! quiet_output
) {
217 while (optind
< argc
)
218 printf(" %s",normalize(argv
[optind
++]));
225 * Report an error when parsing getopt's own arguments.
226 * If message is NULL, we already sent a message, we just exit with a helpful
229 void parse_error(const char *message
)
232 fprintf(stderr
,"getopt: %s\n",message
);
233 fputs(_("Try `getopt --help' for more information.\n"),stderr
);
237 static struct option
*long_options
=NULL
;
238 static int long_options_length
=0; /* Length of array */
239 static int long_options_nr
=0; /* Nr of used elements in array */
240 #define LONG_OPTIONS_INCR 10
241 #define init_longopt() add_longopt(NULL,0)
243 /* Register a long option. The contents of name is copied. */
244 void add_longopt(const char *name
,int has_arg
)
247 if (!name
) { /* init */
250 long_options_length
=0;
254 if (long_options_nr
== long_options_length
) {
255 long_options_length
+= LONG_OPTIONS_INCR
;
256 long_options
=our_realloc(long_options
,
257 sizeof(struct option
) *
258 long_options_length
);
261 long_options
[long_options_nr
].name
=NULL
;
262 long_options
[long_options_nr
].has_arg
=0;
263 long_options
[long_options_nr
].flag
=NULL
;
264 long_options
[long_options_nr
].val
=0;
266 if (long_options_nr
) { /* Not for init! */
267 long_options
[long_options_nr
-1].has_arg
=has_arg
;
268 long_options
[long_options_nr
-1].flag
=NULL
;
269 long_options
[long_options_nr
-1].val
=LONG_OPT
;
270 tmp
= our_malloc(strlen(name
)+1);
272 long_options
[long_options_nr
-1].name
=tmp
;
279 * Register several long options. options is a string of long options,
280 * separated by commas or whitespace.
281 * This nukes options!
283 void add_long_options(char *options
)
286 char *tokptr
=strtok(options
,", \t\n");
289 if (strlen(tokptr
) > 0) {
290 if (tokptr
[strlen(tokptr
)-1] == ':') {
291 if (tokptr
[strlen(tokptr
)-2] == ':') {
292 tokptr
[strlen(tokptr
)-2]='\0';
293 arg_opt
=optional_argument
;
295 tokptr
[strlen(tokptr
)-1]='\0';
296 arg_opt
=required_argument
;
298 if (strlen(tokptr
) == 0)
299 parse_error(_("empty long option after "
300 "-l or --long argument"));
302 add_longopt(tokptr
,arg_opt
);
304 tokptr
=strtok(NULL
,", \t\n");
308 void set_shell(const char *new_shell
)
310 if (!strcmp(new_shell
,"bash"))
312 else if (!strcmp(new_shell
,"tcsh"))
314 else if (!strcmp(new_shell
,"sh"))
316 else if (!strcmp(new_shell
,"csh"))
319 parse_error(_("unknown shell after -s or --shell argument"));
322 void print_help(void)
324 fputs(_("Usage: getopt optstring parameters\n"),stderr
);
325 fputs(_(" getopt [options] [--] optstring parameters\n"),stderr
);
326 fputs(_(" getopt [options] -o|--options optstring [options] [--]\n"),stderr
);
327 fputs(_(" parameters\n"),stderr
);
328 fputs(_(" -a, --alternative Allow long options starting with single -\n"),stderr
);
329 fputs(_(" -h, --help This small usage guide\n"),stderr
);
330 fputs(_(" -l, --longoptions=longopts Long options to be recognized\n"),stderr
);
331 fputs(_(" -n, --name=progname The name under which errors are reported\n"),stderr
);
332 fputs(_(" -o, --options=optstring Short options to be recognized\n"),stderr
);
333 fputs(_(" -q, --quiet Disable error reporting by getopt(3)\n"),stderr
);
334 fputs(_(" -Q, --quiet-output No normal output\n"),stderr
);
335 fputs(_(" -s, --shell=shell Set shell quoting conventions\n"),stderr
);
336 fputs(_(" -T, --test Test for getopt(1) version\n"),stderr
);
337 fputs(_(" -u, --unqote Do not quote the output\n"),stderr
);
338 fputs(_(" -V, --version Output version information\n"),stderr
);
343 * 0) No errors, succesful operation.
344 * 1) getopt(3) returned an error.
345 * 2) A problem with parameter parsing for getopt(1).
346 * 3) Internal error, out of memory
350 static struct option longopts
[]={ {"options",required_argument
,NULL
,'o'},
351 {"longoptions",required_argument
,NULL
,'l'},
352 {"quiet",no_argument
,NULL
,'q'},
353 {"quiet-output",no_argument
,NULL
,'Q'},
354 {"shell",required_argument
,NULL
,'s'},
355 {"test",no_argument
,NULL
,'T'},
356 {"unquoted",no_argument
,NULL
,'u'},
357 {"help",no_argument
,NULL
,'h'},
358 {"alternative",no_argument
,NULL
,'a'},
359 {"name",required_argument
,NULL
,'n'},
360 {"version",no_argument
,NULL
,'V'},
364 /* Stop scanning as soon as a non-option argument is found! */
365 static const char *shortopts
="+ao:l:n:qQs:TuhV";
367 int main(int argc
, char *argv
[])
376 setlocale(LC_ALL
,"");
377 bindtextdomain(PACKAGE
, LOCALEDIR
);
383 if (getenv("GETOPT_COMPATIBLE"))
389 /* For some reason, the original getopt gave no error
390 when there were no arguments. */
395 parse_error(_("missing optstring argument"));
398 if (argv
[1][0] != '-' || compatible
) {
400 optstr
=our_malloc(strlen(argv
[1])+1);
401 strcpy(optstr
,argv
[1]+strspn(argv
[1],"-+"));
403 exit(generate_output(argv
+1,argc
-1,optstr
,long_options
));
406 while ((opt
=getopt_long(argc
,argv
,shortopts
,longopts
,NULL
)) != EOF
)
417 optstr
=our_malloc(strlen(optarg
)+1);
418 strcpy(optstr
,optarg
);
421 add_long_options(optarg
);
426 name
=our_malloc(strlen(optarg
)+1);
444 printf(_("getopt (enhanced) 1.1.3\n"));
450 parse_error(_("internal error, contact the author."));
456 parse_error(_("missing optstring argument"));
458 optstr
=our_malloc(strlen(argv
[optind
])+1);
459 strcpy(optstr
,argv
[optind
]);
466 argv
[optind
-1]=argv
[0];
467 exit(generate_output(argv
+optind
-1,argc
-optind
+1,optstr
,long_options
));