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