2 * UCW Library -- Parsing of command line options
4 * (c) 2013 Jan Moskyto Matejka <mq@ucw.cz>
6 * This software may be freely distributed and used according to the terms
7 * of the GNU Lesser General Public License.
12 #include <ucw/strtonum.h>
13 #include <ucw/fastbuf.h>
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");
20 struct teapot_temperature {
31 static char * temp_scale_str[] = { "C", "F", "K", "Re", "R" };
33 static enum TEAPOT_TYPE {
39 } set = TEAPOT_UNDEFINED;
41 static char * teapot_type_str[] = { "standard", "exclusive", "glass", "hands" };
43 static int show_hooks = 0;
44 static int english = 0;
46 static int verbose = 1;
47 static int with_gas = 0;
48 static clist black_magic;
50 static int water_amount = 0;
51 static char * first_tea = NULL;
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);
62 tea_list[tea_num++] = xstrdup(name);
65 static const char * teapot_temperature_parser(char * in, void * ptr) {
66 struct teapot_temperature * temp = ptr;
68 const char * err = str_to_int(&temp->value, in, &next, 10);
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;
82 fprintf(stderr, "Unknown scale: %s\n", next);
83 exit(OPT_EXIT_BAD_ARGS);
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]);
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
100 static void opt_test_hook(struct opt_item * opt, const char * value, void * data) {
104 printf("[HOOK-%s:%c/%s=%s] ", (char *) data, opt->letter, opt->name, value);
106 printf("[HOOK-%s] ", (char *) data);
109 static struct opt_section water_options = {
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"),
117 static struct opt_section help = {
119 OPT_HELP("A simple tea boiling console."),
120 OPT_HELP("Usage: teapot [options] name-of-the-tea"),
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."),
126 OPT_HELP("Options:"),
127 OPT_HELP_OPTION(help),
128 OPT_CALL('V', "version", show_version, NULL, OPT_NO_VALUE, "\tShow the version"),
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, ""),
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."),
155 OPT_HELP("Configuration options:"),
166 int main(int argc UNUSED, char ** argv)
168 cf_def_file = "etc/libucw";
169 clist_init(&black_magic);
170 opt_parse(&help, argv+1);
172 printf("English style: %s|", english ? "yes" : "no");
174 printf("Sugar: %d teaspoons|", sugar);
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]);
188 printf("Everything OK. Bye.\n");