Magellan Linux

Annotation of /trunk/mkinitrd-magellan/busybox/util-linux/getopt.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 984 - (hide annotations) (download)
Sun May 30 11:32:42 2010 UTC (14 years ago) by niro
File MIME type: text/plain
File size: 9563 byte(s)
-updated to busybox-1.16.1 and enabled blkid/uuid support in default config
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 niro 816 * Added NLS support (partly written by Arkadiusz Mickiewicz
26 niro 532 * <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 <getopt.h>
35 niro 816 #include "libbb.h"
36 niro 532
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 niro 984 #if ENABLE_FEATURE_GETOPT_LONG
42 niro 532 /* LONG_OPT is the code that is returned when a long option is found. */
43     LONG_OPT = 2
44 niro 816 #endif
45 niro 532 };
46    
47 niro 816 /* For finding activated option flags. Must match getopt32 call! */
48     enum {
49     OPT_o = 0x1, // -o
50     OPT_n = 0x2, // -n
51     OPT_q = 0x4, // -q
52     OPT_Q = 0x8, // -Q
53     OPT_s = 0x10, // -s
54     OPT_T = 0x20, // -T
55     OPT_u = 0x40, // -u
56 niro 984 #if ENABLE_FEATURE_GETOPT_LONG
57 niro 816 OPT_a = 0x80, // -a
58     OPT_l = 0x100, // -l
59     #endif
60     SHELL_IS_TCSH = 0x8000, /* hijack this bit for other purposes */
61     };
62 niro 532
63 niro 816 /* 0 is getopt_long, 1 is getopt_long_only */
64     #define alternative (option_mask32 & OPT_a)
65 niro 532
66 niro 816 #define quiet_errors (option_mask32 & OPT_q)
67     #define quiet_output (option_mask32 & OPT_Q)
68     #define quote (!(option_mask32 & OPT_u))
69     #define shell_TCSH (option_mask32 & SHELL_IS_TCSH)
70 niro 532
71     /*
72     * This function 'normalizes' a single argument: it puts single quotes around
73     * it and escapes other special characters. If quote is false, it just
74     * returns its argument.
75     * Bash only needs special treatment for single quotes; tcsh also recognizes
76     * exclamation marks within single quotes, and nukes whitespace.
77     * This function returns a pointer to a buffer that is overwritten by
78     * each call.
79     */
80 niro 816 static const char *normalize(const char *arg)
81 niro 532 {
82     char *bufptr;
83 niro 816 #if ENABLE_FEATURE_CLEAN_UP
84     static char *BUFFER = NULL;
85 niro 532 free(BUFFER);
86 niro 816 #else
87     char *BUFFER;
88     #endif
89 niro 532
90     if (!quote) { /* Just copy arg */
91 niro 816 BUFFER = xstrdup(arg);
92 niro 532 return BUFFER;
93     }
94    
95     /* Each character in arg may take up to four characters in the result:
96     For a quote we need a closing quote, a backslash, a quote and an
97     opening quote! We need also the global opening and closing quote,
98     and one extra character for '\0'. */
99 niro 816 BUFFER = xmalloc(strlen(arg)*4 + 3);
100 niro 532
101 niro 816 bufptr = BUFFER;
102     *bufptr ++= '\'';
103 niro 532
104 niro 816 while (*arg) {
105     if (*arg == '\'') {
106 niro 532 /* Quote: replace it with: '\'' */
107 niro 816 *bufptr ++= '\'';
108     *bufptr ++= '\\';
109     *bufptr ++= '\'';
110     *bufptr ++= '\'';
111     } else if (shell_TCSH && *arg == '!') {
112 niro 532 /* Exclamation mark: replace it with: \! */
113 niro 816 *bufptr ++= '\'';
114     *bufptr ++= '\\';
115     *bufptr ++= '!';
116     *bufptr ++= '\'';
117     } else if (shell_TCSH && *arg == '\n') {
118 niro 532 /* Newline: replace it with: \n */
119 niro 816 *bufptr ++= '\\';
120     *bufptr ++= 'n';
121     } else if (shell_TCSH && isspace(*arg)) {
122 niro 532 /* Non-newline whitespace: replace it with \<ws> */
123 niro 816 *bufptr ++= '\'';
124     *bufptr ++= '\\';
125     *bufptr ++= *arg;
126     *bufptr ++= '\'';
127 niro 532 } else
128     /* Just copy */
129 niro 816 *bufptr ++= *arg;
130     arg++;
131 niro 532 }
132 niro 816 *bufptr ++= '\'';
133     *bufptr ++= '\0';
134 niro 532 return BUFFER;
135     }
136    
137     /*
138     * Generate the output. argv[0] is the program name (used for reporting errors).
139     * argv[1..] contains the options to be parsed. argc must be the number of
140     * elements in argv (ie. 1 if there are no options, only the program name),
141     * optstr must contain the short options, and longopts the long options.
142     * Other settings are found in global variables.
143     */
144 niro 984 #if !ENABLE_FEATURE_GETOPT_LONG
145 niro 816 #define generate_output(argv,argc,optstr,longopts) \
146     generate_output(argv,argc,optstr)
147     #endif
148     static int generate_output(char **argv, int argc, const char *optstr, const struct option *longopts)
149 niro 532 {
150     int exit_code = 0; /* We assume everything will be OK */
151     int opt;
152 niro 984 #if ENABLE_FEATURE_GETOPT_LONG
153 niro 532 int longindex;
154 niro 816 #endif
155 niro 532 const char *charptr;
156    
157     if (quiet_errors) /* No error reporting from getopt(3) */
158 niro 816 opterr = 0;
159 niro 532
160 niro 816 /* We used it already in main() in getopt32(),
161     * we *must* reset getopt(3): */
162     #ifdef __GLIBC__
163     optind = 0;
164     #else /* BSD style */
165     optind = 1;
166     /* optreset = 1; */
167     #endif
168    
169     while (1) {
170     opt =
171 niro 984 #if ENABLE_FEATURE_GETOPT_LONG
172 niro 816 alternative ?
173     getopt_long_only(argc, argv, optstr, longopts, &longindex) :
174     getopt_long(argc, argv, optstr, longopts, &longindex);
175     #else
176     getopt(argc, argv, optstr);
177     #endif
178     if (opt == -1)
179     break;
180 niro 532 if (opt == '?' || opt == ':' )
181     exit_code = 1;
182     else if (!quiet_output) {
183 niro 984 #if ENABLE_FEATURE_GETOPT_LONG
184 niro 532 if (opt == LONG_OPT) {
185 niro 816 printf(" --%s", longopts[longindex].name);
186 niro 532 if (longopts[longindex].has_arg)
187     printf(" %s",
188 niro 816 normalize(optarg ? optarg : ""));
189     } else
190     #endif
191     if (opt == NON_OPT)
192     printf(" %s", normalize(optarg));
193 niro 532 else {
194 niro 816 printf(" -%c", opt);
195     charptr = strchr(optstr, opt);
196 niro 532 if (charptr != NULL && *++charptr == ':')
197     printf(" %s",
198 niro 816 normalize(optarg ? optarg : ""));
199 niro 532 }
200     }
201 niro 816 }
202 niro 532
203 niro 816 if (!quiet_output) {
204 niro 532 printf(" --");
205     while (optind < argc)
206 niro 816 printf(" %s", normalize(argv[optind++]));
207     bb_putchar('\n');
208 niro 532 }
209     return exit_code;
210     }
211    
212 niro 984 #if ENABLE_FEATURE_GETOPT_LONG
213 niro 532 /*
214     * Register several long options. options is a string of long options,
215     * separated by commas or whitespace.
216     * This nukes options!
217     */
218 niro 816 static struct option *add_long_options(struct option *long_options, char *options)
219 niro 532 {
220 niro 816 int long_nr = 0;
221 niro 532 int arg_opt, tlen;
222 niro 816 char *tokptr = strtok(options, ", \t\n");
223    
224     if (long_options)
225     while (long_options[long_nr].name)
226     long_nr++;
227    
228 niro 532 while (tokptr) {
229 niro 816 arg_opt = no_argument;
230     tlen = strlen(tokptr);
231     if (tlen) {
232     tlen--;
233     if (tokptr[tlen] == ':') {
234     arg_opt = required_argument;
235     if (tlen && tokptr[tlen-1] == ':') {
236     tlen--;
237     arg_opt = optional_argument;
238 niro 532 }
239 niro 816 tokptr[tlen] = '\0';
240 niro 532 if (tlen == 0)
241 niro 816 bb_error_msg_and_die("empty long option specified");
242 niro 532 }
243 niro 816 long_options = xrealloc_vector(long_options, 4, long_nr);
244     long_options[long_nr].has_arg = arg_opt;
245     /*long_options[long_nr].flag = NULL; - xrealloc_vector did it */
246     long_options[long_nr].val = LONG_OPT;
247     long_options[long_nr].name = xstrdup(tokptr);
248     long_nr++;
249     /*memset(&long_options[long_nr], 0, sizeof(long_options[0])); - xrealloc_vector did it */
250 niro 532 }
251 niro 816 tokptr = strtok(NULL, ", \t\n");
252 niro 532 }
253 niro 816 return long_options;
254 niro 532 }
255 niro 816 #endif
256 niro 532
257 niro 816 static void set_shell(const char *new_shell)
258 niro 532 {
259 niro 816 if (!strcmp(new_shell, "bash") || !strcmp(new_shell, "sh"))
260     return;
261     if (!strcmp(new_shell, "tcsh") || !strcmp(new_shell, "csh"))
262     option_mask32 |= SHELL_IS_TCSH;
263 niro 532 else
264 niro 816 bb_error_msg("unknown shell '%s', assuming bash", new_shell);
265 niro 532 }
266    
267    
268     /* Exit codes:
269     * 0) No errors, successful operation.
270     * 1) getopt(3) returned an error.
271     * 2) A problem with parameter parsing for getopt(1).
272     * 3) Internal error, out of memory
273     * 4) Returned for -T
274     */
275    
276 niro 984 #if ENABLE_FEATURE_GETOPT_LONG
277 niro 816 static const char getopt_longopts[] ALIGN1 =
278     "options\0" Required_argument "o"
279     "longoptions\0" Required_argument "l"
280     "quiet\0" No_argument "q"
281     "quiet-output\0" No_argument "Q"
282     "shell\0" Required_argument "s"
283     "test\0" No_argument "T"
284     "unquoted\0" No_argument "u"
285     "alternative\0" No_argument "a"
286     "name\0" Required_argument "n"
287     ;
288     #endif
289 niro 532
290 niro 816 int getopt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
291     int getopt_main(int argc, char **argv)
292 niro 532 {
293 niro 816 char *optstr = NULL;
294 niro 532 char *name = NULL;
295 niro 816 unsigned opt;
296     const char *compatible;
297     char *s_arg;
298 niro 984 #if ENABLE_FEATURE_GETOPT_LONG
299 niro 816 struct option *long_options = NULL;
300     llist_t *l_arg = NULL;
301     #endif
302 niro 532
303 niro 816 compatible = getenv("GETOPT_COMPATIBLE"); /* used as yes/no flag */
304 niro 532
305     if (argc == 1) {
306     if (compatible) {
307     /* For some reason, the original getopt gave no error
308     when there were no arguments. */
309     printf(" --\n");
310     return 0;
311 niro 816 }
312     bb_error_msg_and_die("missing optstring argument");
313 niro 532 }
314    
315     if (argv[1][0] != '-' || compatible) {
316     char *s;
317    
318 niro 816 option_mask32 |= OPT_u; /* quoting off */
319     s = xstrdup(argv[1] + strspn(argv[1], "-+"));
320     argv[1] = argv[0];
321     return generate_output(argv+1, argc-1, s, long_options);
322 niro 532 }
323    
324 niro 984 #if !ENABLE_FEATURE_GETOPT_LONG
325 niro 816 opt = getopt32(argv, "+o:n:qQs:Tu", &optstr, &name, &s_arg);
326     #else
327     applet_long_options = getopt_longopts;
328     opt_complementary = "l::";
329     opt = getopt32(argv, "+o:n:qQs:Tual:",
330     &optstr, &name, &s_arg, &l_arg);
331     /* Effectuate the read options for the applet itself */
332     while (l_arg) {
333     long_options = add_long_options(long_options, llist_pop(&l_arg));
334     }
335     #endif
336 niro 532
337 niro 816 if (opt & OPT_s) {
338     set_shell(s_arg);
339     }
340    
341     if (opt & OPT_T) {
342     return 4;
343     }
344    
345     /* All options controlling the applet have now been parsed */
346 niro 532 if (!optstr) {
347     if (optind >= argc)
348     bb_error_msg_and_die("missing optstring argument");
349 niro 816 optstr = argv[optind++];
350 niro 532 }
351 niro 816
352     argv[optind-1] = name ? name : argv[0];
353     return generate_output(argv+optind-1, argc-optind+1, optstr, long_options);
354 niro 532 }