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/stkstring.h>
13 #include <ucw/strtonum.h>
17 struct opt_section * opt_section_root;
19 void opt_help_noexit_internal(struct opt_section * help) {
22 for (struct opt_item * item = help->opt; item->cls != OPT_CL_END; item++) {
23 if (item->flags & OPT_NO_HELP) continue;
24 if (item->cls == OPT_CL_HELP && item->u.help2 == NULL) continue;
25 if (item->cls == OPT_CL_SECTION) continue;
28 if (item->cls == OPT_CL_HELP) { // two-column help line
29 if (first_column < strlen(item->help))
30 first_column = strlen(item->help);
34 if (item->letter) { // will write sth like "-x, --exclusive"
35 linelen = strlen("-x, --") + strlen(item->name);
36 } else { // will write sth like "--exclusive"
37 linelen = strlen("--") + strlen(item->name);
40 ASSERT(item->flags & OPT_VALUE_FLAGS);
42 if (item->flags & OPT_REQUIRED_VALUE) {
43 linelen += strlen("=value");
44 } else if (item->flags & OPT_MAYBE_VALUE) {
45 linelen += strlen("(=value)");
48 if (linelen > first_column)
49 first_column = linelen;
52 char * spaces = alloca(first_column + 1);
53 char * buf = alloca(first_column + 1);
54 for (uns i=0;i<first_column;i++)
57 spaces[first_column] = 0;
59 #define VAL(it) ((it->flags & OPT_REQUIRED_VALUE) ? "=value" : ((it->flags & OPT_NO_VALUE) ? "" : "(=value)"))
60 for (struct opt_item * item = help->opt; item->cls != OPT_CL_END; item++) {
61 if (item->flags & OPT_NO_HELP) continue;
63 if (item->cls == OPT_CL_HELP) {
64 fprintf(stderr, "%s", item->help);
65 if (item->u.help2 == NULL)
66 fprintf(stderr, "\n");
68 fprintf(stderr, "%s %s\n", spaces + strlen(item->help), item->u.help2);
69 } else if (item->cls == OPT_CL_SECTION) {
70 opt_help_noexit_internal(item->u.section);
71 } else if (item->letter) {
72 sprintf(buf, "-%c, --%s%s", item->letter, item->name, VAL(item));
73 fprintf(stderr, "%s%s %s\n", buf, spaces + strlen(buf), item->help);
75 sprintf(buf, "--%s%s", item->name, VAL(item));
76 fprintf(stderr, "%s%s %s\n", buf, spaces + strlen(buf), item->help);
81 void opt_init(struct opt_section * options) {
82 opt_section_root = options;
83 for (struct opt_item * item = options->opt; item->cls != OPT_CL_END; item++)
84 if (!(item->flags & OPT_VALUE_FLAGS)) {
85 if (item->cls == OPT_CL_CALL || item->cls == OPT_CL_USER) {
86 fprintf(stderr, "You MUST specify some of the value flags for the %c/%s item.\n", item->letter, item->name);
89 item->flags |= opt_default_value_flags[item->cls];
93 int opt_parse(char ** argv, char *** posargs) {
94 // Temporary. To be fixed.
96 d = xmalloc(sizeof (*d) * 2);
104 #include <ucw/fastbuf.h>
106 static int show_version(const char ** param UNUSED) {
107 printf("This is a simple tea boiling console v0.1.\n");
111 struct teapot_temperature {
122 static char * temp_scale_str[] = { "C", "F", "K", "Re", "R" };
124 static enum TEAPOT_TYPE {
129 TEAPOT_UNDEFINED = -1
130 } set = TEAPOT_UNDEFINED;
132 static int english = 0;
133 static char * name = NULL;
134 static uns sugar = 0;
135 static uns verbose = 1;
136 static int with_gas = 0;
137 static uns black_magic = 0;
139 static uns water_amount = 0;
141 static const char * teapot_temperature_parser(char * in, void * ptr) {
142 struct teapot_temperature * temp = ptr;
144 const char * err = str_to_int(&temp->value, in, &next, 0);
147 if (!strcmp("C", next))
148 temp->scale = TEMP_CELSIUS;
149 else if (!strcmp("F", next))
150 temp->scale = TEMP_FAHRENHEIT;
151 else if (!strcmp("K", next))
152 temp->scale = TEMP_KELVIN;
153 else if (!strcmp("R", next))
154 temp->scale = TEMP_RANKINE;
155 else if (!strcmp("Re", next))
156 temp->scale = TEMP_REAUMUR;
158 fprintf(stderr, "Unknown scale: %s\n", next);
161 return next + strlen(next);
164 static void teapot_temperature_dumper(struct fastbuf * fb, void * ptr) {
165 struct teapot_temperature * temp = ptr;
166 bprintf(fb, "%d%s", temp->value, temp_scale_str[temp->scale]);
169 static struct cf_user_type teapot_temperature_t = {
170 .size = 2*sizeof(int),
171 .name = "teapot_temperature_t",
172 .parser = (cf_parser1*) teapot_temperature_parser,
173 .dumper = (cf_dumper1*) teapot_temperature_dumper
176 static struct opt_section water_options = {
178 OPT_UNS('w', "water", water_amount, OPT_REQUIRED | OPT_REQUIRED_VALUE, "Amount of water (in mls)"),
179 OPT_BOOL('G', "with-gas", with_gas, OPT_NO_VALUE, "Use water with gas"),
184 static struct opt_section help = {
186 OPT_HELP("A simple tea boiling console."),
187 OPT_HELP("Usage: teapot [options] name-of-the-tea"),
188 OPT_HELP("Black, green or white tea supported as well as fruit or herbal tea."),
189 OPT_HELP("You may specify more kinds of tea, all of them will be boiled for you, in the given order."),
191 OPT_HELP("Options:"),
193 OPT_CALL('V', "version", show_version, OPT_NO_VALUE, "Show the version"),
195 OPT_BOOL('e', "english-style", english, 0, "English style (with milk)"),
196 OPT_UNS('s', "sugar", sugar, OPT_REQUIRED_VALUE, "Amount of sugar (in teaspoons)"),
197 OPT_SWITCH(0, "standard-set", set, TEAPOT_STANDARD, 0, "Standard teapot"),
198 OPT_SWITCH('x', "exclusive-set", set, TEAPOT_EXCLUSIVE, 0, "Exclusive teapot"),
199 OPT_SWITCH('g', "glass-set", set, TEAPOT_GLASS, 0, "Transparent glass teapot"),
200 OPT_SWITCH('h', "hands", set, TEAPOT_HANDS, 0, "Use user's hands as a teapot (a bit dangerous)"),
201 OPT_USER('t', "temperature", temperature, teapot_temperature_t, OPT_REQUIRED_VALUE, "Wanted final temperature of the tea to be served"),
202 OPT_HELP2("", "Supported scales: Celsius [60C], Fahrenheit [140F],"),
203 OPT_HELP2("", " Kelvin [350K], Rankine [600R] and Reaumur [50Re]"),
204 OPT_HELP2("", "Only integer values allowed."),
205 OPT_INC('v', "verbose", verbose, 0, "Verbose (the more -v, the more verbose)"),
206 OPT_INC('q', "quiet", verbose, OPT_DECREMENT, "Quiet (the more -q, the more quiet)"),
207 OPT_UNS('b', "black-magic", black_magic, 0, "Use black magic to make the tea extraordinary delicious"),
208 OPT_BOOL('p', "pray", pray, 0, "Pray before boiling"),
210 OPT_HELP("Water options:"),
211 OPT_SECTION(water_options),
216 static void boil_tea(const char * name) {
217 printf("Boiling a tea: %s\n", name);
220 int main(int argc, char ** argv)
226 teas_num = opt_parse(argv, &teas);
228 for (int i=0; i<teas_num; i++)
231 printf("Everything OK. Bye.\n");