aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2007-04-07 10:25:04 +0000
committervda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2007-04-07 10:25:04 +0000
commit856f5842cce6d45cb91d7ae59f445120715fcd79 (patch)
tree498ea2fc84be4966ebf210fdb4d995d16b23c9f8
parentc891e27bc28236ed070971f7cf5b27dea656ad93 (diff)
downloadbusybox-w32-856f5842cce6d45cb91d7ae59f445120715fcd79.tar.gz
busybox-w32-856f5842cce6d45cb91d7ae59f445120715fcd79.tar.bz2
busybox-w32-856f5842cce6d45cb91d7ae59f445120715fcd79.zip
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 git-svn-id: svn://busybox.net/trunk/busybox@18359 69ca8d6d-28ef-0310-b511-8ec308f3f277
-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 {
42 LONG_OPT = 2 42 LONG_OPT = 2
43}; 43};
44 44
45/* The shells recognized. */ 45/* For finding activated option flags. Must match getopt32 call! */
46typedef enum {BASH,TCSH} shell_t; 46enum {
47 47 OPT_o = 0x1, // -o
48 48 OPT_n = 0x2, // -n
49/* Some global variables that tells us how to parse. */ 49 OPT_q = 0x4, // -q
50static shell_t shell=BASH; /* The shell we generate output for. */ 50 OPT_Q = 0x8, // -Q
51static int quiet_errors; /* 0 is not quiet. */ 51 OPT_s = 0x10, // -s
52static int quiet_output; /* 0 is not quiet. */ 52 OPT_T = 0x20, // -T
53static int quote=1; /* 1 is do quote. */ 53 OPT_u = 0x40, // -u
54static int alternative; /* 0 is getopt_long, 1 is getopt_long_only */ 54#if ENABLE_GETOPT_LONG
55 OPT_a = 0x80, // -a
56 OPT_l = 0x100, // -l
57#endif
58 SHELL_IS_TCSH = 0x8000, /* hijack this bit for other purposes */
59};
55 60
56/* Function prototypes */ 61/* 0 is getopt_long, 1 is getopt_long_only */
57static const char *normalize(const char *arg); 62#define alternative (option_mask32 & OPT_a)
58static int generate_output(char **argv,int argc,const char *optstr,
59 const struct option *longopts);
60static void add_long_options(char *options);
61static void add_longopt(const char *name,int has_arg);
62static void set_shell(const char *new_shell);
63 63
64#define quiet_errors (option_mask32 & OPT_q)
65#define quiet_output (option_mask32 & OPT_Q)
66#define quote (!(option_mask32 & OPT_u))
67#define shell_TCSH (option_mask32 & SHELL_IS_TCSH)
64 68
65/* 69/*
66 * This function 'normalizes' a single argument: it puts single quotes around 70 * This function 'normalizes' a single argument: it puts single quotes around
@@ -71,16 +75,18 @@ static void set_shell(const char *new_shell);
71 * This function returns a pointer to a buffer that is overwritten by 75 * This function returns a pointer to a buffer that is overwritten by
72 * each call. 76 * each call.
73 */ 77 */
74const char *normalize(const char *arg) 78static const char *normalize(const char *arg)
75{ 79{
76 static char *BUFFER=NULL;
77 const char *argptr=arg;
78 char *bufptr; 80 char *bufptr;
79 81#if ENABLE_FEATURE_CLEAN_UP
82 static char *BUFFER = NULL;
80 free(BUFFER); 83 free(BUFFER);
84#else
85 char *BUFFER;
86#endif
81 87
82 if (!quote) { /* Just copy arg */ 88 if (!quote) { /* Just copy arg */
83 BUFFER=xstrdup(arg); 89 BUFFER = xstrdup(arg);
84 return BUFFER; 90 return BUFFER;
85 } 91 }
86 92
@@ -88,41 +94,41 @@ const char *normalize(const char *arg)
88 For a quote we need a closing quote, a backslash, a quote and an 94 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, 95 opening quote! We need also the global opening and closing quote,
90 and one extra character for '\0'. */ 96 and one extra character for '\0'. */
91 BUFFER=xmalloc(strlen(arg)*4+3); 97 BUFFER = xmalloc(strlen(arg)*4 + 3);
92 98
93 bufptr=BUFFER; 99 bufptr = BUFFER;
94 *bufptr++='\''; 100 *bufptr ++= '\'';
95 101
96 while (*argptr) { 102 while (*arg) {
97 if (*argptr == '\'') { 103 if (*arg == '\'') {
98 /* Quote: replace it with: '\'' */ 104 /* Quote: replace it with: '\'' */
99 *bufptr++='\''; 105 *bufptr ++= '\'';
100 *bufptr++='\\'; 106 *bufptr ++= '\\';
101 *bufptr++='\''; 107 *bufptr ++= '\'';
102 *bufptr++='\''; 108 *bufptr ++= '\'';
103 } else if (shell==TCSH && *argptr=='!') { 109 } else if (shell_TCSH && *arg == '!') {
104 /* Exclamation mark: replace it with: \! */ 110 /* Exclamation mark: replace it with: \! */
105 *bufptr++='\''; 111 *bufptr ++= '\'';
106 *bufptr++='\\'; 112 *bufptr ++= '\\';
107 *bufptr++='!'; 113 *bufptr ++= '!';
108 *bufptr++='\''; 114 *bufptr ++= '\'';
109 } else if (shell==TCSH && *argptr=='\n') { 115 } else if (shell_TCSH && *arg == '\n') {
110 /* Newline: replace it with: \n */ 116 /* Newline: replace it with: \n */
111 *bufptr++='\\'; 117 *bufptr ++= '\\';
112 *bufptr++='n'; 118 *bufptr ++= 'n';
113 } else if (shell==TCSH && isspace(*argptr)) { 119 } else if (shell_TCSH && isspace(*arg)) {
114 /* Non-newline whitespace: replace it with \<ws> */ 120 /* Non-newline whitespace: replace it with \<ws> */
115 *bufptr++='\''; 121 *bufptr ++= '\'';
116 *bufptr++='\\'; 122 *bufptr ++= '\\';
117 *bufptr++=*argptr; 123 *bufptr ++= *arg;
118 *bufptr++='\''; 124 *bufptr ++= '\'';
119 } else 125 } else
120 /* Just copy */ 126 /* Just copy */
121 *bufptr++=*argptr; 127 *bufptr ++= *arg;
122 argptr++; 128 arg++;
123 } 129 }
124 *bufptr++='\''; 130 *bufptr ++= '\'';
125 *bufptr++='\0'; 131 *bufptr ++= '\0';
126 return BUFFER; 132 return BUFFER;
127} 133}
128 134
@@ -133,132 +139,102 @@ const char *normalize(const char *arg)
133 * optstr must contain the short options, and longopts the long options. 139 * optstr must contain the short options, and longopts the long options.
134 * Other settings are found in global variables. 140 * Other settings are found in global variables.
135 */ 141 */
136int generate_output(char **argv,int argc,const char *optstr, 142static int generate_output(char * argv[],int argc,const char *optstr,
137 const struct option *longopts) 143 const struct option *longopts)
138{ 144{
139 int exit_code = 0; /* We assume everything will be OK */ 145 int exit_code = 0; /* We assume everything will be OK */
140 int opt; 146 unsigned opt;
141 int longindex; 147 int longindex;
142 const char *charptr; 148 const char *charptr;
143 149
144 if (quiet_errors) /* No error reporting from getopt(3) */ 150 if (quiet_errors) /* No error reporting from getopt(3) */
145 opterr=0; 151 opterr = 0;
146 optind=0; /* Reset getopt(3) */ 152 optind = 0; /* Reset getopt(3) */
147 153
148 while ((opt = (alternative? 154 while ((opt = (alternative ?
149 getopt_long_only(argc,argv,optstr,longopts,&longindex): 155 getopt_long_only(argc,argv,optstr,longopts,&longindex) :
150 getopt_long(argc,argv,optstr,longopts,&longindex))) 156 getopt_long(argc,argv,optstr,longopts,&longindex)))
151 != EOF) 157 != EOF)
152 if (opt == '?' || opt == ':' ) 158 if (opt == '?' || opt == ':' )
153 exit_code = 1; 159 exit_code = 1;
154 else if (!quiet_output) { 160 else if (!quiet_output) {
155 if (opt == LONG_OPT) { 161 if (opt == LONG_OPT) {
156 printf(" --%s",longopts[longindex].name); 162 printf(" --%s", longopts[longindex].name);
157 if (longopts[longindex].has_arg) 163 if (longopts[longindex].has_arg)
158 printf(" %s", 164 printf(" %s",
159 normalize(optarg?optarg:"")); 165 normalize(optarg ? optarg : ""));
160 } else if (opt == NON_OPT) 166 } else if (opt == NON_OPT)
161 printf(" %s",normalize(optarg)); 167 printf(" %s", normalize(optarg));
162 else { 168 else {
163 printf(" -%c",opt); 169 printf(" -%c", opt);
164 charptr = strchr(optstr,opt); 170 charptr = strchr(optstr,opt);
165 if (charptr != NULL && *++charptr == ':') 171 if (charptr != NULL && *++charptr == ':')
166 printf(" %s", 172 printf(" %s",
167 normalize(optarg?optarg:"")); 173 normalize(optarg ? optarg : ""));
168 } 174 }
169 } 175 }
170 176
171 if (! quiet_output) { 177 if (!quiet_output) {
172 printf(" --"); 178 printf(" --");
173 while (optind < argc) 179 while (optind < argc)
174 printf(" %s",normalize(argv[optind++])); 180 printf(" %s", normalize(argv[optind++]));
175 puts(""); 181 puts("");
176 } 182 }
177 return exit_code; 183 return exit_code;
178} 184}
179 185
180static struct option *long_options;
181static int long_options_length; /* Length of array */
182static int long_options_nr; /* Nr of used elements in array */
183enum { LONG_OPTIONS_INCR = 10 };
184#define init_longopt() add_longopt(NULL,0)
185
186/* Register a long option. The contents of name is copied. */
187void 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/* 186/*
219 * Register several long options. options is a string of long options, 187 * Register several long options. options is a string of long options,
220 * separated by commas or whitespace. 188 * separated by commas or whitespace.
221 * This nukes options! 189 * This nukes options!
222 */ 190 */
223void add_long_options(char *options) 191static struct option *add_long_options(struct option *long_options, char *options)
224{ 192{
193 int long_nr = 0;
225 int arg_opt, tlen; 194 int arg_opt, tlen;
226 char *tokptr=strtok(options,", \t\n"); 195 char *tokptr = strtok(options, ", \t\n");
196
197 if (long_options)
198 while (long_options[long_nr].name)
199 long_nr++;
200
227 while (tokptr) { 201 while (tokptr) {
228 arg_opt=no_argument; 202 arg_opt = no_argument;
229 tlen=strlen(tokptr); 203 tlen = strlen(tokptr);
230 if (tlen > 0) { 204 if (tlen) {
231 if (tokptr[tlen-1] == ':') { 205 tlen--;
232 if (tlen > 1 && tokptr[tlen-2] == ':') { 206 if (tokptr[tlen] == ':') {
233 tokptr[tlen-2]='\0'; 207 arg_opt = required_argument;
234 tlen -= 2; 208 if (tlen && tokptr[tlen-1] == ':') {
235 arg_opt=optional_argument; 209 tlen--;
236 } else { 210 arg_opt = optional_argument;
237 tokptr[tlen-1]='\0';
238 tlen -= 1;
239 arg_opt=required_argument;
240 } 211 }
212 tokptr[tlen] = '\0';
241 if (tlen == 0) 213 if (tlen == 0)
242 bb_error_msg("empty long option after -l or --long argument"); 214 bb_error_msg_and_die("empty long option specified");
243 } 215 }
244 add_longopt(tokptr,arg_opt); 216 long_options = xrealloc(long_options,
217 sizeof(long_options[0]) * (long_nr+2));
218 long_options[long_nr].has_arg = arg_opt;
219 long_options[long_nr].flag = NULL;
220 long_options[long_nr].val = LONG_OPT;
221 long_options[long_nr].name = xstrdup(tokptr);
222 long_nr++;
223 memset(&long_options[long_nr], 0, sizeof(long_options[0]));
245 } 224 }
246 tokptr=strtok(NULL,", \t\n"); 225 tokptr = strtok(NULL, ", \t\n");
247 } 226 }
227 return long_options;
248} 228}
249 229
250void set_shell(const char *new_shell) 230static void set_shell(const char *new_shell)
251{ 231{
252 if (!strcmp(new_shell,"bash")) 232 if (!strcmp(new_shell,"bash") || !strcmp(new_shell,"sh"))
253 shell=BASH; 233 return;
254 else if (!strcmp(new_shell,"tcsh")) 234 if (!strcmp(new_shell,"tcsh") || !strcmp(new_shell,"csh"))
255 shell=TCSH; 235 option_mask32 |= SHELL_IS_TCSH;
256 else if (!strcmp(new_shell,"sh"))
257 shell=BASH;
258 else if (!strcmp(new_shell,"csh"))
259 shell=TCSH;
260 else 236 else
261 bb_error_msg("unknown shell after -s or --shell argument"); 237 bb_error_msg("unknown shell '%s', assuming bash", new_shell);
262} 238}
263 239
264 240
@@ -270,36 +246,35 @@ void set_shell(const char *new_shell)
270 * 4) Returned for -T 246 * 4) Returned for -T
271 */ 247 */
272 248
273static const struct option longopts[]= 249#if ENABLE_GETOPT_LONG
274{ 250static const struct option longopts[] = {
275 {"options",required_argument,NULL,'o'}, 251 { "options", required_argument, NULL, 'o' },
276 {"longoptions",required_argument,NULL,'l'}, 252 { "longoptions", required_argument, NULL, 'l' },
277 {"quiet",no_argument,NULL,'q'}, 253 { "quiet", no_argument, NULL, 'q' },
278 {"quiet-output",no_argument,NULL,'Q'}, 254 { "quiet-output", no_argument, NULL, 'Q' },
279 {"shell",required_argument,NULL,'s'}, 255 { "shell", required_argument, NULL, 's' },
280 {"test",no_argument,NULL,'T'}, 256 { "test", no_argument, NULL, 'T' },
281 {"unquoted",no_argument,NULL,'u'}, 257 { "unquoted", no_argument, NULL, 'u' },
282 {"alternative",no_argument,NULL,'a'}, 258 { "alternative", no_argument, NULL, 'a' },
283 {"name",required_argument,NULL,'n'}, 259 { "name", required_argument, NULL, 'n' },
284 {NULL,0,NULL,0} 260 { NULL, 0, NULL, 0 }
285}; 261};
262#endif
286 263
287/* Stop scanning as soon as a non-option argument is found! */ 264int getopt_main(int argc, char *argv[]);
288static const char shortopts[]="+ao:l:n:qQs:Tu"; 265int getopt_main(int argc, char *argv[])
289
290
291int getopt_main(int argc, char **argv);
292int getopt_main(int argc, char **argv)
293{ 266{
294 const char *optstr = NULL; 267 struct option *long_options = NULL;
268 char *optstr = NULL;
295 char *name = NULL; 269 char *name = NULL;
296 int opt; 270 unsigned opt;
297 int compatible=0; 271 const char *compatible;
272 char *s_arg;
273#if ENABLE_GETOPT_LONG
274 llist_t *l_arg = NULL;
275#endif
298 276
299 init_longopt(); 277 compatible = getenv("GETOPT_COMPATIBLE"); /* used as yes/no flag */
300
301 if (getenv("GETOPT_COMPATIBLE"))
302 compatible=1;
303 278
304 if (argc == 1) { 279 if (argc == 1) {
305 if (compatible) { 280 if (compatible) {
@@ -307,60 +282,48 @@ int getopt_main(int argc, char **argv)
307 when there were no arguments. */ 282 when there were no arguments. */
308 printf(" --\n"); 283 printf(" --\n");
309 return 0; 284 return 0;
310 } else 285 }
311 bb_error_msg_and_die("missing optstring argument"); 286 bb_error_msg_and_die("missing optstring argument");
312 } 287 }
313 288
314 if (argv[1][0] != '-' || compatible) { 289 if (argv[1][0] != '-' || compatible) {
315 char *s; 290 char *s;
316 291
317 quote=0; 292 option_mask32 |= OPT_u; /* quoting off */
318 s=xmalloc(strlen(argv[1])+1); 293 s = xstrdup(argv[1] + strspn(argv[1], "-+"));
319 strcpy(s,argv[1]+strspn(argv[1],"-+")); 294 argv[1] = argv[0];
320 argv[1]=argv[0]; 295 return generate_output(argv+1, argc-1, s, long_options);
321 return generate_output(argv+1,argc-1,s,long_options);
322 } 296 }
323 297
324 while ((opt = getopt_long(argc,argv,shortopts,longopts,NULL)) != EOF) 298#if !ENABLE_GETOPT_LONG
325 switch (opt) { 299 opt = getopt32(argc, argv, "+o:n:qQs:Tu", &optstr, &name, &s_arg);
326 case 'a': 300#else
327 alternative=1; 301 applet_long_options = longopts;
328 break; 302 opt_complementary = "?:l::";
329 case 'o': 303 opt = getopt32(argc, argv, "+o:n:qQs:Tual:",
330 optstr = optarg; 304 &optstr, &name, &s_arg, &l_arg);
331 break; 305 /* Effectuate the read options for the applet itself */
332 case 'l': 306 while (l_arg) {
333 add_long_options(optarg); 307 long_options = add_long_options(long_options, l_arg->data);
334 break; 308 l_arg = l_arg->link;
335 case 'n': 309 }
336 name = optarg; 310#endif
337 break; 311
338 case 'q': 312 if (opt & OPT_s) {
339 quiet_errors=1; 313 set_shell(s_arg);
340 break; 314 }
341 case 'Q':
342 quiet_output=1;
343 break;
344 case 's':
345 set_shell(optarg);
346 break;
347 case 'T':
348 return 4;
349 case 'u':
350 quote=0;
351 break;
352 default:
353 bb_show_usage();
354 }
355 315
316 if (opt & OPT_T) {
317 return 4;
318 }
319
320 /* All options controlling the applet have now been parsed */
356 if (!optstr) { 321 if (!optstr) {
357 if (optind >= argc) 322 if (optind >= argc)
358 bb_error_msg_and_die("missing optstring argument"); 323 bb_error_msg_and_die("missing optstring argument");
359 else optstr=argv[optind++]; 324 optstr = argv[optind++];
360 } 325 }
361 if (name) 326
362 argv[optind-1]=name; 327 argv[optind-1] = name ? name : argv[0];
363 else 328 return generate_output(argv+optind-1, argc-optind+1, optstr, long_options);
364 argv[optind-1]=argv[0];
365 return generate_output(argv+optind-1,argc-optind+1,optstr,long_options);
366} 329}