]> mj.ucw.cz Git - libucw.git/blob - ucw/opt-test.c
xtypes: bool now supports yes/no strings
[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 int clean_pot = 1;
54 static char * first_tea = NULL;
55
56 #define MAX_TEA_COUNT 30
57 static char * tea_list[MAX_TEA_COUNT];
58 static int tea_num = 0;
59 static void add_tea(struct opt_item * opt UNUSED, const char * name, void * data) {
60   char ** tea_list = data;
61   if (tea_num >= MAX_TEA_COUNT) {
62     fprintf(stderr, "Cannot boil more than %d teas.\n", MAX_TEA_COUNT);
63     exit(OPT_EXIT_BAD_ARGS);
64   }
65   tea_list[tea_num++] = xstrdup(name);
66 }
67
68 static const char * teapot_temperature_parser(char * in, void * ptr) {
69   struct teapot_temperature * temp = ptr;
70   const char * next;
71   const char * err = str_to_int(&temp->value, in, &next, 10);
72   if (err)
73     return err;
74   if (!strcmp("C", next))
75     temp->scale = TEMP_CELSIUS;
76   else if (!strcmp("F", next))
77     temp->scale = TEMP_FAHRENHEIT;
78   else if (!strcmp("K", next))
79     temp->scale = TEMP_KELVIN;
80   else if (!strcmp("R", next))
81     temp->scale = TEMP_RANKINE;
82   else if (!strcmp("Re", next))
83     temp->scale = TEMP_REAUMUR;
84   else {
85     fprintf(stderr, "Unknown scale: %s\n", next);
86     exit(OPT_EXIT_BAD_ARGS);
87   }
88   return NULL;
89 }
90
91 static void teapot_temperature_dumper(struct fastbuf * fb, void * ptr) {
92   struct teapot_temperature * temp = ptr;
93   bprintf(fb, "%d%s", temp->value, temp_scale_str[temp->scale]);
94 }
95
96 static struct cf_user_type teapot_temperature_t = {
97   .size = sizeof(struct teapot_temperature),
98   .name = "teapot_temperature_t",
99   .parser = (cf_parser1*) teapot_temperature_parser,
100   .dumper = (cf_dumper1*) teapot_temperature_dumper
101 };
102
103 static void opt_test_hook(struct opt_item * opt, uint event UNUSED, const char * value, void * data) {
104   if (!show_hooks)
105     return;
106   if (opt)
107     printf("[HOOK-%s:%c/%s=%s] ", (char *) data, opt->letter, opt->name, value);
108   else
109     printf("[HOOK-%s] ", (char *) data);
110 }
111
112 static struct opt_section water_options = {
113   OPT_ITEMS {
114     OPT_INT('w', "water", water_amount, OPT_REQUIRED | OPT_REQUIRED_VALUE, "<volume>\tAmount of water (in mls; required)"),
115     OPT_BOOL('G', "with-gas", with_gas, OPT_NO_VALUE, "\tUse water with gas"),
116     OPT_END
117   }
118 };
119
120 static struct opt_section options = {
121   OPT_ITEMS {
122     OPT_HELP("A simple tea boiling console."),
123     OPT_HELP("Usage: teapot [options] name-of-the-tea"),
124     OPT_HELP(""),
125     OPT_HELP("Black, green or white tea supported as well as fruit or herbal tea."),
126     OPT_HELP("You may specify more kinds of tea, all of them will be boiled for you, in the given order."),
127     OPT_HELP("At least one kind of tea must be specified."),
128     OPT_HELP(""),
129     OPT_HELP("Options:"),
130     OPT_HELP_OPTION,
131     OPT_CALL('V', "version", show_version, NULL, OPT_NO_VALUE, "\tShow the version"),
132     OPT_HELP(""),
133     OPT_BOOL('e', "english-style", english, 0, "\tEnglish style (with milk)"),
134     OPT_INT('s', "sugar", sugar, OPT_REQUIRED_VALUE, "<spoons>\tAmount of sugar (in teaspoons)"),
135     OPT_SWITCH(0, "standard-set", set, TEAPOT_STANDARD, OPT_SINGLE, "\tStandard teapot"),
136     OPT_SWITCH('x', "exclusive-set", set, TEAPOT_EXCLUSIVE, OPT_SINGLE, "\tExclusive teapot"),
137     OPT_SWITCH('g', "glass-set", set, TEAPOT_GLASS, OPT_SINGLE, "\tTransparent glass teapot"),
138     OPT_SWITCH('h', "hands", set, TEAPOT_HANDS, OPT_SINGLE, "\tUse user's hands as a teapot (a bit dangerous)"),
139     OPT_USER('t', "temperature", temperature, teapot_temperature_t, OPT_REQUIRED_VALUE | OPT_REQUIRED,
140                   "<value>\tWanted final temperature of the tea to be served (required)\n"
141               "\t\tSupported scales:  Celsius [60C], Fahrenheit [140F],\n"
142               "\t\t                   Kelvin [350K], Rankine [600R] and Reaumur [50Re]\n"
143               "\t\tOnly integer values allowed."),
144     OPT_INC('v', "verbose", verbose, 0, "\tVerbose (the more -v, the more verbose)"),
145     OPT_INC('q', "quiet", verbose, OPT_NEGATIVE, "\tQuiet (the more -q, the more quiet)"),
146     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."),
147     OPT_BOOL('p', "pray", pray, OPT_SINGLE, "\tPray before boiling"),
148     OPT_BOOL(0, "no-clean", clean_pot, OPT_NEGATIVE, "\tDo not clean the teapot before boiling"),
149     OPT_STRING(OPT_POSITIONAL(1), NULL, first_tea, OPT_REQUIRED, ""),
150     OPT_CALL(OPT_POSITIONAL_TAIL, NULL, add_tea, &tea_list, 0, ""),
151     OPT_HELP(""),
152     OPT_HELP("Water options:"),
153     OPT_SECTION(water_options),
154     OPT_HOOK(opt_test_hook, "prearg", OPT_HOOK_BEFORE_ARG),
155     OPT_HOOK(opt_test_hook, "preval", OPT_HOOK_BEFORE_VALUE),
156     OPT_HOOK(opt_test_hook, "postval", OPT_HOOK_AFTER_VALUE),
157     OPT_BOOL('H', "show-hooks", show_hooks, 0, "\tDemonstrate the hooks."),
158     OPT_HELP(""),
159     OPT_HELP("Configuration options:"),
160     OPT_CONF_OPTIONS,
161     OPT_END
162   }
163 };
164
165 struct intnode {
166   cnode n;
167   int x;
168 };
169
170 int main(int argc UNUSED, char ** argv)
171 {
172   cf_def_file = "etc/libucw";
173   GARY_INIT(black_magic, 0);
174   opt_parse(&options, argv+1);
175
176   printf("English style: %s|", english ? "yes" : "no");
177   if (sugar)
178     printf("Sugar: %d teaspoons|", sugar);
179   if (set != -1)
180     printf("Chosen teapot: %s|", teapot_type_str[set]);
181   printf("Temperature: %d%s|", temperature.value, temp_scale_str[temperature.scale]);
182   printf("Verbosity: %d|", verbose);
183   uint magick = GARY_SIZE(black_magic);
184   for (uint i=0; i<magick; i++)
185     printf("Black magic: %d|", black_magic[i]);
186   printf("Prayer: %s|", pray ? "yes" : "no");
187   printf("Clean: %s|", clean_pot ? "yes" : "no");
188   printf("Water amount: %d|", water_amount);
189   printf("Gas: %s|", with_gas ? "yes" : "no");
190   printf("First tea: %s|", first_tea);
191   for (int i=0; i<tea_num; i++)
192     printf("Boiling a tea: %s|", tea_list[i]);
193
194   printf("Everything OK. Bye.\n");
195 }