diff options
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/getopt_ulflags.c | 273 |
1 files changed, 149 insertions, 124 deletions
diff --git a/libbb/getopt_ulflags.c b/libbb/getopt_ulflags.c index 6197e8d9f..44c8e1a76 100644 --- a/libbb/getopt_ulflags.c +++ b/libbb/getopt_ulflags.c @@ -2,7 +2,7 @@ /* * universal getopt_ulflags implementation for busybox * - * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru> + * Copyright (C) 2003-2005 Vladimir Oleynik <dzo@simtreas.ru> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,158 +31,152 @@ unsigned long bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) - The command line options must be declared in const char - *applet_opts as a string of chars, for example: + The command line options must be declared in const char + *applet_opts as a string of chars, for example: - flags = bb_getopt_ulflags(argc, argv, "rnug"); + flags = bb_getopt_ulflags(argc, argv, "rnug"); - If one of the given options is found, a flag value is added to - the return value (an unsigned long). + If one of the given options is found, a flag value is added to + the return value (an unsigned long). - The flag value is determined by the position of the char in - applet_opts string. For example, in the above case: + The flag value is determined by the position of the char in + applet_opts string. For example, in the above case: - flags = bb_getopt_ulflags(argc, argv, "rnug"); + flags = bb_getopt_ulflags(argc, argv, "rnug"); - "r" will add 1 (bit 1 : 0x01) - "n" will add 2 (bit 2 : 0x02) - "u will add 4 (bit 3 : 0x03) - "g" will add 8 (bit 4 : 0x04) + "r" will add 1 (bit 1 : 0x01) + "n" will add 2 (bit 2 : 0x02) + "u will add 4 (bit 3 : 0x03) + "g" will add 8 (bit 4 : 0x04) - and so on. You can also look at the return value as a bit - field and each option sets one of bits. + and so on. You can also look at the return value as a bit + field and each option sets one of bits. - ":" If one of the options requires an argument, then add a ":" - after the char in applet_opts and provide a pointer to store - the argument. For example: + ":" If one of the options requires an argument, then add a ":" + after the char in applet_opts and provide a pointer to store + the argument. For example: - char *pointer_to_arg_for_a; - char *pointer_to_arg_for_b; - char *pointer_to_arg_for_c; - char *pointer_to_arg_for_d; + char *pointer_to_arg_for_a; + char *pointer_to_arg_for_b; + char *pointer_to_arg_for_c; + char *pointer_to_arg_for_d; - flags = bb_getopt_ulflags(argc, argv, "a:b:c:d:", - &pointer_to_arg_for_a, &pointer_to_arg_for_b, - &pointer_to_arg_for_c, &pointer_to_arg_for_d); + flags = bb_getopt_ulflags(argc, argv, "a:b:c:d:", + &pointer_to_arg_for_a, &pointer_to_arg_for_b, + &pointer_to_arg_for_c, &pointer_to_arg_for_d); - The type of the pointer (char* or llist_t *) may be controlled - by the "*" special character that is set in the external string - bb_opt_complementaly (see below for more info). + The type of the pointer (char* or llist_t *) may be controlled + by the "*" special character that is set in the external string + bb_opt_complementally (see below for more info). static const struct option bb_default_long_options[] - This struct allows you to define long options. The syntax for - declaring the array is just like that of getopt's longopts. + This struct allows you to define long options. The syntax for + declaring the array is just like that of getopt's longopts. + (see getopt(3)) - static const struct option applet_long_options[] = { - { "verbose", 0, 0, "v" }, - { 0, 0, 0, 0 } - }; - bb_applet_long_options = applet_long_options; + static const struct option applet_long_options[] = { + { "verbose", 0, 0, v }, + { 0, 0, 0, 0 } + }; + bb_applet_long_options = applet_long_options; - The first parameter is the long option name that you would pass - to the applet (without the dashes). + The last argument (val) can undefined from applet_opts. + If you use this, then: + - return bit have next position after short options + - if has_arg is not "no_argument", use ptr for arg also + - bb_opt_complementally have effects for this too - The second field determines whether the option has an argument. - You can set this to 0, 1, or 2, or you can use the long named - defines of no_argument, required_argument, and optional_argument. + Note: a good applet will make long options configurable via the + config process and not a required feature. The current standard + is to name the config option CONFIG_FEATURE_<applet>_LONG_OPTIONS. - The third argument is used only when the long option does not - have a corresponding short option. In that case, it should be - an integer pointer. Otherwise (and normally), it should just - bet set to NULL. +const char *bb_opt_complementally - The last argument is the corresponding short option (if there - is one of course). + ":" The colon (":") is used to separate groups of two or more chars + and/or groups of chars and special characters (stating some + conditions to be checked). - Note: a good applet will make long options configurable via the - config process and not a required feature. The current standard - is to name the config option CONFIG_FEATURE_<applet>_LONG_OPTIONS. + "abc" If groups of two or more chars are specified, the first char + is the main option and the other chars are secondary options. + Their flags will be turned on if the main option is found even + if they are not specifed on the command line. For example: -const char *bb_opt_complementaly + bb_opt_complementally = "abc"; - ":" The colon (":") is used to separate groups of two or more chars - and/or groups of chars and special characters (stating some - conditions to be checked). + flags = bb_getopt_ulflags(argc, argv, "abcd") - "abc" If groups of two or more chars are specified, the first char - is the main option and the other chars are secondary options. - Their flags will be turned on if the main option is found even - if they are not specifed on the command line. For example: - - bb_opt_complementaly = "abc"; - - flags = bb_getopt_ulflags(argc, argv, "abcd") - - If getopt() finds "-a" on the command line, then - bb_getopt_ulflags's return value will be as if "-a -b -c" were - found. + If getopt() finds "-a" on the command line, then + bb_getopt_ulflags's return value will be as if "-a -b -c" were + found. Special characters: - "-" A dash between two options causes the second of the two - to be unset (and ignored) if it is given on the command line. + "-" A dash between two options causes the second of the two + to be unset (and ignored) if it is given on the command line. - For example: - The du applet has the options "-s" and "-d depth". If - bb_getopt_ulflags finds -s, then -d is unset or if it finds -d - then -s is unset. (Note: busybox implements the GNU - "--max-depth" option as "-d".) To obtain this behavior, you - set bb_opt_complementaly = "s-d:d-s". Only one flag value is - added to bb_getopt_ulflags's return value depending on the - position of the options on the command line. If one of the - two options requires an argument pointer (":" in applet_opts - as in "d:") optarg is set accordingly. + For example: + The du applet has the options "-s" and "-d depth". If + bb_getopt_ulflags finds -s, then -d is unset or if it finds -d + then -s is unset. (Note: busybox implements the GNU + "--max-depth" option as "-d".) To obtain this behavior, you + set bb_opt_complementally = "s-d:d-s". Only one flag value is + added to bb_getopt_ulflags's return value depending on the + position of the options on the command line. If one of the + two options requires an argument pointer (":" in applet_opts + as in "d:") optarg is set accordingly. - char *smax_print_depth; + char *smax_print_depth; - bb_opt_complementaly = "s-d:d-s"; - opt = bb_getopt_ulflags(argc, argv, "sd:", &smax_print_depth); + bb_opt_complementally = "s-d:d-s"; + opt = bb_getopt_ulflags(argc, argv, "sd:", &smax_print_depth); - if (opt & 2) { - max_print_depth = bb_xgetularg10_bnd(smax_print_depth, - 0, INT_MAX); - } + if (opt & 2) { + max_print_depth = bb_xgetularg10_bnd(smax_print_depth, + 0, INT_MAX); + } - "~" A tilde between two options, or between an option and a group - of options, means that they are mutually exclusive. Unlike - the "-" case above, an error will be forced if the options - are used together. + "~" A tilde between two options, or between an option and a group + of options, means that they are mutually exclusive. Unlike + the "-" case above, an error will be forced if the options + are used together. - For example: - The cut applet must have only one type of list specified, so - -b, -c and -f are mutally exclusive and should raise an error - if specified together. In this case you must set - bb_opt_complementaly = "b~cf:c~bf:f~bc". If two of the - mutually exclusive options are found, bb_getopt_ulflags's - return value will have the error flag set (BB_GETOPT_ERROR) so - that we can check for it: + For example: + The cut applet must have only one type of list specified, so + -b, -c and -f are mutally exclusive and should raise an error + if specified together. In this case you must set + bb_opt_complementally = "b~cf:c~bf:f~bc". If two of the + mutually exclusive options are found, bb_getopt_ulflags's + return value will have the error flag set (BB_GETOPT_ERROR) so + that we can check for it: - if (flags & BB_GETOPT_ERROR) - bb_show_usage(); + if (flags & BB_GETOPT_ERROR) + bb_show_usage(); - "*" A star after a char in bb_opt_complementaly means that the - option can occur multiple times: + "!" If previous point set BB_GETOPT_ERROR, don`t return and call + previous example internally - For example: - The grep applet can have one or more "-e pattern" arguments. - In this case you should use bb_getopt_ulflags() as follows: + "*" A star after a char in bb_opt_complementally means that the + option can occur multiple times: - llist_t *patterns = NULL; + For example: + The grep applet can have one or more "-e pattern" arguments. + In this case you should use bb_getopt_ulflags() as follows: - (this pointer must be initializated to NULL if the list is empty - as required by *llist_add_to(llist_t *old_head, char *new_item).) + llist_t *patterns = NULL; - bb_opt_complementaly = "e*"; + (this pointer must be initializated to NULL if the list is empty + as required by *llist_add_to(llist_t *old_head, char *new_item).) - bb_getopt_ulflags(argc, argv, "e:", &patterns); - $ grep -e user -e root /etc/passwd - root:x:0:0:root:/root:/bin/bash - user:x:500:500::/home/user:/bin/bash + bb_opt_complementally = "e*"; + bb_getopt_ulflags(argc, argv, "e:", &patterns); + $ grep -e user -e root /etc/passwd + root:x:0:0:root:/root:/bin/bash + user:x:500:500::/home/user:/bin/bash */ -const char *bb_opt_complementaly; +const char *bb_opt_complementally; typedef struct { unsigned char opt; @@ -191,12 +185,12 @@ typedef struct { unsigned long switch_off; unsigned long incongruously; void **optarg; /* char **optarg or llist_t **optarg */ -} t_complementaly; +} t_complementally; /* You can set bb_applet_long_options for parse called long options */ static const struct option bb_default_long_options[] = { -/* { "help", 0, NULL, '?' }, */ +/* { "help", 0, NULL, '?' }, */ { 0, 0, 0, 0 } }; @@ -206,11 +200,13 @@ unsigned long bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) { unsigned long flags = 0; - t_complementaly complementaly[sizeof(flags) * 8 + 1]; + t_complementally complementally[sizeof(flags) * 8 + 1]; int c; const unsigned char *s; - t_complementaly *on_off; + t_complementally *on_off; va_list p; + const struct option *l_o; + char flg_show_usage_if_error = 0; va_start (p, applet_opts); @@ -220,7 +216,7 @@ bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) s++; c = 0; - on_off = complementaly; + on_off = complementally; for (; *s; s++) { if(c >= (sizeof(flags)*8)) break; @@ -240,9 +236,31 @@ bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) c++; } on_off->opt = 0; + + for(l_o = bb_applet_long_options; l_o->name; l_o++) { + for(on_off = complementally; on_off->opt != 0; on_off++) + if(on_off->opt == l_o->val) + break; + if(on_off->opt == 0) { + if(c >= (sizeof(flags)*8)) + break; + on_off->opt = l_o->val; + on_off->switch_on = (1 << c); + on_off->list_flg = 0; + on_off->switch_off = 0; + on_off->incongruously = 0; + if(l_o->has_arg != no_argument) + on_off->optarg = va_arg (p, void **); + else + on_off->optarg = NULL; + on_off++; + on_off->opt = 0; + c++; + } + } c = 0; - for (s = bb_opt_complementaly; s && *s; s++) { - t_complementaly *pair; + for (s = bb_opt_complementally; s && *s; s++) { + t_complementally *pair; if (*s == ':') { c = 0; @@ -250,7 +268,11 @@ bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) } if (c) continue; - for (on_off = complementaly; on_off->opt; on_off++) + if(*s == '!') { + flg_show_usage_if_error = '!'; + continue; + } + for (on_off = complementally; on_off->opt; on_off++) if (on_off->opt == *s) break; pair = on_off; @@ -263,7 +285,7 @@ bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) unsigned long *pair_switch = &(pair->switch_on); if(c) pair_switch = c == '-' ? &(pair->switch_off) : &(pair->incongruously); - for (on_off = complementaly; on_off->opt; on_off++) + for (on_off = complementally; on_off->opt; on_off++) if (on_off->opt == *s) { *pair_switch |= on_off->switch_on; break; @@ -274,13 +296,16 @@ bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) } while ((c = getopt_long (argc, argv, applet_opts, - bb_applet_long_options, NULL)) > 0) { - for (on_off = complementaly; on_off->opt != c; on_off++) { + bb_applet_long_options, NULL)) > 0) { + for (on_off = complementally; on_off->opt != c; on_off++) { if(!on_off->opt) bb_show_usage (); } - if(flags & on_off->incongruously) + if(flags & on_off->incongruously) { + if(flg_show_usage_if_error) + bb_show_usage (); flags |= BB_GETOPT_ERROR; + } flags &= ~on_off->switch_off; flags |= on_off->switch_on; if(on_off->list_flg) { |