Magellan Linux

Annotation of /tags/mkinitrd-6_2_0/util-linux/getopt.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (hide annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 9 months ago) by niro
Original Path: trunk/mkinitrd-magellan/busybox/util-linux/getopt.c
File MIME type: text/plain
File size: 9527 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

1 niro 532 /* vi: set sw=4 ts=4: */
2     /*
3     * getopt.c - Enhanced implementation of BSD getopt(1)
4     * Copyright (c) 1997, 1998, 1999, 2000 Frodo Looijaard <frodol@dds.nl>
5     *
6     * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
7     */
8    
9     /*
10     * Version 1.0-b4: Tue Sep 23 1997. First public release.
11     * Version 1.0: Wed Nov 19 1997.
12     * Bumped up the version number to 1.0
13     * Fixed minor typo (CSH instead of TCSH)
14     * Version 1.0.1: Tue Jun 3 1998
15     * Fixed sizeof instead of strlen bug
16     * Bumped up the version number to 1.0.1
17     * Version 1.0.2: Thu Jun 11 1998 (not present)
18     * Fixed gcc-2.8.1 warnings
19     * Fixed --version/-V option (not present)
20     * Version 1.0.5: Tue Jun 22 1999
21     * Make -u option work (not present)
22     * Version 1.0.6: Tue Jun 27 2000
23     * No important changes
24     * Version 1.1.0: Tue Jun 30 2000
25     * Added NLS support (partly written by Arkadiusz Mi<B6>kiewicz
26     * <misiek@misiek.eu.org>)
27     * Ported to Busybox - Alfred M. Szmidt <ams@trillian.itslinux.org>
28     * Removed --version/-V and --help/-h in
29     * Removed parse_error(), using bb_error_msg() from Busybox instead
30     * Replaced our_malloc with xmalloc and our_realloc with xrealloc
31     *
32     */
33    
34     #include "busybox.h"
35     #include <getopt.h>
36    
37     /* NON_OPT is the code that is returned when a non-option is found in '+'
38     mode */
39     enum {
40     NON_OPT = 1,
41     /* LONG_OPT is the code that is returned when a long option is found. */
42     LONG_OPT = 2
43     };
44    
45     /* The shells recognized. */
46     typedef enum {BASH,TCSH} shell_t;
47    
48    
49     /* Some global variables that tells us how to parse. */
50     static shell_t shell=BASH; /* The shell we generate output for. */
51     static int quiet_errors; /* 0 is not quiet. */
52     static int quiet_output; /* 0 is not quiet. */
53     static int quote=1; /* 1 is do quote. */
54     static int alternative; /* 0 is getopt_long, 1 is getopt_long_only */
55    
56     /* Function prototypes */
57     static const char *normalize(const char *arg);
58     static int generate_output(char * argv[],int argc,const char *optstr,
59     const struct option *longopts);
60     static void add_long_options(char *options);
61     static void add_longopt(const char *name,int has_arg);
62     static void set_shell(const char *new_shell);
63    
64    
65     /*
66     * This function 'normalizes' a single argument: it puts single quotes around
67     * it and escapes other special characters. If quote is false, it just
68     * returns its argument.
69     * Bash only needs special treatment for single quotes; tcsh also recognizes
70     * exclamation marks within single quotes, and nukes whitespace.
71     * This function returns a pointer to a buffer that is overwritten by
72     * each call.
73     */
74     const char *normalize(const char *arg)
75     {
76     static char *BUFFER=NULL;
77     const char *argptr=arg;
78     char *bufptr;
79    
80     free(BUFFER);
81    
82     if (!quote) { /* Just copy arg */
83     BUFFER=xstrdup(arg);
84     return BUFFER;
85     }
86    
87     /* Each character in arg may take up to four characters in the result:
88     For a quote we need a closing quote, a backslash, a quote and an
89     opening quote! We need also the global opening and closing quote,
90     and one extra character for '\0'. */
91     BUFFER=xmalloc(strlen(arg)*4+3);
92    
93     bufptr=BUFFER;
94     *bufptr++='\'';
95    
96     while (*argptr) {
97     if (*argptr == '\'') {
98     /* Quote: replace it with: '\'' */
99     *bufptr++='\'';
100     *bufptr++='\\';
101     *bufptr++='\'';
102     *bufptr++='\'';
103     } else if (shell==TCSH && *argptr=='!') {
104     /* Exclamation mark: replace it with: \! */
105     *bufptr++='\'';
106     *bufptr++='\\';
107     *bufptr++='!';
108     *bufptr++='\'';
109     } else if (shell==TCSH && *argptr=='\n') {
110     /* Newline: replace it with: \n */
111     *bufptr++='\\';
112     *bufptr++='n';
113     } else if (shell==TCSH && isspace(*argptr)) {
114     /* Non-newline whitespace: replace it with \<ws> */
115     *bufptr++='\'';
116     *bufptr++='\\';
117     *bufptr++=*argptr;
118     *bufptr++='\'';
119     } else
120     /* Just copy */
121     *bufptr++=*argptr;
122     argptr++;
123     }
124     *bufptr++='\'';
125     *bufptr++='\0';
126     return BUFFER;
127     }
128    
129     /*
130     * Generate the output. argv[0] is the program name (used for reporting errors).
131     * argv[1..] contains the options to be parsed. argc must be the number of
132     * elements in argv (ie. 1 if there are no options, only the program name),
133     * optstr must contain the short options, and longopts the long options.
134     * Other settings are found in global variables.
135     */
136     int generate_output(char * argv[],int argc,const char *optstr,
137     const struct option *longopts)
138     {
139     int exit_code = 0; /* We assume everything will be OK */
140     int opt;
141     int longindex;
142     const char *charptr;
143    
144     if (quiet_errors) /* No error reporting from getopt(3) */
145     opterr=0;
146     optind=0; /* Reset getopt(3) */
147    
148     while ((opt = (alternative?
149     getopt_long_only(argc,argv,optstr,longopts,&longindex):
150     getopt_long(argc,argv,optstr,longopts,&longindex)))
151     != EOF)
152     if (opt == '?' || opt == ':' )
153     exit_code = 1;
154     else if (!quiet_output) {
155     if (opt == LONG_OPT) {
156     printf(" --%s",longopts[longindex].name);
157     if (longopts[longindex].has_arg)
158     printf(" %s",
159     normalize(optarg?optarg:""));
160     } else if (opt == NON_OPT)
161     printf(" %s",normalize(optarg));
162     else {
163     printf(" -%c",opt);
164     charptr = strchr(optstr,opt);
165     if (charptr != NULL && *++charptr == ':')
166     printf(" %s",
167     normalize(optarg?optarg:""));
168     }
169     }
170    
171     if (! quiet_output) {
172     printf(" --");
173     while (optind < argc)
174     printf(" %s",normalize(argv[optind++]));
175     puts("");
176     }
177     return exit_code;
178     }
179    
180     static struct option *long_options;
181     static int long_options_length; /* Length of array */
182     static int long_options_nr; /* Nr of used elements in array */
183     enum { LONG_OPTIONS_INCR = 10 };
184     #define init_longopt() add_longopt(NULL,0)
185    
186     /* Register a long option. The contents of name is copied. */
187     void add_longopt(const char *name, int has_arg)
188     {
189     if (!name) { /* init */
190     free(long_options);
191     long_options=NULL;
192     long_options_length=0;
193     long_options_nr=0;
194     }
195    
196     if (long_options_nr == long_options_length) {
197     long_options_length += LONG_OPTIONS_INCR;
198     long_options=xrealloc(long_options,
199     sizeof(struct option) *
200     long_options_length);
201     }
202    
203     long_options[long_options_nr].name=NULL;
204     long_options[long_options_nr].has_arg=0;
205     long_options[long_options_nr].flag=NULL;
206     long_options[long_options_nr].val=0;
207    
208     if (long_options_nr) { /* Not for init! */
209     long_options[long_options_nr-1].has_arg=has_arg;
210     long_options[long_options_nr-1].flag=NULL;
211     long_options[long_options_nr-1].val=LONG_OPT;
212     long_options[long_options_nr-1].name=xstrdup(name);
213     }
214     long_options_nr++;
215     }
216    
217    
218     /*
219     * Register several long options. options is a string of long options,
220     * separated by commas or whitespace.
221     * This nukes options!
222     */
223     void add_long_options(char *options)
224     {
225     int arg_opt, tlen;
226     char *tokptr=strtok(options,", \t\n");
227     while (tokptr) {
228     arg_opt=no_argument;
229     tlen=strlen(tokptr);
230     if (tlen > 0) {
231     if (tokptr[tlen-1] == ':') {
232     if (tlen > 1 && tokptr[tlen-2] == ':') {
233     tokptr[tlen-2]='\0';
234     tlen -= 2;
235     arg_opt=optional_argument;
236     } else {
237     tokptr[tlen-1]='\0';
238     tlen -= 1;
239     arg_opt=required_argument;
240     }
241     if (tlen == 0)
242     bb_error_msg("empty long option after -l or --long argument");
243     }
244     add_longopt(tokptr,arg_opt);
245     }
246     tokptr=strtok(NULL,", \t\n");
247     }
248     }
249    
250     void set_shell(const char *new_shell)
251     {
252     if (!strcmp(new_shell,"bash"))
253     shell=BASH;
254     else if (!strcmp(new_shell,"tcsh"))
255     shell=TCSH;
256     else if (!strcmp(new_shell,"sh"))
257     shell=BASH;
258     else if (!strcmp(new_shell,"csh"))
259     shell=TCSH;
260     else
261     bb_error_msg("unknown shell after -s or --shell argument");
262     }
263    
264    
265     /* Exit codes:
266     * 0) No errors, successful operation.
267     * 1) getopt(3) returned an error.
268     * 2) A problem with parameter parsing for getopt(1).
269     * 3) Internal error, out of memory
270     * 4) Returned for -T
271     */
272    
273     static const struct option longopts[]=
274     {
275     {"options",required_argument,NULL,'o'},
276     {"longoptions",required_argument,NULL,'l'},
277     {"quiet",no_argument,NULL,'q'},
278     {"quiet-output",no_argument,NULL,'Q'},
279     {"shell",required_argument,NULL,'s'},
280     {"test",no_argument,NULL,'T'},
281     {"unquoted",no_argument,NULL,'u'},
282     {"alternative",no_argument,NULL,'a'},
283     {"name",required_argument,NULL,'n'},
284     {NULL,0,NULL,0}
285     };
286    
287     /* Stop scanning as soon as a non-option argument is found! */
288     static const char shortopts[]="+ao:l:n:qQs:Tu";
289    
290    
291     int getopt_main(int argc, char *argv[])
292     {
293     const char *optstr = NULL;
294     char *name = NULL;
295     int opt;
296     int compatible=0;
297    
298     init_longopt();
299    
300     if (getenv("GETOPT_COMPATIBLE"))
301     compatible=1;
302    
303     if (argc == 1) {
304     if (compatible) {
305     /* For some reason, the original getopt gave no error
306     when there were no arguments. */
307     printf(" --\n");
308     return 0;
309     } else
310     bb_error_msg_and_die("missing optstring argument");
311     }
312    
313     if (argv[1][0] != '-' || compatible) {
314     char *s;
315    
316     quote=0;
317     s=xmalloc(strlen(argv[1])+1);
318     strcpy(s,argv[1]+strspn(argv[1],"-+"));
319     argv[1]=argv[0];
320     return generate_output(argv+1,argc-1,s,long_options);
321     }
322    
323     while ((opt = getopt_long(argc,argv,shortopts,longopts,NULL)) != EOF)
324     switch (opt) {
325     case 'a':
326     alternative=1;
327     break;
328     case 'o':
329     optstr = optarg;
330     break;
331     case 'l':
332     add_long_options(optarg);
333     break;
334     case 'n':
335     name = optarg;
336     break;
337     case 'q':
338     quiet_errors=1;
339     break;
340     case 'Q':
341     quiet_output=1;
342     break;
343     case 's':
344     set_shell(optarg);
345     break;
346     case 'T':
347     return 4;
348     case 'u':
349     quote=0;
350     break;
351     default:
352     bb_show_usage();
353     }
354    
355     if (!optstr) {
356     if (optind >= argc)
357     bb_error_msg_and_die("missing optstring argument");
358     else optstr=argv[optind++];
359     }
360     if (name)
361     argv[optind-1]=name;
362     else
363     argv[optind-1]=argv[0];
364     return generate_output(argv+optind-1,argc-optind+1,optstr,long_options);
365     }