X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=ucw%2Fopt.h;h=557cadb16491255fcd62bf31ad120a87e9f001c9;hb=156301aa8c7fd24d49ed27cfbd1afc10ccb7bc58;hp=f376a81193ea5e830f4134202a9bff31a0c5e3c3;hpb=0db6e10eac28f38bfc3b325b13ad95107c58ce1e;p=libucw.git diff --git a/ucw/opt.h b/ucw/opt.h index f376a811..557cadb1 100644 --- a/ucw/opt.h +++ b/ucw/opt.h @@ -3,6 +3,7 @@ * * (c) 2013 Jan Moskyto Matejka * (c) 2014 Martin Mares + * (c) 2014 Pavel Charvat * * This software may be freely distributed and used according to the terms * of the GNU Lesser General Public License. @@ -50,28 +51,28 @@ * the option is given as `--no-`'option' with no argument. * - `OPT_CL_STATIC`: options of this class just take a value and store * it in the variable. + * - `OPT_CL_MULTIPLE`: collect values from all occurrences of this + * option in a growing array (see `gary.h`). * - `OPT_CL_SWITCH`: a multiple-choice switch, which sets the variable * to a fixed value provided in option definition. * - `OPT_CL_INC`: increments the variable (or decrements, if the * `OPT_NEGATIVE` flag is set). * - `OPT_CL_CALL`: instead of setting a variable, call a function * and pass the value of the option to it. - * - `OPT_CL_USER`: like `OPT_CL_STATIC`, but with user-defined value - * syntax, specified as <>. * - `OPT_CL_SECTION`: not a real option, but an instruction to insert * contents of another list of options. * - `OPT_CL_HELP`: no option, just print a help text. - * - `OPT_CL_HOOK`: no option, but a definition of a hook. (FIXME) + * - `OPT_CL_HOOK`: no option, but a definition of a <>. ***/ enum opt_class { OPT_CL_END, OPT_CL_BOOL, OPT_CL_STATIC, + OPT_CL_MULTIPLE, OPT_CL_SWITCH, OPT_CL_INC, OPT_CL_CALL, - OPT_CL_USER, OPT_CL_SECTION, OPT_CL_HELP, OPT_CL_HOOK, @@ -99,13 +100,13 @@ struct opt_item { const char * name; // long name (NULL if none) int letter; // short name (0 if none) void * ptr; // variable to store the value to - const char * help; // description in --help + const char * help; // description in --help (NULL to omit the option from the help) union opt_union { struct opt_section * section; // subsection for OPT_CL_SECTION int value; // value for OPT_CL_SWITCH void (* call)(struct opt_item * opt, const char * value, void * data); // function to call for OPT_CL_CALL - void (* hook)(struct opt_item * opt, uns event, const char * value, void * data); // function to call for OPT_CL_HOOK - struct cf_user_type * utype; // specification of the user-defined type for OPT_CL_USER + void (* hook)(struct opt_item * opt, uint event, const char * value, void * data); // function to call for OPT_CL_HOOK + struct cf_user_type * utype; // specification of the user-defined type for CT_USER } u; u16 flags; // as defined below (for hooks, event mask is stored instead) byte cls; // enum opt_class @@ -125,7 +126,6 @@ struct opt_item { #define OPT_NO_VALUE 0x4 /** The option must have no value. **/ #define OPT_MAYBE_VALUE 0x8 /** The option may have a value. **/ #define OPT_NEGATIVE 0x10 /** Reversing the effect of OPT_INC or saving @false into OPT_BOOL. **/ -#define OPT_NO_HELP 0x20 /** Exclude this option from the help. **/ #define OPT_LAST_ARG 0x40 /** Stop processing arguments after this line. **/ #define OPT_SINGLE 0x100 /** The option must appear at most once. **/ #define OPT_MULTIPLE 0x200 /** The option may appear multiple times; will save all the values into a simple list. **/ @@ -138,6 +138,7 @@ struct opt_item { * according to option class: * * - `OPT_MAYBE_VALUE` for `OPT_CL_STATIC` + * - `OPT_REQUIRED_VALUE` for `OPT_CL_MULTIPLE` * - `OPT_NO_VALUE` for `OPT_CL_BOOL`, `OPT_CL_SWITCH` and `OPT_CL_INC` * - An error is reported in all other cases. **/ @@ -161,29 +162,54 @@ struct opt_item { #define OPT_HELP_OPTION OPT_CALL(0, "help", opt_handle_help, NULL, OPT_BEFORE_CONFIG | OPT_INTERNAL | OPT_NO_VALUE, "\tShow this help") /** Boolean option. @target should be a variable of type `int`. **/ -#define OPT_BOOL(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .help = desc, .flags = fl, .cls = OPT_CL_BOOL, .type = CT_INT } +#define OPT_BOOL(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = CHECK_PTR_TYPE(&target, int *), .help = desc, .flags = fl, .cls = OPT_CL_BOOL, .type = CT_INT } /** String option. @target should be a variable of type `char *`. **/ -#define OPT_STRING(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .help = desc, .flags = fl, .cls = OPT_CL_STATIC, .type = CT_STRING } +#define OPT_STRING(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = CHECK_PTR_TYPE(&target, char **), .help = desc, .flags = fl, .cls = OPT_CL_STATIC, .type = CT_STRING } -// FIXME: Check that the target is of the right type (likewise in other statically typed options) /** Ordinary integer option. @target should be a variable of type `int`. **/ -#define OPT_INT(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .help = desc, .flags = fl, .cls = OPT_CL_STATIC, .type = CT_INT } +#define OPT_INT(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = CHECK_PTR_TYPE(&target, int *), .help = desc, .flags = fl, .cls = OPT_CL_STATIC, .type = CT_INT } + +/** Unsigned integer option. @target should be a variable of type `uint`. **/ +#define OPT_UINT(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = CHECK_PTR_TYPE(&target, uint *), .help = desc, .flags = fl, .cls = OPT_CL_STATIC, .type = CT_INT } /** 64-bit integer option. @target should be a variable of type `u64`. **/ -#define OPT_U64(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .help = desc, .flags = fl, .cls = OPT_CL_STATIC, .type = CT_U64 } +#define OPT_U64(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = CHECK_PTR_TYPE(&target, u64 *), .help = desc, .flags = fl, .cls = OPT_CL_STATIC, .type = CT_U64 } /** Floating-point option. @target should be a variable of type `double`. **/ -#define OPT_DOUBLE(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .help = desc, .flags = fl, .cls = OPT_CL_STATIC, .type = CT_DOUBLE } +#define OPT_DOUBLE(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = CHECK_PTR_TYPE(&target, double *), .help = desc, .flags = fl, .cls = OPT_CL_STATIC, .type = CT_DOUBLE } /** IP address option, currently IPv4 only. @target should be a variable of type `u32`. **/ -#define OPT_IP(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .help = desc, .flags = fl, .cls = OPT_CL_STATIC, .type = CT_IP } +#define OPT_IP(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = CHECK_PTR_TYPE(&target, u32 *), .help = desc, .flags = fl, .cls = OPT_CL_STATIC, .type = CT_IP } + +/** Multi-valued string option. @target should be a growing array of `char *`s. **/ +#define OPT_STRING_MULTIPLE(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = CHECK_PTR_TYPE(&target, char ***), .help = desc, .flags = fl, .cls = OPT_CL_MULTIPLE, .type = CT_STRING } + +/** Multi-valued integer option. @target should be a growing array of `int`s. **/ +#define OPT_INT_MULTIPLE(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = CHECK_PTR_TYPE(&target, int **), .help = desc, .flags = fl, .cls = OPT_CL_MULTIPLE, .type = CT_INT } + +/** Multi-valued unsigned integer option. @target should be a growing array of `uint`s. **/ +#define OPT_UINT_MULTIPLE(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = CHECK_PTR_TYPE(&target, uint **), .help = desc, .flags = fl, .cls = OPT_CL_MULTIPLE, .type = CT_INT } + +/** Multi-valued 64-bit integer option. @target should be a growing array of `u64`s. **/ +#define OPT_U64_MULTIPLE(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = CHECK_PTR_TYPE(&target, u64 **), .help = desc, .flags = fl, .cls = OPT_CL_MULTIPLE, .type = CT_U64 } + +/** Multi-valued floating-point option. @target should be a growing array of `double`s. **/ +#define OPT_DOUBLE_MULTIPLE(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = CHECK_PTR_TYPE(&target, double **), .help = desc, .flags = fl, .cls = OPT_CL_MULTIPLE, .type = CT_DOUBLE } + +/** Multi-valued IPv4 address option. @target should be a growing array of `u32`s. **/ +#define OPT_IP_MULTIPLE(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = CHECK_PTR_TYPE(&target, u32 **), .help = desc, .flags = fl, .cls = OPT_CL_MULTIPLE, .type = CT_IP } /** Switch option. @target should be a variable of type `int` and it will be set to the value @val. **/ -#define OPT_SWITCH(shortopt, longopt, target, val, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .help = desc, .flags = fl, .cls = OPT_CL_SWITCH, .type = CT_LOOKUP, .u.value = val } +#define OPT_SWITCH(shortopt, longopt, target, val, fl, desc) { .letter = shortopt, .name = longopt, .ptr = CHECK_PTR_TYPE(&target, int *), .help = desc, .flags = fl, .cls = OPT_CL_SWITCH, .type = CT_LOOKUP, .u.value = val } /** Incrementing option. @target should be a variable of type `int`. **/ -#define OPT_INC(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .flags = fl, .help = desc, .cls = OPT_CL_INC, .type = CT_INT } +#define OPT_INC(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = CHECK_PTR_TYPE(&target, int *), .flags = fl, .help = desc, .cls = OPT_CL_INC, .type = CT_INT } + +/* FIXME: Backwards compatibility only, should not be used anymore. */ +#define OPT_UNS OPT_UINT +#define OPT_UNS_MULTIPLE OPT_UINT_MULTIPLE + /** * When this option appears, call the function @fn with parameters @item, @value, @data, @@ -195,9 +221,13 @@ struct opt_item { /** * An option with user-defined syntax. @ttype is a <> - * describing the syntax, @target is a variable of the corresponding type. + * describing the syntax, @target is a variable of the corresponding type. If the @OPT_REQUIRED_VALUE + * flag is not set, the parser must be able to parse a NULL value. **/ -#define OPT_USER(shortopt, longopt, target, ttype, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .u.utype = &ttype, .flags = fl, .help = desc, .cls = OPT_CL_USER, .type = CT_USER } +#define OPT_USER(shortopt, longopt, target, ttype, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .u.utype = &ttype, .flags = fl, .help = desc, .cls = OPT_CL_STATIC, .type = CT_USER } + +/** Multi-valued option of user-defined type. @target should be a growing array of the right kind of items. **/ +#define OPT_USER_MULTIPLE(shortopt, longopt, target, ttype, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .u.utype = &ttype, .flags = fl, .help = desc, .cls = OPT_CL_MULTIPLE, .type = CT_USER } /** A sub-section. **/ #define OPT_SECTION(sec) { .cls = OPT_CL_SECTION, .u.section = &sec } @@ -320,7 +350,7 @@ void opt_handle_help(struct opt_item * opt, const char * value, void * data); void opt_handle_config(struct opt_item * opt, const char * value, void * data); void opt_handle_set(struct opt_item * opt, const char * value, void * data); void opt_handle_dumpconfig(struct opt_item * opt, const char * value, void * data); -void opt_conf_hook_internal(struct opt_item * opt, uns event, const char * value, void * data); +void opt_conf_hook_internal(struct opt_item * opt, uint event, const char * value, void * data); // XXX: This is duplicated with , but that one will hopefully go away one day. /** @@ -353,7 +383,7 @@ extern char *cf_env_file; #define OPT_HOOK_BEFORE_ARG 0x1 /** Call before option parsing **/ #define OPT_HOOK_BEFORE_VALUE 0x2 /** Call before value parsing **/ #define OPT_HOOK_AFTER_VALUE 0x4 /** Call after value parsing **/ -#define OPT_HOOK_FINAL 0x8 /** Call just before opt_parse() returns **/ +#define OPT_HOOK_FINAL 0x8 /** Call just before @opt_parse() returns **/ #define OPT_HOOK_INTERNAL 0x4000 // Used internally to ask for passing of struct opt_context #endif