]> mj.ucw.cz Git - libucw.git/blob - ucw/opt.h
Opt: defined user interface
[libucw.git] / ucw / opt.h
1 /*
2  *      UCW Library -- Parsing of command line options
3  *
4  *      (c) 2013 Jan Moskyto Matejka <mq@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #ifndef _UCW_OPT_H
11 #define _UCW_OPT_H
12
13 #include <stdlib.h>
14 #include <stdio.h>
15
16 /***
17  * [[opt]]
18  * Parsing of command line options
19  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20  ***/
21
22 enum opt_class {
23   OPT_CL_END,     // end of list
24   OPT_CL_BOOL,    // boolean value
25   OPT_CL_STATIC,  // static value
26   OPT_CL_SWITCH,  // lookup/switch
27   OPT_CL_INC,     // incremental value
28   OPT_CL_USER,    // user defined value
29   OPT_CL_SECTION, // subsection
30   OPT_CL_HELP,    // help line
31 };
32
33 enum opt_type {
34   OPT_CT_INT, OPT_CT_64, OPT_CT_DOUBLE, // number
35   OPT_CT_STRING,                        // string
36   OPT_CT_LOOKUP,                        // lookup/switch
37   OPT_CT_USER,                          // user defined
38 };
39
40 typedef int opt_custom_parser(const char * param, void * target);
41
42 struct opt_section;
43 struct opt_item {
44   const char letter;                    // short-op
45   const char *name;                     // long-op
46   void *ptr;                            // where to save
47   const char *help;                     // description in --help
48   union opt_union {
49     struct opt_section *section;        // subsection for OPT_SECTION
50     int value;                          // value for OPT_SWITCH
51     opt_custom_parser *parser;          // parser for OPT_USER
52     const char *help2;                  // second value for OPT_HELP2
53   } u;
54   short flags;
55   enum opt_class cls;
56   enum opt_type type;
57 };
58
59 struct opt_section {
60   struct opt_item *opt;
61 };
62
63 #define OPT_ITEMS       .opt = ( struct opt_item[] )  /** List of sub-items. **/
64
65 /** Sub-items to be enclosed in OPT_ITEMS { } list
66  *
67  * OPT_SHOW_HELP declares --help and prints a line about that
68  * OPT_HELP prints a line into help()
69  * OPT_HELP2 prints two strings onto a line using the same tab structure as the option listing
70  * OPT_BOOL declares boolean option with an auto-negation (--sth and --no-sth); may be changed by OPT_BOOL_SET_PREFIXES
71  * OPT_STRING, OPT_UNS, OPT_INT declare simple string/uns/int option
72  * OPT_SWITCH declares one choice of a switch statement; these have common target and different `value`s; last wins unless OPT_SINGLE is set;
73  *            parser fails if it matches an OPT_SWITCH with OPT_SINGLE set and also target set.
74  *            Target must be of signed integer type; it is set to -1 if no switch appears at the command-line.
75  * OPT_USER declares a custom type of value; parser is of type opt_custom_parser
76  *                                           and returns 1 on success and 0 on failure
77  * OPT_INC declares an incremental value like -v/--verbose
78  * OPT_SECTION declares a subsection
79  *
80  * **/
81
82 #define OPT_SHOW_HELP(flags) OPT_USER(0, "help", *(NULL), opt_help_success2, flags, "Show this help")
83 #define OPT_HELP(line) OPT_HELP2(line, NULL)
84 #define OPT_HELP2(first, second) { .help = first, .cls = OPT_CL_HELP, .u.help2 = second }
85 #define OPT_BOOL(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .help = desc, .flags = fl, .cls = OPT_CL_BOOL, .type = OPT_CT_INT }
86 #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 = OPT_CT_STRING }
87 #define OPT_UNS(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = CHECK_PTR_TYPE(&target, uns*), .help = desc, .flags = fl, .cls = OPT_CL_STATIC, .type = OPT_CT_INT }
88 #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 = OPT_CT_INT }
89 #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 = OPT_CT_INT, .u.value = val }
90 #define OPT_USER(shortopt, longopt, target, pa, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .u.parser = pa, .flags = fl, .help = desc, .cls = OPT_CL_USER, .type = OPT_CT_USER }
91 #define OPT_INC(shortopt, longopt, target, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .flags = fl, .help = desc, .cls = OPT_CL_INC, .type = OPT_CT_INT }
92 #define OPT_SECTION(sec) { .cls = OPT_CL_SECTION, .u.section = &sec }
93 #define OPT_END { .cls = OPT_CL_END }
94
95 /** Flags for the preceeding calls **/
96 #define OPT_REQUIRED        0x1         // Argument must appear at the command line
97 #define OPT_REQUIRED_VALUE  0x2         // Argument must have a value
98 #define OPT_NO_VALUE        0x4         // Argument must have no value
99 #define OPT_DECREMENT       0x8         // Reversing the effect of OPT_INC
100 #define OPT_SINGLE          0x10        // Argument must appear at most once
101 #define OPT_NO_HELP         0x20        // Omit this line from help
102
103 extern struct opt_section * opt_section_root;
104 void opt_help_noexit_internal(struct opt_section * help);
105
106 static void opt_help_noexit(void) {
107   opt_help_noexit_internal(opt_section_root);
108 }
109
110 static void opt_usage_noexit(void) {
111   fprintf(stderr, "Run with argument --help for more information.\n");
112 }
113
114 static int opt_help_success2(const char * param UNUSED, void * target UNUSED) {
115   opt_help_noexit();
116   exit(0);
117 }
118
119 static void opt_help(void) {
120   opt_help_noexit();
121   exit(1);
122 }
123
124 static void opt_usage(void) {
125   opt_usage_noexit();
126   exit(1);
127 }
128
129 void opt_parse(struct opt_section * options);
130
131 #endif