]> mj.ucw.cz Git - libucw.git/blob - ucw/opt-test.c
Merge branch 'master' into dev-opt
[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("Black, green or white tea supported as well as fruit or herbal tea."),
122     OPT_HELP("You may specify more kinds of tea, all of them will be boiled for you, in the given order."),
123     OPT_HELP("At least one kind of tea must be specified."),
124     OPT_HELP(""),
125     OPT_HELP("Options:"),
126     OPT_HELP_OPTION,
127     OPT_CALL('V', "version", show_version, NULL, OPT_NO_VALUE, "\tShow the version"),
128     OPT_HELP(""),
129     OPT_BOOL('e', "english-style", english, 0, "\tEnglish style (with milk)"),
130     OPT_INT('s', "sugar", sugar, OPT_REQUIRED_VALUE, "<spoons>\tAmount of sugar (in teaspoons)"),
131     OPT_SWITCH(0, "standard-set", set, TEAPOT_STANDARD, 0, "\tStandard teapot"),
132     OPT_SWITCH('x', "exclusive-set", set, TEAPOT_EXCLUSIVE, 0, "\tExclusive teapot"),
133     OPT_SWITCH('g', "glass-set", set, TEAPOT_GLASS, 0, "\tTransparent glass teapot"),
134     OPT_SWITCH('h', "hands", set, TEAPOT_HANDS, 0, "\tUse user's hands as a teapot (a bit dangerous)"),
135     OPT_USER('t', "temperature", temperature, teapot_temperature_t, OPT_REQUIRED_VALUE | OPT_REQUIRED,
136                   "<value>\tWanted final temperature of the tea to be served (required)\n"
137               "\t\tSupported scales:  Celsius [60C], Fahrenheit [140F],\n"
138               "\t\t                   Kelvin [350K], Rankine [600R] and Reaumur [50Re]\n"
139               "\t\tOnly integer values allowed."),
140     OPT_INC('v', "verbose", verbose, 0, "\tVerbose (the more -v, the more verbose)"),
141     OPT_INC('q', "quiet", verbose, OPT_NEGATIVE, "\tQuiet (the more -q, the more quiet)"),
142     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."),
143     OPT_BOOL('p', "pray", pray, OPT_SINGLE, "\tPray before boiling"),
144     OPT_STRING(OPT_POSITIONAL(1), NULL, first_tea, OPT_REQUIRED | OPT_NO_HELP, ""),
145     OPT_CALL(OPT_POSITIONAL_TAIL, NULL, add_tea, &tea_list, OPT_NO_HELP, ""),
146     OPT_HELP(""),
147     OPT_HELP("Water options:"),
148     OPT_SECTION(water_options),
149     OPT_HOOK(opt_test_hook, "prearg", OPT_HOOK_BEFORE_ARG),
150     OPT_HOOK(opt_test_hook, "preval", OPT_HOOK_BEFORE_VALUE),
151     OPT_HOOK(opt_test_hook, "postval", OPT_HOOK_AFTER_VALUE),
152     OPT_BOOL('H', "show-hooks", show_hooks, 0, "Demonstrate the hooks."),
153     OPT_CONF_OPTIONS,
154     OPT_END
155   }
156 };
157
158 struct intnode {
159   cnode n;
160   int x;
161 };
162
163 int main(int argc UNUSED, char ** argv)
164 {
165   clist_init(&black_magic);
166   opt_parse(&help, argv+1);
167
168   printf("English style: %s|", english ? "yes" : "no");
169   if (sugar)
170     printf("Sugar: %d teaspoons|", sugar);
171   if (set != -1)
172     printf("Chosen teapot: %s|", teapot_type_str[set]);
173   printf("Temperature: %d%s|", temperature.value, temp_scale_str[temperature.scale]);
174   printf("Verbosity: %d|", verbose);
175   CLIST_FOR_EACH(struct intnode *, n, black_magic)
176     printf("Black magic: %d|", n->x);
177   printf("Prayer: %s|", pray ? "yes" : "no");
178   printf("Water amount: %d|", water_amount);
179   printf("Gas: %s|", with_gas ? "yes" : "no");
180   printf("First tea: %s|", first_tea);
181   for (int i=0; i<tea_num; i++)
182     printf("Boiling a tea: %s|", tea_list[i]);
183
184   printf("Everything OK. Bye.\n");
185 }