]> mj.ucw.cz Git - libucw.git/blobdiff - ucw/opt.h
tableprinter: code cleanup
[libucw.git] / ucw / opt.h
index f376a81193ea5e830f4134202a9bff31a0c5e3c3..557cadb16491255fcd62bf31ad120a87e9f001c9 100644 (file)
--- a/ucw/opt.h
+++ b/ucw/opt.h
@@ -3,6 +3,7 @@
  *
  *     (c) 2013 Jan Moskyto Matejka <mq@ucw.cz>
  *     (c) 2014 Martin Mares <mj@ucw.cz>
+ *     (c) 2014 Pavel Charvat <pchar@ucw.cz>
  *
  *     This software may be freely distributed and used according to the terms
  *     of the GNU Lesser General Public License.
  *   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 <<conf:struct_cf_user_type,`cf_user_type`>>.
  * - `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 <<hooks,hook>>.
  ***/
 
 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 <<conf:struct_cf_user_type,`cf_user_type`>>
- * 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 <ucw/getopt.h>, 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