2 * UCW Library -- Parsing of command line options
4 * (c) 2013 Jan Moskyto Matejka <mq@ucw.cz>
5 * (c) 2014 Martin Mares <mj@ucw.cz>
7 * This software may be freely distributed and used according to the terms
8 * of the GNU Lesser General Public License.
13 #include <ucw/strtonum.h>
14 #include <ucw/fastbuf.h>
17 static void show_version(struct opt_item * opt UNUSED, const char * value UNUSED, void * data UNUSED) {
18 printf("This is a simple tea boiling console v0.1.\n");
22 struct teapot_temperature {
33 static char * temp_scale_str[] = { "C", "F", "K", "Re", "R" };
35 static enum TEAPOT_TYPE {
41 } set = TEAPOT_UNDEFINED;
43 static char * teapot_type_str[] = { "standard", "exclusive", "glass", "hands" };
45 static int show_hooks = 0;
46 static int english = 0;
48 static int verbose = 1;
49 static int with_gas = 0;
50 static int *black_magic;
52 static int water_amount = 0;
53 static char * first_tea = NULL;
55 #define MAX_TEA_COUNT 30
56 static char * tea_list[MAX_TEA_COUNT];
57 static int tea_num = 0;
58 static void add_tea(struct opt_item * opt UNUSED, const char * name, void * data) {
59 char ** tea_list = data;
60 if (tea_num >= MAX_TEA_COUNT) {
61 fprintf(stderr, "Cannot boil more than %d teas.\n", MAX_TEA_COUNT);
62 exit(OPT_EXIT_BAD_ARGS);
64 tea_list[tea_num++] = xstrdup(name);
67 static const char * teapot_temperature_parser(char * in, void * ptr) {
68 struct teapot_temperature * temp = ptr;
70 const char * err = str_to_int(&temp->value, in, &next, 10);
73 if (!strcmp("C", next))
74 temp->scale = TEMP_CELSIUS;
75 else if (!strcmp("F", next))
76 temp->scale = TEMP_FAHRENHEIT;
77 else if (!strcmp("K", next))
78 temp->scale = TEMP_KELVIN;
79 else if (!strcmp("R", next))
80 temp->scale = TEMP_RANKINE;
81 else if (!strcmp("Re", next))
82 temp->scale = TEMP_REAUMUR;
84 fprintf(stderr, "Unknown scale: %s\n", next);
85 exit(OPT_EXIT_BAD_ARGS);
90 static void teapot_temperature_dumper(struct fastbuf * fb, void * ptr) {
91 struct teapot_temperature * temp = ptr;
92 bprintf(fb, "%d%s", temp->value, temp_scale_str[temp->scale]);
95 static struct cf_user_type teapot_temperature_t = {
96 .size = sizeof(struct teapot_temperature),
97 .name = "teapot_temperature_t",
98 .parser = (cf_parser1*) teapot_temperature_parser,
99 .dumper = (cf_dumper1*) teapot_temperature_dumper
102 static void opt_test_hook(struct opt_item * opt, uns event UNUSED, const char * value, void * data) {
106 printf("[HOOK-%s:%c/%s=%s] ", (char *) data, opt->letter, opt->name, value);
108 printf("[HOOK-%s] ", (char *) data);
111 static struct opt_section water_options = {
113 OPT_INT('w', "water", water_amount, OPT_REQUIRED | OPT_REQUIRED_VALUE, "<volume>\tAmount of water (in mls; required)"),
114 OPT_BOOL('G', "with-gas", with_gas, OPT_NO_VALUE, "\tUse water with gas"),
119 static struct opt_section options = {
121 OPT_HELP("A simple tea boiling console."),
122 OPT_HELP("Usage: teapot [options] name-of-the-tea"),
124 OPT_HELP("Black, green or white tea supported as well as fruit or herbal tea."),
125 OPT_HELP("You may specify more kinds of tea, all of them will be boiled for you, in the given order."),
126 OPT_HELP("At least one kind of tea must be specified."),
128 OPT_HELP("Options:"),
130 OPT_CALL('V', "version", show_version, NULL, OPT_NO_VALUE, "\tShow the version"),
132 OPT_BOOL('e', "english-style", english, 0, "\tEnglish style (with milk)"),
133 OPT_INT('s', "sugar", sugar, OPT_REQUIRED_VALUE, "<spoons>\tAmount of sugar (in teaspoons)"),
134 OPT_SWITCH(0, "standard-set", set, TEAPOT_STANDARD, OPT_SINGLE, "\tStandard teapot"),
135 OPT_SWITCH('x', "exclusive-set", set, TEAPOT_EXCLUSIVE, OPT_SINGLE, "\tExclusive teapot"),
136 OPT_SWITCH('g', "glass-set", set, TEAPOT_GLASS, OPT_SINGLE, "\tTransparent glass teapot"),
137 OPT_SWITCH('h', "hands", set, TEAPOT_HANDS, OPT_SINGLE, "\tUse user's hands as a teapot (a bit dangerous)"),
138 OPT_USER('t', "temperature", temperature, teapot_temperature_t, OPT_REQUIRED_VALUE | OPT_REQUIRED,
139 "<value>\tWanted final temperature of the tea to be served (required)\n"
140 "\t\tSupported scales: Celsius [60C], Fahrenheit [140F],\n"
141 "\t\t Kelvin [350K], Rankine [600R] and Reaumur [50Re]\n"
142 "\t\tOnly integer values allowed."),
143 OPT_INC('v', "verbose", verbose, 0, "\tVerbose (the more -v, the more verbose)"),
144 OPT_INC('q', "quiet", verbose, OPT_NEGATIVE, "\tQuiet (the more -q, the more quiet)"),
145 OPT_INT_MULTIPLE('b', NULL, black_magic, 0, "<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."),
146 OPT_BOOL('p', "pray", pray, OPT_SINGLE, "\tPray before boiling"),
147 OPT_STRING(OPT_POSITIONAL(1), NULL, first_tea, OPT_REQUIRED, ""),
148 OPT_CALL(OPT_POSITIONAL_TAIL, NULL, add_tea, &tea_list, 0, ""),
150 OPT_HELP("Water options:"),
151 OPT_SECTION(water_options),
152 OPT_HOOK(opt_test_hook, "prearg", OPT_HOOK_BEFORE_ARG),
153 OPT_HOOK(opt_test_hook, "preval", OPT_HOOK_BEFORE_VALUE),
154 OPT_HOOK(opt_test_hook, "postval", OPT_HOOK_AFTER_VALUE),
155 OPT_BOOL('H', "show-hooks", show_hooks, 0, "\tDemonstrate the hooks."),
157 OPT_HELP("Configuration options:"),
168 int main(int argc UNUSED, char ** argv)
170 cf_def_file = "etc/libucw";
171 GARY_INIT(black_magic, 0);
172 opt_parse(&options, argv+1);
174 printf("English style: %s|", english ? "yes" : "no");
176 printf("Sugar: %d teaspoons|", sugar);
178 printf("Chosen teapot: %s|", teapot_type_str[set]);
179 printf("Temperature: %d%s|", temperature.value, temp_scale_str[temperature.scale]);
180 printf("Verbosity: %d|", verbose);
181 uns magick = GARY_SIZE(black_magic);
182 for (uns i=0; i<magick; i++)
183 printf("Black magic: %d|", black_magic[i]);
184 printf("Prayer: %s|", pray ? "yes" : "no");
185 printf("Water amount: %d|", water_amount);
186 printf("Gas: %s|", with_gas ? "yes" : "no");
187 printf("First tea: %s|", first_tea);
188 for (int i=0; i<tea_num; i++)
189 printf("Boiling a tea: %s|", tea_list[i]);
191 printf("Everything OK. Bye.\n");