build: Honor the Filesystem Hierarchy Standard.
[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 }