config_file.l: Instruct flex to create a reentrant scanner.
[lopsub.git] / lopsubex.c
1 /*
2 * Written 2016 by Andre Noll <maan@tuebingen.mpg.de>
3 *
4 * Public domain, no copyright claims.
5 */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <inttypes.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <unistd.h>
13 #include <stdbool.h>
14
15 #include "lopsub.h"
16 #include "lopsubex.lsg.h"
17
18 typedef int (*example_handler_t)(struct lls_parse_result *);
19
20 struct local_command_info {
21 example_handler_t handler;
22 };
23
24 #define EXPORT_CMD(_cmd) \
25 const struct local_command_info lsg_lopsubex_com_ ## _cmd ## _user_data = { \
26 .handler = com_ ## _cmd \
27 };
28
29 #define CMD_PTR(_cmd) lls_cmd(LSG_LOPSUBEX_CMD_ ## _cmd, lopsubex_suite)
30 #define OPT_PTR(_cmd, _opt) \
31 lls_opt(LSG_LOPSUBEX_ ## _cmd ## _OPT_ ## _opt, CMD_PTR(_cmd))
32
33 #define OPT_RESULT(_cmd, _opt, _lpr) \
34 lls_opt_result(LSG_LOPSUBEX_ ## _cmd ## _OPT_ ## _opt, _lpr)
35
36 static void print_available_commands(void)
37 {
38 const struct lls_command *cmd;
39 int i;
40 printf("Available subcommands:\n");
41 for (i = 1; (cmd = lls_cmd(i, lopsubex_suite)); i++) {
42 const char *name = lls_command_name(cmd);
43 const char *purpose = lls_purpose(cmd);
44 printf("%-20s%s\n", name, purpose);
45 }
46 }
47
48 static const struct lls_command *lookup_subcmd_or_die(const char *str)
49 {
50 char *errctx;
51 int ret = lls_lookup_subcmd(str, lopsubex_suite, &errctx);
52
53 if (ret < 0) {
54 if (errctx)
55 printf("%s: ", errctx);
56 printf("%s\n", lls_strerror(-ret));
57 print_available_commands();
58 exit(EXIT_FAILURE);
59 }
60 return lls_cmd(ret, lopsubex_suite);
61 }
62
63 static int com_flag(struct lls_parse_result *lpr)
64 {
65 const struct lls_opt_result *r = OPT_RESULT(FLAG, SIMPLE, lpr);
66
67 /* flag count is obtained with lls_given() */
68 printf("--simple is given %u times\n", lls_opt_given(r));
69
70 r = OPT_RESULT(FLAG, SQRT4, lpr);
71 printf("--sqrt4 (aka -2) is given %u times\n", lls_opt_given(r));
72 return 0;
73 }
74 EXPORT_CMD(flag)
75
76 static int com_int_param(struct lls_parse_result *lpr)
77 {
78 const struct lls_opt_result *r_r = OPT_RESULT(INT_PARAM, ROTATE, lpr);
79 printf("rotating by %d degrees\n", lls_int32_val(0, r_r));
80 return 0;
81 }
82 EXPORT_CMD(int_param)
83
84 static int com_multiple(struct lls_parse_result *lpr)
85 {
86 const struct lls_opt_result *r;
87 int i;
88 unsigned given;
89
90 r = OPT_RESULT(MULTIPLE, VERBOSE, lpr);
91 printf("--verbose is given %d times\n", lls_opt_given(r));
92 r = OPT_RESULT(MULTIPLE, INPUT_FILE, lpr);
93 given = lls_opt_given(r);
94 printf("--input-file is given %d times\n", lls_opt_given(r));
95 for (i = 0; i < given; i++)
96 printf("--input-file val #%d: %s\n", i, lls_string_val(i, r));
97 r = OPT_RESULT(MULTIPLE, OUTPUT_FILE, lpr);
98 printf("--output-file is given %d times\n", lls_opt_given(r));
99 printf("--output-file val: %s\n", lls_string_val(0, r));
100 return 0;
101 }
102 EXPORT_CMD(multiple)
103
104 static int com_custom_synopsis(struct lls_parse_result *lpr)
105 {
106 const struct lls_command *cmd = CMD_PTR(CUSTOM_SYNOPSIS);
107 char *long_help = lls_long_help(cmd);
108 printf("%s\n", long_help);
109 free(long_help);
110 return 0;
111 }
112 EXPORT_CMD(custom_synopsis)
113
114 static void fruit_salad(struct lls_parse_result *lpr)
115 {
116 const struct lls_opt_result *r_f = OPT_RESULT(SERIALIZE, FRUIT, lpr);
117 const struct lls_opt_result *r_a = OPT_RESULT(SERIALIZE, AMOUNT, lpr);
118 const struct lls_opt_result *r_s = OPT_RESULT(SERIALIZE, SUGAR, lpr);
119 const struct lls_opt_result *r_c = OPT_RESULT(SERIALIZE, CONTAINER, lpr);
120 int i, num_vals;
121
122 printf("Put %d gramms of fruits (", lls_uint32_val(0, r_a));
123 num_vals = lls_opt_given(r_f) > 0? lls_opt_given(r_f) : 1;
124 for (i = 0; i < num_vals; i++)
125 printf("%s%s", lls_string_val(i, r_f),
126 i == num_vals - 1? "" : ", ");
127 printf(") in a %s, ", lls_string_val(0, r_c));
128 if (lls_opt_given(r_s))
129 printf("add sugar, ");
130 printf("and serve cold.\n");
131 }
132
133 static int com_serialize(struct lls_parse_result *lpr)
134 {
135 const struct lls_command *cmd = CMD_PTR(SERIALIZE);
136 char *buf = NULL;
137 int ret;
138 size_t nbytes;
139 struct lls_parse_result *dlpr; /* deserialized */
140
141 fruit_salad(lpr);
142 ret = lls_serialize_parse_result(lpr, cmd, &buf, &nbytes);
143 if (ret < 0)
144 return ret;
145 printf("serialized parse result into %zu byte buffer\n", nbytes);
146 ret = lls_deserialize_parse_result(buf, cmd, &dlpr);
147 free(buf);
148 if (ret < 0)
149 return ret;
150 printf("successfully deserialized parse result\n");
151 fruit_salad(dlpr);
152 lls_free_parse_result(dlpr, cmd);
153 return 1;
154 }
155 EXPORT_CMD(serialize)
156
157 static int com_non_ascii(struct lls_parse_result *lpr)
158 {
159 const struct lls_opt_result *r_c = OPT_RESULT(NON_ASCII, CITY, lpr);
160 const char *city = lls_string_val(0, r_c);
161
162 if (strcmp(city, "Göttingen"))
163 printf("I don't know anything about %s\n", city);
164 else
165 printf("One of the most famous citicens of Göttingen was\n"
166 "the mathematician Carl Friedrich Gauß.\n");
167 exit(EXIT_SUCCESS);
168 }
169 EXPORT_CMD(non_ascii)
170
171 static int com_enum(struct lls_parse_result *lpr)
172 {
173 const struct lls_option *o_c = OPT_PTR(ENUM, COLOR);
174 const struct lls_opt_result *r_c = OPT_RESULT(ENUM, COLOR, lpr);
175 bool c_given = lls_opt_given(r_c);
176 uint32_t num;
177 const char *color;
178
179 num = lls_uint32_val(0, r_c);
180 color = lls_enum_string_val(num, o_c);
181 printf("%s value: #%d: %s\n", c_given? "good" : "default", num, color);
182 printf("Band names containing '%s'\n", color);
183 switch (num) {
184 case COLOR_RED:
185 printf("Red Snapper\n");
186 printf("Red Lorry Yellow Lorry\n");
187 break;
188 case COLOR_GREEN:
189 printf("Green Day\n");
190 printf("Green Jelly\n");
191 break;
192 case COLOR_BLUE:
193 printf("Blue Cheer\n");
194 printf("Blue Öyster Cult\n");
195 break;
196 default:
197 printf("Nothing appropriate\n");
198 }
199 if (!c_given) {
200 printf("Available colors:\n");
201 for (num = 0; num < LSG_NUM_LOPSUBEX_ENUM_COLOR_VALUES; num++)
202 printf("color #%d: %s\n", num,
203 lls_enum_string_val(num, o_c));
204 }
205 return 1;
206 }
207 EXPORT_CMD(enum)
208
209 static int com_quotes(struct lls_parse_result *lpr)
210 {
211 const struct lls_opt_result *r_s = OPT_RESULT(QUOTES, CHARS, lpr);
212 const char *val= lls_string_val(0, r_s);
213
214 printf("Special characters: %s\n", val);
215 return 0;
216 }
217 EXPORT_CMD(quotes)
218
219 static int com_help(struct lls_parse_result *lpr)
220 {
221 const struct lls_command *cmd = CMD_PTR(HELP);
222 const struct lls_opt_result *r_l = OPT_RESULT(HELP, LONG, lpr);
223 char *txt;
224 int ret;
225
226 ret = lls_check_arg_count(lpr, 0, 1, NULL);
227 if (ret < 0)
228 return ret;
229 if (lls_num_inputs(lpr) > 0)
230 cmd = lookup_subcmd_or_die(lls_input(0, lpr));
231 if (lls_opt_given(r_l))
232 txt = lls_long_help(cmd);
233 else
234 txt = lls_short_help(cmd);
235 printf("%s", txt);
236 free(txt);
237 return 0;
238 }
239 EXPORT_CMD(help)
240
241 static int com_default_val(struct lls_parse_result *lpr)
242 {
243 const struct lls_opt_result *r;
244 uint32_t val1, val2;
245 const char *txt1, *txt2;
246
247 r = OPT_RESULT(DEFAULT_VAL, WIDTH, lpr);
248 val1 = lls_uint32_val(0, r);
249 r = OPT_RESULT(DEFAULT_VAL, HEIGHT, lpr);
250 val2 = lls_uint32_val(0, r);
251 printf("geometry: %" PRIu32 "x%" PRIu32 "\n", val1, val2);
252
253 r = OPT_RESULT(DEFAULT_VAL, TOWN, lpr);
254 txt1 = lls_string_val(0, r);
255 r = OPT_RESULT(DEFAULT_VAL, STREET, lpr);
256 txt2 = lls_string_val(0, r);
257 printf("address: %s, %s\n", txt2, txt1);
258
259 r = OPT_RESULT(DEFAULT_VAL, TIME, lpr);
260 val1 = lls_uint32_val(0, r);
261 txt1 = lls_enum_string_val(val1, OPT_PTR(DEFAULT_VAL, TIME));
262 r = OPT_RESULT(DEFAULT_VAL, WEEKDAY, lpr);
263 val2 = lls_uint32_val(0, r);
264 txt2 = lls_enum_string_val(val2, OPT_PTR(DEFAULT_VAL, WEEKDAY));
265 printf("when: %s %s\n", txt2, txt1);
266
267 return 0;
268 }
269 EXPORT_CMD(default_val)
270
271 static int com_optional_arg(struct lls_parse_result *lpr)
272 {
273 const struct lls_opt_result *r;
274
275 r = OPT_RESULT(OPTIONAL_ARG, WIDTH, lpr);
276
277 printf("width: %u (%u times given)\n", lls_uint32_val(0, r),
278 lls_opt_given(r));
279 r = OPT_RESULT(OPTIONAL_ARG, HEIGHT, lpr);
280 printf("height: %u (%u times given)\n", lls_uint32_val(0, r),
281 lls_opt_given(r));
282 printf("%u non-option arguments\n", lls_num_inputs(lpr));
283 return 0;
284 }
285 EXPORT_CMD(optional_arg)
286
287 /* stringify the first argument (author information) */
288 #define LOPSUBEX_AUX_INFO(_author, _perms) #_author,
289 static const char * const authors[] = {LSG_LOPSUBEX_AUX_INFOS};
290 #undef LOPSUBEX_AUX_INFO
291 #define LOPSUBEX_AUX_INFO(_author, _perms) _perms,
292 static const mode_t permissions[] = {LSG_LOPSUBEX_AUX_INFOS};
293 static int com_aux_info(struct lls_parse_result *lpr)
294 {
295 const struct lls_command *cmd;
296 int i;
297
298 for (i = 0; (cmd = lls_cmd(i, lopsubex_suite)); i++) {
299 const char *name = lls_command_name(cmd);
300 printf("%s: ", name);
301 printf("author: %s, permissions: %o\n", authors[i],
302 permissions[i]);
303 }
304 return 0;
305 }
306 EXPORT_CMD(aux_info)
307
308 int main(int argc, char **argv)
309 {
310 int ret;
311 const struct lls_command *cmd;
312 struct lls_parse_result *lpr;
313 const struct local_command_info *lci;
314 char *errctx;
315
316 if (argc <= 1) {
317 printf("Usage: %s <subcommand> [options]\n", argv[0]);
318 print_available_commands();
319 exit(EXIT_FAILURE);
320 }
321 cmd = lookup_subcmd_or_die(argv[1]);
322 ret = lls_parse(argc - 1, argv + 1, cmd, &lpr, &errctx);
323 if (ret < 0) {
324 printf("%s: %s\n", errctx, lls_strerror(-ret));
325 free(errctx);
326 exit(EXIT_FAILURE);
327 }
328 lci = lls_user_data(cmd);
329 ret = lci->handler(lpr);
330 lls_free_parse_result(lpr, cmd);
331 exit(ret < 0? EXIT_FAILURE : EXIT_SUCCESS);
332 }