]> mj.ucw.cz Git - libucw.git/blob - ucw/opt.c
Opt: OPT_MULTIPLE implemented, no tests yet but seems working
[libucw.git] / ucw / opt.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/conf.h>
13 #include <ucw/stkstring.h>
14 #include <ucw/strtonum.h>
15
16 #include <alloca.h>
17 #include <math.h>
18
19 static void opt_failure(const char * mesg, ...) FORMAT_CHECK(printf,1,2) NONRET;
20 static void opt_failure(const char * mesg, ...) {
21   va_list args;
22   va_start(args, mesg);
23   vfprintf(stderr, mesg, args);
24   fprintf(stderr, "\n");
25   opt_usage();
26   exit(OPT_EXIT_BAD_ARGS);
27   va_end(args);
28 }
29
30 #define OPT_ADD_DEFAULT_ITEM_FLAGS(item, flags) \
31   do { \
32     if (item->letter >= 256) { \
33       if (flags & OPT_VALUE_FLAGS) \
34         flags &= ~OPT_VALUE_FLAGS; \
35       flags |= OPT_REQUIRED_VALUE; \
36     } \
37     if (!(flags & OPT_VALUE_FLAGS) && \
38         (item->cls == OPT_CL_CALL || item->cls == OPT_CL_USER)) { \
39       fprintf(stderr, "You MUST specify some of the value flags for the %c/%s item.\n", item->letter, item->name); \
40       ASSERT(0); \
41     } \
42     else if (!(flags & OPT_VALUE_FLAGS)) \
43       flags |= opt_default_value_flags[item->cls]; \
44   } while (0)
45 #define OPT_ITEM_FLAGS(item) ((item->flags & OPT_VALUE_FLAGS) ? item->flags : item->flags | opt_default_value_flags[item->cls])
46
47 const struct opt_section * opt_section_root;
48
49 #define FOREACHLINE(text) for (const char * begin = (text), * end = (text); (*end) && (end = strchrnul(begin, '\n')); begin = end+1)
50
51 void opt_help_internal(const struct opt_section * help) {
52   int sections_cnt = 0;
53   int lines_cnt = 0;
54
55   for (struct opt_item * item = help->opt; item->cls != OPT_CL_END; item++) {
56     if (item->flags & OPT_NO_HELP) continue;
57     if (item->cls == OPT_CL_SECTION) {
58       sections_cnt++;
59       continue;
60     }
61     if (!*(item->help)) {
62       lines_cnt++;
63       continue;
64     }
65     FOREACHLINE(item->help)
66       lines_cnt++;
67   }
68
69   struct opt_sectlist {
70     int pos;
71     struct opt_section * sect;
72   } sections[sections_cnt];
73   int s = 0;
74
75   const char *lines[lines_cnt][3];
76   memset(lines, 0, sizeof(lines));
77   int line = 0;
78
79   int linelengths[3] = { -1, -1, -1 };
80
81   for (struct opt_item * item = help->opt; item->cls != OPT_CL_END; item++) {
82     if (item->flags & OPT_NO_HELP) continue;
83
84     if (item->cls == OPT_CL_HELP) {
85       if (!*(item->help)) {
86         line++;
87         continue;
88       }
89 #define SPLITLINES(text) do { \
90       FOREACHLINE(text) { \
91         int cell = 0; \
92         for (const char * b = begin, * e = begin; (e < end) && (e = strchrnul(b, '\t')) && (e > end ? (e = end) : end); b = e+1) { \
93           lines[line][cell] = b; \
94           if (cell >= 2) \
95             break; \
96           else \
97             if (*e == '\t' && linelengths[cell] < (e - b)) \
98               linelengths[cell] = e-b; \
99           cell++; \
100         } \
101         line++; \
102       } } while (0)
103       SPLITLINES(item->help);
104       continue;
105     }
106
107     if (item->cls == OPT_CL_SECTION) {
108       sections[s++] = (struct opt_sectlist) { .pos = line, .sect = item->u.section };
109       continue;
110     }
111
112     uns valoff = strchrnul(item->help, '\t') - item->help;
113     uns eol = strchrnul(item->help, '\n') - item->help;
114     if (valoff > eol)
115       valoff = eol;
116 #define VAL(it) ((OPT_ITEM_FLAGS(it) & OPT_REQUIRED_VALUE) ? stk_printf("=%.*s", valoff, item->help)  : ((OPT_ITEM_FLAGS(it) & OPT_NO_VALUE) ? "" : stk_printf("(=%.*s)", valoff, item->help)))
117     if (item->name) {
118       lines[line][1] = stk_printf("--%s%s", item->name, VAL(item));
119       if (linelengths[1] < (int) strlen(lines[line][1]))
120         linelengths[1] = strlen(lines[line][1]);
121       lines[line][0] = "";
122       if (linelengths[0] < 0)
123         linelengths[0] = 0;
124     }
125     if (item->letter) {
126       lines[line][0] = stk_printf("-%c,", item->letter);
127       if (linelengths[0] < (int) strlen(lines[line][0]))
128         linelengths[0] = strlen(lines[line][0]);
129     }
130 #undef VAL
131
132     if (eol > valoff) {
133       lines[line][2] = item->help + valoff + 1;
134     }
135
136     line++;
137
138     if (*(item->help + eol))
139       SPLITLINES(item->help + eol + 1);
140   }
141 #undef SPLITLINES
142
143   s = 0;
144 #define FIELD(k) linelengths[k], MIN(strchrnul(lines[i][k], '\t')-lines[i][k],strchrnul(lines[i][k], '\n')-lines[i][k]), lines[i][k]
145 #define LASTFIELD(k) MIN(strchrnul(lines[i][k], '\t')-lines[i][k],strchrnul(lines[i][k], '\n')-lines[i][k]), lines[i][k]
146   for (int i=0;i<line;i++) {
147     while (s < sections_cnt && sections[s].pos == i) {
148       opt_help_internal(sections[s].sect);
149       s++;
150     }
151     if (lines[i][0] == NULL)
152       printf("\n");
153     else if (linelengths[0] == -1 || lines[i][1] == NULL)
154       printf("%.*s\n", LASTFIELD(0));
155     else if (linelengths[1] == -1 || lines[i][2] == NULL)
156       printf("%-*.*s  %.*s\n", FIELD(0), LASTFIELD(1));
157     else
158       printf("%-*.*s  %-*.*s  %.*s\n", FIELD(0), FIELD(1), LASTFIELD(2));
159   }
160   while (s < sections_cnt && sections[s].pos == line) {
161     opt_help_internal(sections[s].sect);
162     s++;
163   }
164 }
165
166 static int opt_positional_max = 0;
167 static int opt_positional_count = 0;
168
169 struct opt_precomputed {
170   struct opt_precomputed_option {
171     struct opt_item * item;
172     const char * name;
173     short flags;
174     short count;
175   } ** opts;
176   struct opt_precomputed_option ** shortopt;
177   short opt_count;
178 };
179
180 static struct opt_precomputed_option * opt_find_item_shortopt(int chr, struct opt_precomputed * pre) {
181   struct opt_precomputed_option * candidate = pre->shortopt[chr];
182   if (!candidate)
183     opt_failure("Invalid option -%c", chr);
184   if (candidate->count++ && (candidate->flags & OPT_SINGLE))
185     opt_failure("Option -%c appeared the second time.", candidate->item->letter);
186   return candidate;
187 }
188
189 static struct opt_precomputed_option * opt_find_item_longopt(char * str, struct opt_precomputed * pre) {
190   uns len = strlen(str);
191   struct opt_precomputed_option * candidate = NULL;
192
193   for (int i=0; i<pre->opt_count; i++) {
194     if (!strncmp(pre->opts[i]->name, str, len)) {
195       if (strlen(pre->opts[i]->name) == len) {
196         if (pre->opts[i]->count++ && (pre->opts[i]->flags & OPT_SINGLE))
197           opt_failure("Option %s appeared the second time.", pre->opts[i]->name);
198
199         return pre->opts[i];
200       }
201       if (candidate)
202         opt_failure("Ambiguous prefix %s: Found matching %s and %s.", str, candidate->name, pre->opts[i]->name);
203       else
204         candidate = pre->opts[i];
205     }
206     if (!strncmp("no-", str, 3) && !strncmp(pre->opts[i]->name, str+3, len-3)) {
207       if (strlen(pre->opts[i]->name) == len-3) {
208         if (pre->opts[i]->count++ && (pre->opts[i]->flags & OPT_SINGLE))
209           opt_failure("Option %s appeared the second time.", pre->opts[i]->name);
210
211         return pre->opts[i];
212       }
213       if (candidate)
214         opt_failure("Ambiguous prefix %s: Found matching %s and %s.", str, candidate->name, pre->opts[i]->name);
215       else
216         candidate = pre->opts[i];
217     }
218   }
219
220   if (candidate)
221     return candidate;
222
223   opt_failure("Invalid option %s.", str);
224 }
225
226 #define OPT_PTR(type) ({ \
227   type * ptr; \
228   if (item->flags & OPT_MULTIPLE) { \
229     struct { \
230       cnode n; \
231       type v; \
232     } * n = xmalloc(sizeof(*n)); \
233     clist_add_tail(item->ptr, &(n->n)); \
234     ptr = &(n->v); \
235   } else \
236     ptr = item->ptr; \
237   ptr; })
238
239 #define OPT_NAME (longopt == 2 ? stk_printf("positional arg #%d", opt_positional_count) : (longopt == 1 ? stk_printf("--%s", opt->name) : stk_printf("-%c", item->letter)))
240 static void opt_parse_value(struct opt_precomputed_option * opt, char * value, int longopt) {
241   struct opt_item * item = opt->item;
242
243   switch (item->cls) {
244     case OPT_CL_BOOL:
245       if (!value || !strcasecmp(value, "y") || !strcasecmp(value, "yes") || !strcasecmp(value, "true") || !strcasecmp(value, "1"))
246         *((int *) item->ptr) = 1 ^ (!!(opt->flags & OPT_NEGATIVE));
247       else if (!strcasecmp(value, "n") || !strcasecmp(value, "no") || !strcasecmp(value, "false") || !strcasecmp(value, "0"))
248         *((int *) item->ptr) = 0 ^ (!!(opt->flags & OPT_NEGATIVE));
249       else
250         opt_failure("Boolean argument for %s has a strange value. Supported (case insensitive): y/n, yes/no, true/false.", OPT_NAME);
251       break;
252     case OPT_CL_STATIC:
253       {
254         char * e = NULL;
255         switch (item->type) {
256           case CT_INT:
257             if (!value)
258               *OPT_PTR(int) = 0;
259             else
260               e = cf_parse_int(value, OPT_PTR(int));
261             if (e)
262               opt_failure("Integer value parsing failed for %s: %s", OPT_NAME, e);
263             break;
264           case CT_U64:
265             if (!value)
266               *OPT_PTR(u64) = 0;
267             else
268               e = cf_parse_u64(value, OPT_PTR(u64));
269             if (e)
270               opt_failure("Unsigned 64-bit value parsing failed for %s: %s", OPT_NAME, e);
271             break;
272           case CT_DOUBLE:
273             if (!value)
274               *OPT_PTR(double) = NAN;
275             else
276               e = cf_parse_double(value, OPT_PTR(double));
277             if (e)
278               opt_failure("Double value parsing failed for %s: %s", OPT_NAME, e);
279             break;
280           case CT_IP:
281             if (!value)
282               e = cf_parse_ip("0.0.0.0", OPT_PTR(u32));
283             else
284               e = cf_parse_ip(value, OPT_PTR(u32));
285             if (e)
286               opt_failure("IP parsing failed for %s: %s", OPT_NAME, e);
287             break;
288           case CT_STRING:
289             if (!value)
290               *OPT_PTR(const char *) = NULL;
291             else
292               *OPT_PTR(const char *) = xstrdup(value);
293             break;
294           default:
295             ASSERT(0);
296         }
297         break;
298       }
299     case OPT_CL_SWITCH:
300       if (*((int *)item->ptr) != -1)
301         opt_failure("Multiple switches: %s", OPT_NAME);
302       else
303         *((int *)item->ptr) = item->u.value;
304       break;
305     case OPT_CL_INC:
306       if (opt->flags & OPT_NEGATIVE)
307         (*((int *)item->ptr))--;
308       else
309         (*((int *)item->ptr))++;
310       break;
311     case OPT_CL_CALL:
312       item->u.call(item, value, item->ptr);
313       break;
314     case OPT_CL_USER:
315       {
316         char * e = NULL;
317         e = item->u.utype->parser(value, OPT_PTR(void*));
318         if (e)
319           opt_failure("User defined type value parsing failed for %s: %s", OPT_NAME, e);
320         break;
321       }
322     default:
323       ASSERT(0);
324   }
325 }
326 #undef OPT_NAME
327
328 static int opt_longopt(char ** argv, int index, struct opt_precomputed * pre) {
329   int eaten = 0;
330   char * name_in = argv[index] + 2; // skipping the -- on the beginning
331   uns pos = strchrnul(name_in, '=') - name_in;
332   struct opt_precomputed_option * opt = opt_find_item_longopt(strndupa(name_in, pos), pre);
333   char * value = NULL;
334
335   if (opt->item->cls == OPT_CL_BOOL && !strncmp(name_in, "no-", 3) && !strncmp(name_in+3, opt->item->name, pos-3))
336     value = "n";
337   else if (opt->flags & OPT_REQUIRED_VALUE) {
338     if (pos < strlen(name_in))
339       value = name_in + pos + 1;
340     else {
341       value = argv[index+1];
342       if (!value)
343         opt_failure("Argument --%s must have a value but nothing supplied.", opt->name);
344       eaten++;
345     }
346   }
347   else if (opt->flags & OPT_MAYBE_VALUE) {
348     if (pos < strlen(name_in))
349       value = name_in + pos + 1;
350   }
351   else {
352     if (pos < strlen(name_in))
353       opt_failure("Argument --%s must not have any value.", opt->name);
354   }
355   opt_parse_value(opt, value, 1);
356   return eaten;
357 }
358
359 static int opt_shortopt(char ** argv, int index, struct opt_precomputed * pre) {
360   int chr = 0;
361   struct opt_precomputed_option * opt;
362   while (argv[index][++chr] && (opt = opt_find_item_shortopt(argv[index][chr], pre))) {
363     if (opt->flags & OPT_NO_VALUE) {
364       opt_parse_value(opt, NULL, 0);
365     }
366     else if (opt->flags & OPT_REQUIRED_VALUE) {
367       if (chr == 1 && argv[index][2]) {
368         opt_parse_value(opt, argv[index] + 2, 0);
369         return 0;
370       }
371       else if (argv[index][chr+1])
372         opt_failure("Option -%c must have a value but found inside a bunch of short opts.", opt->item->letter);
373       else if (!argv[index+1])
374         opt_failure("Option -%c must have a value but nothing supplied.", opt->item->letter);
375       else {
376         opt_parse_value(opt, argv[index+1], 0);
377         return 1;
378       }
379     }
380     else if (opt->flags & OPT_MAYBE_VALUE) {
381       if (chr == 1 && argv[index][2]) {
382         opt_parse_value(opt, argv[index] + 2, 0);
383         return 0;
384       }
385       else
386         opt_parse_value(opt, NULL, 0);
387     }
388     else {
389       ASSERT(0);
390     }
391   }
392
393   if (argv[index][chr])
394     opt_failure("Unknown option -%c.", argv[index][chr]);
395   
396   return 0;
397 }
398
399 static void opt_positional(char * value, struct opt_precomputed * pre) {
400   opt_positional_count++;
401   struct opt_precomputed_option * opt = opt_find_item_shortopt((opt_positional_count > opt_positional_max ? 256 : opt_positional_count + 256), pre);
402   if (!opt) {
403     ASSERT(opt_positional_count > opt_positional_max);
404     opt_failure("Too many positional args.");
405   }
406
407   opt_parse_value(opt, value, 2);
408 }
409
410 #define OPT_TRAVERSE_SECTIONS \
411     while (item->cls == OPT_CL_SECTION) { \
412       if (stk->next) \
413         stk = stk->next; \
414       else { \
415         struct opt_stack * new_stk = alloca(sizeof(*new_stk)); \
416         new_stk->prev = stk; \
417         stk->next = new_stk; \
418         stk = new_stk; \
419       } \
420       stk->this = item; \
421       item = item->u.section->opt; \
422     } \
423     if (item->cls == OPT_CL_END) { \
424       if (!stk->prev) break; \
425       item = stk->this; \
426       stk = stk->prev; \
427       continue; \
428     }
429
430 void opt_parse(const struct opt_section * options, char ** argv) {
431   opt_section_root = options;
432
433   struct opt_stack {
434     struct opt_item * this;
435     struct opt_stack * prev;
436     struct opt_stack * next;
437   } * stk = alloca(sizeof(*stk));
438   stk->this = NULL;
439   stk->prev = NULL;
440   stk->next = NULL;
441
442   struct opt_precomputed * pre = alloca(sizeof(*pre));
443   memset(pre, 0, sizeof (*pre));
444
445   int count = 0;
446
447   for (struct opt_item * item = options->opt; ; item++) {
448     OPT_TRAVERSE_SECTIONS;
449     if (item->letter || item->name)
450       count++;
451     if (item->cls == OPT_CL_BOOL)
452       count++;
453     if (item->letter > 256)
454       opt_positional_max++;
455   }
456   
457   pre->opts = alloca(sizeof(*pre->opts) * count);
458   pre->shortopt = alloca(sizeof(*pre->shortopt) * (opt_positional_max + 257));
459   memset(pre->shortopt, 0, sizeof(*pre->shortopt) * (opt_positional_max + 257));
460   
461   pre->opt_count = 0;
462
463   for (struct opt_item * item = options->opt; ; item++) {
464     OPT_TRAVERSE_SECTIONS;
465     if (item->letter || item->name) {
466       struct opt_precomputed_option * opt = xmalloc(sizeof(*opt));
467       opt->item = item;
468       opt->flags = item->flags;
469       opt->count = 0;
470       opt->name = item->name;
471       pre->opts[pre->opt_count++] = opt;
472       if (item->letter)
473         pre->shortopt[(int) item->letter] = opt;
474       OPT_ADD_DEFAULT_ITEM_FLAGS(item, opt->flags);
475     }
476   }
477
478   int force_positional = 0;
479   for (int i=0;argv[i];i++) {
480     if (argv[i][0] != '-' || force_positional) {
481       opt_positional(argv[i], pre);
482     }
483     else {
484       if (argv[i][1] == '-') {
485         if (argv[i][2] == '\0')
486           force_positional++;
487         else
488           i += opt_longopt(argv, i, pre);
489       }
490       else if (argv[i][1])
491         i += opt_shortopt(argv, i, pre);
492       else
493         opt_positional(argv[i], pre);
494     }
495   }
496
497   for (int i=0;i<opt_positional_max+257;i++) {
498     if (!pre->shortopt[i])
499       continue;
500     if (!pre->shortopt[i]->count && (pre->shortopt[i]->flags & OPT_REQUIRED))
501       if (i < 256)
502         opt_failure("Required option -%c not found.\n", pre->shortopt[i]->item->letter);
503       else
504         opt_failure("Required positional argument #%d not found.\n", (i > 256) ? pre->shortopt[i]->item->letter-256 : opt_positional_max+1);
505   }
506
507   for (int i=0;i<pre->opt_count;i++) {
508     if (!pre->opts[i])
509       continue;
510     if (!pre->opts[i]->count && (pre->opts[i]->flags & OPT_REQUIRED))
511       opt_failure("Required option --%s not found.\n", pre->opts[i]->item->name);
512   }
513 }
514
515 #ifdef TEST
516 #include <ucw/fastbuf.h>
517
518 static void show_version(struct opt_item * opt UNUSED, const char * value UNUSED, void * data UNUSED) {
519   printf("This is a simple tea boiling console v0.1.\n");
520   exit(EXIT_SUCCESS);
521 }
522
523 struct teapot_temperature {
524   enum {
525     TEMP_CELSIUS = 0,
526     TEMP_FAHRENHEIT,
527     TEMP_KELVIN,
528     TEMP_REAUMUR,
529     TEMP_RANKINE
530   } scale;
531   int value;
532 } temperature;
533
534 static char * temp_scale_str[] = { "C", "F", "K", "Re", "R" };
535
536 static enum TEAPOT_TYPE {
537   TEAPOT_STANDARD = 0,
538   TEAPOT_EXCLUSIVE,
539   TEAPOT_GLASS,
540   TEAPOT_HANDS,
541   TEAPOT_UNDEFINED = -1
542 } set = TEAPOT_UNDEFINED;
543
544 static char * teapot_type_str[] = { "standard", "exclusive", "glass", "hands" };
545
546 static int english = 0;
547 static int sugar = 0;
548 static int verbose = 1;
549 static int with_gas = 0;
550 static clist black_magic;
551 static int pray = 0;
552 static int water_amount = 0;
553 static char * first_tea = NULL;
554
555 #define MAX_TEA_COUNT 30
556 static char * tea_list[MAX_TEA_COUNT];
557 static int tea_num = 0;
558 static void add_tea(struct opt_item * opt UNUSED, const char * name, void * data) {
559   char ** tea_list = data;
560   if (tea_num >= MAX_TEA_COUNT) {
561     fprintf(stderr, "Cannot boil more than %d teas.\n", MAX_TEA_COUNT);
562     exit(OPT_EXIT_BAD_ARGS);
563   }
564   tea_list[tea_num++] = xstrdup(name);
565 }
566
567 static const char * teapot_temperature_parser(char * in, void * ptr) {
568   struct teapot_temperature * temp = ptr;
569   const char * next;
570   const char * err = str_to_int(&temp->value, in, &next, 10);
571   if (err)
572     return err;
573   if (!strcmp("C", next))
574     temp->scale = TEMP_CELSIUS;
575   else if (!strcmp("F", next))
576     temp->scale = TEMP_FAHRENHEIT;
577   else if (!strcmp("K", next))
578     temp->scale = TEMP_KELVIN;
579   else if (!strcmp("R", next))
580     temp->scale = TEMP_RANKINE;
581   else if (!strcmp("Re", next))
582     temp->scale = TEMP_REAUMUR;
583   else {
584     fprintf(stderr, "Unknown scale: %s\n", next);
585     exit(OPT_EXIT_BAD_ARGS);
586   }
587   return NULL;
588 }
589
590 static void teapot_temperature_dumper(struct fastbuf * fb, void * ptr) {
591   struct teapot_temperature * temp = ptr;
592   bprintf(fb, "%d%s", temp->value, temp_scale_str[temp->scale]);
593 }
594
595 static struct cf_user_type teapot_temperature_t = {
596   .size = sizeof(struct teapot_temperature),
597   .name = "teapot_temperature_t",
598   .parser = (cf_parser1*) teapot_temperature_parser,
599   .dumper = (cf_dumper1*) teapot_temperature_dumper
600 };
601
602 static struct opt_section water_options = {
603   OPT_ITEMS {
604     OPT_INT('w', "water", water_amount, OPT_REQUIRED | OPT_REQUIRED_VALUE, "<volume>\tAmount of water (in mls; required)"),
605     OPT_BOOL('G', "with-gas", with_gas, OPT_NO_VALUE, "\tUse water with gas"),
606     OPT_END
607   }
608 };
609
610 static struct opt_section help = {
611   OPT_ITEMS {
612     OPT_HELP("A simple tea boiling console."),
613     OPT_HELP("Usage: teapot [options] name-of-the-tea"),
614     OPT_HELP("Black, green or white tea supported as well as fruit or herbal tea."),
615     OPT_HELP("You may specify more kinds of tea, all of them will be boiled for you, in the given order."),
616     OPT_HELP("At least one kind of tea must be specified."),
617     OPT_HELP(""),
618     OPT_HELP("Options:"),
619     OPT_HELP_OPTION,
620     OPT_CALL('V', "version", show_version, NULL, OPT_NO_VALUE, "\tShow the version"),
621     OPT_HELP(""),
622     OPT_BOOL('e', "english-style", english, 0, "\tEnglish style (with milk)"),
623     OPT_INT('s', "sugar", sugar, OPT_REQUIRED_VALUE, "<spoons>\tAmount of sugar (in teaspoons)"),
624     OPT_SWITCH(0, "standard-set", set, TEAPOT_STANDARD, 0, "\tStandard teapot"),
625     OPT_SWITCH('x', "exclusive-set", set, TEAPOT_EXCLUSIVE, 0, "\tExclusive teapot"),
626     OPT_SWITCH('g', "glass-set", set, TEAPOT_GLASS, 0, "\tTransparent glass teapot"),
627     OPT_SWITCH('h', "hands", set, TEAPOT_HANDS, 0, "\tUse user's hands as a teapot (a bit dangerous)"),
628     OPT_USER('t', "temperature", temperature, teapot_temperature_t, OPT_REQUIRED_VALUE | OPT_REQUIRED,
629                   "<value>\tWanted final temperature of the tea to be served (required)\n"
630               "\t\tSupported scales:  Celsius [60C], Fahrenheit [140F],\n"
631               "\t\t                   Kelvin [350K], Rankine [600R] and Reaumur [50Re]\n"
632               "\t\tOnly integer values allowed."),
633     OPT_INC('v', "verbose", verbose, 0, "\tVerbose (the more -v, the more verbose)"),
634     OPT_INC('q', "quiet", verbose, OPT_NEGATIVE, "\tQuiet (the more -q, the more quiet)"),
635     OPT_INT('b', "black-magic", black_magic, OPT_MULTIPLE, "<strength>\tUse black magic to make the tea extraordinary 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."),
636     OPT_BOOL('p', "pray", pray, OPT_SINGLE, "\tPray before boiling"),
637     OPT_STRING(OPT_POSITIONAL(1), NULL, first_tea, OPT_REQUIRED | OPT_NO_HELP, ""),
638     OPT_CALL(OPT_POSITIONAL_TAIL, NULL, add_tea, &tea_list, OPT_NO_HELP, ""),
639     OPT_HELP(""),
640     OPT_HELP("Water options:"),
641     OPT_SECTION(water_options),
642     OPT_END
643   }
644 };
645
646 struct intnode {
647   cnode n;
648   int x;
649 };
650
651 int main(int argc UNUSED, char ** argv)
652 {
653   clist_init(&black_magic);
654   opt_parse(&help, argv+1);
655
656   printf("English style: %s|", english ? "yes" : "no");
657   if (sugar)
658     printf("Sugar: %d teaspoons|", sugar);
659   if (set != -1)
660     printf("Chosen teapot: %s|", teapot_type_str[set]);
661   printf("Temperature: %d%s|", temperature.value, temp_scale_str[temperature.scale]);
662   printf("Verbosity: %d|", verbose);
663   CLIST_FOR_EACH(struct intnode *, n, black_magic)
664     printf("Black magic: %d|", n->x);
665   printf("Prayer: %s|", pray ? "yes" : "no");
666   printf("Water amount: %d|", water_amount);
667   printf("Gas: %s|", with_gas ? "yes" : "no");
668   printf("First tea: %s|", first_tea);
669   for (int i=0; i<tea_num; i++)
670     printf("Boiling a tea: %s|", tea_list[i]);
671
672   printf("Everything OK. Bye.\n");
673 }
674
675 #endif