diff options
author | "Vladimir N. Oleynik" <dzo@simtreas.ru> | 2005-10-11 14:38:01 +0000 |
---|---|---|
committer | "Vladimir N. Oleynik" <dzo@simtreas.ru> | 2005-10-11 14:38:01 +0000 |
commit | 064f04e7e2b1316f7c3de1ac7dd1fc4d4e108dd5 (patch) | |
tree | dcf88d0a287b1f154984bfc0acb292631df2f1f3 /libbb | |
parent | ff567f7943f50b88dea14cd27636168ba2d319b5 (diff) | |
download | busybox-w32-064f04e7e2b1316f7c3de1ac7dd1fc4d4e108dd5.tar.gz busybox-w32-064f04e7e2b1316f7c3de1ac7dd1fc4d4e108dd5.tar.bz2 busybox-w32-064f04e7e2b1316f7c3de1ac7dd1fc4d4e108dd5.zip |
- use complementally '!' to '?' - 'ask' is best 'free' char for this.
- more long opt compatibility, can set flag for long opt struct now
- more logic: check opt-depend requires and global requires, special for 'id' and 'start-stop-daemon' applets.
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/getopt_ulflags.c | 108 |
1 files changed, 72 insertions, 36 deletions
diff --git a/libbb/getopt_ulflags.c b/libbb/getopt_ulflags.c index 2e2ee0b6b..5f35c583c 100644 --- a/libbb/getopt_ulflags.c +++ b/libbb/getopt_ulflags.c | |||
@@ -197,8 +197,9 @@ Special characters: | |||
197 | if (flags & BB_GETOPT_ERROR) | 197 | if (flags & BB_GETOPT_ERROR) |
198 | bb_show_usage(); | 198 | bb_show_usage(); |
199 | 199 | ||
200 | "!" If previous point set BB_GETOPT_ERROR, don`t return and call | 200 | "?" A "ask" as the first char in a bb_opt_complementally group give: |
201 | previous example internally | 201 | if previous point set BB_GETOPT_ERROR, don`t return and |
202 | call previous example internally | ||
202 | 203 | ||
203 | "*" A star after a char in bb_opt_complementally means that the | 204 | "*" A star after a char in bb_opt_complementally means that the |
204 | option can occur multiple times: | 205 | option can occur multiple times: |
@@ -218,16 +219,38 @@ Special characters: | |||
218 | $ grep -e user -e root /etc/passwd | 219 | $ grep -e user -e root /etc/passwd |
219 | root:x:0:0:root:/root:/bin/bash | 220 | root:x:0:0:root:/root:/bin/bash |
220 | user:x:500:500::/home/user:/bin/bash | 221 | user:x:500:500::/home/user:/bin/bash |
222 | |||
223 | "?" A "ask" between main and group options causes the second of the two | ||
224 | to be depending required if first is given on the command line. | ||
225 | For example from "id" applet: | ||
226 | |||
227 | // Don't allow -n -r -rn -ug -rug -nug -rnug | ||
228 | bb_opt_complementally = "?u~g:g~u:r?ug:n?ug"; | ||
229 | flags = bb_getopt_ulflags(argc, argv, "rnug"); | ||
230 | |||
231 | This example allowed only: | ||
232 | $ id; id -u; id -g; id -ru; id -nu; id -rg; id -ng; id -rnu; id -rng | ||
233 | |||
234 | "?" A "ask" between equivalent options in bb_opt_complementally means | ||
235 | requires this option always, checked after switch off from | ||
236 | complementally logic | ||
237 | For example from "start-stop-daemon" applet: | ||
238 | |||
239 | // Don't allow -KS -SK, but -S or -K required | ||
240 | bb_opt_complementally = "?:K?K:S?S:K~S:S~K"; | ||
241 | flags = bb_getopt_ulflags(argc, argv, "KS...); | ||
242 | |||
221 | */ | 243 | */ |
222 | 244 | ||
223 | const char *bb_opt_complementally; | 245 | const char *bb_opt_complementally; |
224 | 246 | ||
225 | typedef struct { | 247 | typedef struct { |
226 | unsigned char opt; | 248 | int opt; |
227 | char list_flg; | 249 | int list_flg; |
228 | unsigned long switch_on; | 250 | unsigned long switch_on; |
229 | unsigned long switch_off; | 251 | unsigned long switch_off; |
230 | unsigned long incongruously; | 252 | unsigned long incongruously; |
253 | unsigned long requires; | ||
231 | void **optarg; /* char **optarg or llist_t **optarg */ | 254 | void **optarg; /* char **optarg or llist_t **optarg */ |
232 | int *counter; | 255 | int *counter; |
233 | } t_complementally; | 256 | } t_complementally; |
@@ -245,17 +268,20 @@ unsigned long | |||
245 | bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) | 268 | bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) |
246 | { | 269 | { |
247 | unsigned long flags = 0; | 270 | unsigned long flags = 0; |
271 | unsigned long requires = 0; | ||
248 | t_complementally complementally[sizeof(flags) * 8 + 1]; | 272 | t_complementally complementally[sizeof(flags) * 8 + 1]; |
249 | int c; | 273 | int c; |
250 | const unsigned char *s; | 274 | const unsigned char *s; |
251 | t_complementally *on_off; | 275 | t_complementally *on_off; |
252 | va_list p; | 276 | va_list p; |
253 | const struct option *l_o; | 277 | const struct option *l_o; |
254 | char flg_show_usage_if_error = 0; | ||
255 | char flg_argv_is_opts = 0; | ||
256 | unsigned long trigger; | 278 | unsigned long trigger; |
257 | char **pargv = NULL; | 279 | char **pargv = NULL; |
258 | 280 | ||
281 | #define SHOW_USAGE_IF_ERROR 1 | ||
282 | #define ARGV_IS_OPTS 2 | ||
283 | int spec_flgs = 0; | ||
284 | |||
259 | va_start (p, applet_opts); | 285 | va_start (p, applet_opts); |
260 | 286 | ||
261 | /* skip GNU extension */ | 287 | /* skip GNU extension */ |
@@ -265,16 +291,13 @@ bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) | |||
265 | 291 | ||
266 | c = 0; | 292 | c = 0; |
267 | on_off = complementally; | 293 | on_off = complementally; |
294 | memset(on_off, 0, sizeof(complementally)); | ||
295 | |||
268 | for (; *s; s++) { | 296 | for (; *s; s++) { |
269 | if(c >= (int)(sizeof(flags)*8)) | 297 | if(c >= (int)(sizeof(flags)*8)) |
270 | break; | 298 | break; |
271 | on_off->opt = *s; | 299 | on_off->opt = *s; |
272 | on_off->switch_on = (1 << c); | 300 | on_off->switch_on = (1 << c); |
273 | on_off->list_flg = 0; | ||
274 | on_off->switch_off = 0; | ||
275 | on_off->incongruously = 0; | ||
276 | on_off->optarg = NULL; | ||
277 | on_off->counter = NULL; | ||
278 | if (s[1] == ':') { | 301 | if (s[1] == ':') { |
279 | on_off->optarg = va_arg (p, void **); | 302 | on_off->optarg = va_arg (p, void **); |
280 | do | 303 | do |
@@ -284,9 +307,10 @@ bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) | |||
284 | on_off++; | 307 | on_off++; |
285 | c++; | 308 | c++; |
286 | } | 309 | } |
287 | on_off->opt = 0; | ||
288 | 310 | ||
289 | for(l_o = bb_applet_long_options; l_o->name; l_o++) { | 311 | for(l_o = bb_applet_long_options; l_o->name; l_o++) { |
312 | if(l_o->flag) | ||
313 | continue; | ||
290 | for(on_off = complementally; on_off->opt != 0; on_off++) | 314 | for(on_off = complementally; on_off->opt != 0; on_off++) |
291 | if(on_off->opt == l_o->val) | 315 | if(on_off->opt == l_o->val) |
292 | break; | 316 | break; |
@@ -295,16 +319,8 @@ bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) | |||
295 | break; | 319 | break; |
296 | on_off->opt = l_o->val; | 320 | on_off->opt = l_o->val; |
297 | on_off->switch_on = (1 << c); | 321 | on_off->switch_on = (1 << c); |
298 | on_off->list_flg = 0; | ||
299 | on_off->switch_off = 0; | ||
300 | on_off->incongruously = 0; | ||
301 | on_off->counter = NULL; | ||
302 | if(l_o->has_arg != no_argument) | 322 | if(l_o->has_arg != no_argument) |
303 | on_off->optarg = va_arg (p, void **); | 323 | on_off->optarg = va_arg (p, void **); |
304 | else | ||
305 | on_off->optarg = NULL; | ||
306 | on_off++; | ||
307 | on_off->opt = 0; | ||
308 | c++; | 324 | c++; |
309 | } | 325 | } |
310 | } | 326 | } |
@@ -318,12 +334,12 @@ bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) | |||
318 | } | 334 | } |
319 | if (c) | 335 | if (c) |
320 | continue; | 336 | continue; |
321 | if(*s == '!') { | 337 | if(*s == '?') { |
322 | flg_show_usage_if_error = '!'; | 338 | spec_flgs |= SHOW_USAGE_IF_ERROR; |
323 | continue; | 339 | continue; |
324 | } | 340 | } |
325 | if(*s == '-') { | 341 | if(*s == '-') { |
326 | flg_argv_is_opts = '-'; | 342 | spec_flgs |= ARGV_IS_OPTS; |
327 | continue; | 343 | continue; |
328 | } | 344 | } |
329 | for (on_off = complementally; on_off->opt; on_off++) | 345 | for (on_off = complementally; on_off->opt; on_off++) |
@@ -331,18 +347,32 @@ bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) | |||
331 | break; | 347 | break; |
332 | pair = on_off; | 348 | pair = on_off; |
333 | for(s++; *s && *s != ':'; s++) { | 349 | for(s++; *s && *s != ':'; s++) { |
334 | if (*s == '-' || *s == '~') { | 350 | if (*s == '-' || *s == '~' || *s == '?') { |
335 | c = *s; | 351 | c = *s; |
336 | } else if(*s == '*') { | 352 | } else if(*s == '*') { |
337 | pair->list_flg++; | 353 | pair->list_flg++; |
338 | } else { | 354 | } else { |
339 | unsigned long *pair_switch = &(pair->switch_on); | 355 | unsigned long *pair_switch; |
340 | if(c) | 356 | |
341 | pair_switch = c == '-' ? &(pair->switch_off) : &(pair->incongruously); | 357 | switch(c) { |
358 | case '-': | ||
359 | pair_switch = &(pair->switch_off); | ||
360 | break; | ||
361 | case '~': | ||
362 | pair_switch = &(pair->incongruously); | ||
363 | break; | ||
364 | case '?': | ||
365 | pair_switch = &(pair->requires); | ||
366 | break; | ||
367 | default: | ||
368 | pair_switch = &(pair->switch_on); | ||
369 | } | ||
342 | for (on_off = complementally; on_off->opt; on_off++) | 370 | for (on_off = complementally; on_off->opt; on_off++) |
343 | if (on_off->opt == *s) { | 371 | if (on_off->opt == *s) { |
344 | if(pair_switch == &(on_off->switch_on)) | 372 | if(pair_switch == &(on_off->switch_on)) |
345 | on_off->counter = va_arg (p, int *); | 373 | on_off->counter = va_arg (p, int *); |
374 | else if(pair_switch == &(on_off->requires)) | ||
375 | requires |= on_off->switch_on; | ||
346 | else | 376 | else |
347 | *pair_switch |= on_off->switch_on; | 377 | *pair_switch |= on_off->switch_on; |
348 | break; | 378 | break; |
@@ -353,15 +383,16 @@ bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) | |||
353 | } | 383 | } |
354 | 384 | ||
355 | while ((c = getopt_long (argc, argv, applet_opts, | 385 | while ((c = getopt_long (argc, argv, applet_opts, |
356 | bb_applet_long_options, NULL)) > 0) { | 386 | bb_applet_long_options, NULL)) >= 0) { |
357 | 387 | ||
358 | loop_arg_is_opt: | 388 | loop_arg_is_opt: |
359 | for (on_off = complementally; on_off->opt != c; on_off++) { | 389 | for (on_off = complementally; on_off->opt != c; on_off++) { |
360 | if(!on_off->opt) | 390 | /* c==0 if long opt have non NULL flag */ |
391 | if(on_off->opt == 0 && c != 0) | ||
361 | bb_show_usage (); | 392 | bb_show_usage (); |
362 | } | 393 | } |
363 | if(flags & on_off->incongruously) { | 394 | if(flags & on_off->incongruously) { |
364 | if(flg_show_usage_if_error) | 395 | if((spec_flgs & SHOW_USAGE_IF_ERROR)) |
365 | bb_show_usage (); | 396 | bb_show_usage (); |
366 | flags |= BB_GETOPT_ERROR; | 397 | flags |= BB_GETOPT_ERROR; |
367 | } | 398 | } |
@@ -377,15 +408,13 @@ loop_arg_is_opt: | |||
377 | } else if (on_off->optarg) { | 408 | } else if (on_off->optarg) { |
378 | *(char **)(on_off->optarg) = optarg; | 409 | *(char **)(on_off->optarg) = optarg; |
379 | } | 410 | } |
380 | if(flg_argv_is_opts == 'p') | 411 | if(pargv != NULL) |
381 | break; | 412 | break; |
382 | } | 413 | } |
383 | if(flg_argv_is_opts) { | 414 | if((spec_flgs & ARGV_IS_OPTS)) { |
384 | /* process argv is option, for example "ps" applet */ | 415 | /* process argv is option, for example "ps" applet */ |
385 | if(flg_argv_is_opts == '-') { | 416 | if(pargv == NULL) |
386 | flg_argv_is_opts = 'p'; | ||
387 | pargv = argv + optind; | 417 | pargv = argv + optind; |
388 | } | ||
389 | while(*pargv) { | 418 | while(*pargv) { |
390 | c = **pargv; | 419 | c = **pargv; |
391 | if(c == '\0') { | 420 | if(c == '\0') { |
@@ -396,6 +425,13 @@ loop_arg_is_opt: | |||
396 | } | 425 | } |
397 | } | 426 | } |
398 | } | 427 | } |
399 | 428 | /* check depending requires for given options */ | |
429 | for (on_off = complementally; on_off->opt; on_off++) { | ||
430 | if(on_off->requires && (flags & on_off->switch_on) && | ||
431 | (flags & on_off->requires) == 0) | ||
432 | bb_show_usage (); | ||
433 | } | ||
434 | if(requires && (flags & requires) == 0) | ||
435 | bb_show_usage (); | ||
400 | return flags; | 436 | return flags; |
401 | } | 437 | } |