]> mj.ucw.cz Git - libucw.git/blob - ucw/opt-test.c
Opt: OPT_MULTIPLE with clists replaced by OPT_CL_MULTIPLE with gary's
[libucw.git] / ucw / opt-test.c
1 /*
2  *      UCW Library -- Parsing of command line options
3  *
4  *      (c) 2013 Jan Moskyto Matejka <mq@ucw.cz>
5  *      (c) 2014 Martin Mares <mj@ucw.cz>
6  *
7  *      This software may be freely distributed and used according to the terms
8  *      of the GNU Lesser General Public License.
9  */
10
11 #include <ucw/lib.h>
12 #include <ucw/opt.h>
13 #include <ucw/strtonum.h>
14 #include <ucw/fastbuf.h>
15 #include <ucw/gary.h>
16
17 static void show_version(struct opt_item * opt UNUSED, const char * value UNUSED, void * data UNUSED) {
18   printf("This is a simple tea boiling console v0.1.\n");
19   exit(EXIT_SUCCESS);
20 }
21
22 struct teapot_temperature {
23   enum {
24     TEMP_CELSIUS = 0,
25     TEMP_FAHRENHEIT,
26     TEMP_KELVIN,
27     TEMP_REAUMUR,
28     TEMP_RANKINE
29   } scale;
30   int value;
31 } temperature;
32
33 static char * temp_scale_str[] = { "C", "F", "K", "Re", "R" };
34
35 static enum TEAPOT_TYPE {
36   TEAPOT_STANDARD = 0,
37   TEAPOT_EXCLUSIVE,
38   TEAPOT_GLASS,
39   TEAPOT_HANDS,
40   TEAPOT_UNDEFINED = -1
41 } set = TEAPOT_UNDEFINED;
42
43 static char * teapot_type_str[] = { "standard", "exclusive", "glass", "hands" };
44
45 static int show_hooks = 0;
46 static int english = 0;
47 static int sugar = 0;
48 static int verbose = 1;
49 static int with_gas = 0;
50 static int *black_magic;
51 static int pray = 0;
52 static int water_amount = 0;
53 static char * first_tea = NULL;
54
55 #define MAX_TEA_COUNT 30
56 static char * tea_list[MAX_TEA_COUNT];
57 static int tea_num = 0;
58 static void add_tea(struct opt_item * opt UNUSED, const char * name, void * data) {
59   char ** tea_list = data;
60   if (tea_num >= MAX_TEA_COUNT) {
61     fprintf(stderr, "Cannot boil more than %d teas.\n", MAX_TEA_COUNT);
62     exit(OPT_EXIT_BAD_ARGS);
63   }
64   tea_list[tea_num++] = xstrdup(name);
65 }
66
67 static const char * teapot_temperature_parser(char * in, void * ptr) {
68   struct teapot_temperature * temp = ptr;
69   const char * next;
70   const char * err = str_to_int(&temp->value, in, &next, 10);
71   if (err)
72     return err;
73   if (!strcmp("C", next))
74     temp->scale = TEMP_CELSIUS;
75   else if (!strcmp("F", next))
76     temp->scale = TEMP_FAHRENHEIT;
77   else if (!strcmp("K", next))
78     temp->scale = TEMP_KELVIN;
79   else if (!strcmp("R", next))
80     temp->scale = TEMP_RANKINE;
81   else if (!strcmp("Re", next))
82     temp->scale = TEMP_REAUMUR;
83   else {
84     fprintf(stderr, "Unknown scale: %s\n", next);
85     exit(OPT_EXIT_BAD_ARGS);
86   }
87   return NULL;
88 }
89
90 static void teapot_temperature_dumper(struct fastbuf * fb, void * ptr) {
91   struct teapot_temperature * temp = ptr;
92   bprintf(fb, "%d%s", temp->value, temp_scale_str[temp->scale]);
93 }
94
95 static struct cf_user_type teapot_temperature_t = {
96   .size = sizeof(struct teapot_temperature),
97   .name = "teapot_temperature_t",
98   .parser = (cf_parser1*) teapot_temperature_parser,
99   .dumper = (cf_dumper1*) teapot_temperature_dumper
100 };
101
102 static void opt_test_hook(struct opt_item * opt, uns event UNUSED, const char * value, void * data) {
103   if (!show_hooks)
104     return;
105   if (opt)
106     printf("[HOOK-%s:%c/%s=%s] ", (char *) data, opt->letter, opt->name, value);
107   else
108     printf("[HOOK-%s] ", (char *) data);
109 }
110
111 static struct opt_section water_options = {
112   OPT_ITEMS {
113     OPT_INT('w', "water", water_amount, OPT_REQUIRED | OPT_REQUIRED_VALUE, "<volume>\tAmount of water (in mls; required)"),
114     OPT_BOOL('G', "with-gas", with_gas, OPT_NO_VALUE, "\tUse water with gas"),
115     OPT_END
116   }
117 };
118
119 static struct opt_section options = {
120   OPT_ITEMS {
121     OPT_HELP("A simple tea boiling console."),
122     OPT_HELP("Usage: teapot [options] name-of-the-tea"),
123     OPT_HELP(""),
124     OPT_HELP("Black, green or white tea supported as well as fruit or herbal tea."),
125     OPT_HELP("You may specify more kinds of tea, all of them will be boiled for you, in the given order."),
126     OPT_HELP("At least one kind of tea must be specified."),
127     OPT_HELP(""),
128     OPT_HELP("Options:"),
129     OPT_HELP_OPTION,
130     OPT_CALL('V', "version", show_version, NULL, OPT_NO_VALUE, "\tShow the version"),
131     OPT_HELP(""),
132     OPT_BOOL('e', "english-style", english, 0, "\tEnglish style (with milk)"),
133     OPT_INT('s', "sugar", sugar, OPT_REQUIRED_VALUE, "<spoons>\tAmount of sugar (in teaspoons)"),
134     OPT_SWITCH(0, "standard-set", set, TEAPOT_STANDARD, OPT_SINGLE, "\tStandard teapot"),
135     OPT_SWITCH('x', "exclusive-set", set, TEAPOT_EXCLUSIVE, OPT_SINGLE, "\tExclusive teapot"),
136     OPT_SWITCH('g', "glass-set", set, TEAPOT_GLASS, OPT_SINGLE, "\tTransparent glass teapot"),
137     OPT_SWITCH('h', "hands", set, TEAPOT_HANDS, OPT_SINGLE, "\tUse user's hands as a teapot (a bit dangerous)"),
138     OPT_USER('t', "temperature", temperature, teapot_temperature_t, OPT_REQUIRED_VALUE | OPT_REQUIRED,
139                   "<value>\tWanted final temperature of the tea to be served (required)\n"
140               "\t\tSupported scales:  Celsius [60C], Fahrenheit [140F],\n"
141               "\t\t                   Kelvin [350K], Rankine [600R] and Reaumur [50Re]\n"
142               "\t\tOnly integer values allowed."),
143     OPT_INC('v', "verbose", verbose, 0, "\tVerbose (the more -v, the more verbose)"),
144     OPT_INC('q', "quiet", verbose, OPT_NEGATIVE, "\tQuiet (the more -q, the more quiet)"),
145     OPT_INT_MULTIPLE('b', NULL, black_magic, 0, "<strength>\tUse black magic to make the tea extraordinarily delicious.\n\t\tMay be specified more than once to describe the amounts of black magic to be invoked in each step of tea boiling."),
146     OPT_BOOL('p', "pray", pray, OPT_SINGLE, "\tPray before boiling"),
147     OPT_STRING(OPT_POSITIONAL(1), NULL, first_tea, OPT_REQUIRED, ""),
148     OPT_CALL(OPT_POSITIONAL_TAIL, NULL, add_tea, &tea_list, 0, ""),
149     OPT_HELP(""),
150     OPT_HELP("Water options:"),
151     OPT_SECTION(water_options),
152     OPT_HOOK(opt_test_hook, "prearg", OPT_HOOK_BEFORE_ARG),
153     OPT_HOOK(opt_test_hook, "preval", OPT_HOOK_BEFORE_VALUE),
154     OPT_HOOK(opt_test_hook, "postval", OPT_HOOK_AFTER_VALUE),
155     OPT_BOOL('H', "show-hooks", show_hooks, 0, "\tDemonstrate the hooks."),
156     OPT_HELP(""),
157     OPT_HELP("Configuration options:"),
158     OPT_CONF_OPTIONS,
159     OPT_END
160   }
161 };
162
163 struct intnode {
164   cnode n;
165   int x;
166 };
167
168 int main(int argc UNUSED, char ** argv)
169 {
170   cf_def_file = "etc/libucw";
171   GARY_INIT(black_magic, 0);
172   opt_parse(&options, argv+1);
173
174   printf("English style: %s|", english ? "yes" : "no");
175   if (sugar)
176     printf("Sugar: %d teaspoons|", sugar);
177   if (set != -1)
178     printf("Chosen teapot: %s|", teapot_type_str[set]);
179   printf("Temperature: %d%s|", temperature.value, temp_scale_str[temperature.scale]);
180   printf("Verbosity: %d|", verbose);
181   uns magick = GARY_SIZE(black_magic);
182   for (uns i=0; i<magick; i++)
183     printf("Black magic: %d|", black_magic[i]);
184   printf("Prayer: %s|", pray ? "yes" : "no");
185   printf("Water amount: %d|", water_amount);
186   printf("Gas: %s|", with_gas ? "yes" : "no");
187   printf("First tea: %s|", first_tea);
188   for (int i=0; i<tea_num; i++)
189     printf("Boiling a tea: %s|", tea_list[i]);
190
191   printf("Everything OK. Bye.\n");
192 }