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"),
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."),
125 OPT_HELP("Options:"),
126 OPT_HELP_OPTION(help),
127 OPT_CALL('V', "version", show_version, NULL, OPT_NO_VALUE, "\tShow the version"),
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, ""),
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."),
163 int main(int argc UNUSED, char ** argv)
165 clist_init(&black_magic);
166 opt_parse(&help, argv+1);
168 printf("English style: %s|", english ? "yes" : "no");
170 printf("Sugar: %d teaspoons|", sugar);
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]);
184 printf("Everything OK. Bye.\n");