71c987d6a6e276446f135611ca22ac919494305d
[platform/upstream/isl.git] / isl_arg.c
1 /*
2  * Copyright 2008-2009 Katholieke Universiteit Leuven
3  *
4  * Use of this software is governed by the GNU LGPLv2.1 license
5  *
6  * Written by Sven Verdoolaege, K.U.Leuven, Departement
7  * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include "isl_arg.h"
15 #include <isl_ctx.h>
16
17 static void set_default_choice(struct isl_arg *arg, void *opt)
18 {
19         *(unsigned *)(((char *)opt) + arg->offset) = arg->u.choice.default_value;
20 }
21
22 static void set_default_bool(struct isl_arg *arg, void *opt)
23 {
24         *(unsigned *)(((char *)opt) + arg->offset) = arg->u.b.default_value;
25 }
26
27 static void set_default_child(struct isl_arg *arg, void *opt)
28 {
29         void *child = calloc(1, arg->u.child.size);
30
31         if (child)
32                 isl_arg_set_defaults(arg->u.child.child, child);
33
34         *(void **)(((char *)opt) + arg->offset) = child;
35 }
36
37 void isl_arg_set_defaults(struct isl_arg *arg, void *opt)
38 {
39         int i;
40
41         for (i = 0; arg[i].type != isl_arg_end; ++i) {
42                 switch (arg[i].type) {
43                 case isl_arg_choice:
44                         set_default_choice(&arg[i], opt);
45                         break;
46                 case isl_arg_bool:
47                         set_default_bool(&arg[i], opt);
48                         break;
49                 case isl_arg_child:
50                         set_default_child(&arg[i], opt);
51                         break;
52                 }
53         }
54 }
55
56 static int print_arg_help(struct isl_arg *decl, const char *prefix)
57 {
58         int len = 0;
59
60         if (decl->short_name)
61                 printf("  -%c, --", decl->short_name);
62         else
63                 printf("      --");
64         len += 8;
65
66         if (prefix) {
67                 printf("%s-", prefix);
68                 len += strlen(prefix) + 1;
69         }
70         printf("%s", decl->long_name);
71         len += strlen(decl->long_name);
72
73         return len;
74 }
75
76 const void *isl_memrchr(const void *s, int c, size_t n)
77 {
78         const char *p = s;
79         while (n-- > 0)
80                 if (p[n] == c)
81                         return s + n;
82         return NULL;
83 }
84
85 static int print_help_msg(struct isl_arg *decl, int pos)
86 {
87         int len;
88         const char *s;
89
90         if (!decl->help_msg)
91                 return pos;
92
93         if (pos >= 29)
94                 printf("\n%30s", "");
95         else
96                 printf("%*s", 30 - pos, "");
97
98         s = decl->help_msg;
99         len = strlen(s);
100         while (len > 45) {
101                 const char *space = isl_memrchr(s, ' ', 45);
102                 int l;
103
104                 if (!space)
105                         space = strchr(s + 45, ' ');
106                 if (!space)
107                         break;
108                 l = space - s;
109                 printf("%.*s", l, s);
110                 s = space + 1;
111                 len -= l + 1;
112                 printf("\n%30s", "");
113         }
114
115         printf("%s", s);
116         return len;
117 }
118
119 static void print_default_choice(struct isl_arg *decl, int pos)
120 {
121         int i;
122         const char *default_prefix = "[default: ";
123         const char *default_suffix = "]";
124         const char *s = "none";
125         int len = strlen(default_prefix) + strlen(s) + strlen(default_suffix);
126
127         for (i = 0; decl->u.choice.choice[i].name; ++i)
128                 if (decl->u.choice.choice[i].value == decl->u.choice.default_value) {
129                         s = decl->u.choice.choice[i].name;
130                         break;
131                 }
132
133         if (!decl->help_msg) {
134                 if (pos >= 29)
135                         printf("\n%30s", "");
136                 else
137                         printf("%*s", 30 - pos, "");
138                 pos = 0;
139         }
140
141         if (pos && pos + len >= 48)
142                 printf("\n%30s", "");
143         else
144                 printf(" ");
145         printf("%s%s%s", default_prefix, s, default_suffix);
146 }
147
148 static void print_choice_help(struct isl_arg *decl, const char *prefix)
149 {
150         int i;
151         int pos;
152
153         pos = print_arg_help(decl, prefix);
154         printf("=");
155         pos++;
156
157         for (i = 0; decl->u.choice.choice[i].name; ++i) {
158                 if (i) {
159                         printf("|");
160                         pos++;
161                 }
162                 printf("%s", decl->u.choice.choice[i].name);
163                 pos += strlen(decl->u.choice.choice[i].name);
164         }
165
166         pos = print_help_msg(decl, pos);
167         print_default_choice(decl, pos);
168
169         printf("\n");
170 }
171
172 static void print_bool_help(struct isl_arg *decl, const char *prefix)
173 {
174         int pos;
175         pos = print_arg_help(decl, prefix);
176         print_help_msg(decl, pos);
177         printf("\n");
178 }
179
180 static void print_help(struct isl_arg *arg, const char *prefix)
181 {
182         int i;
183
184         for (i = 0; arg[i].type != isl_arg_end; ++i) {
185                 switch (arg[i].type) {
186                 case isl_arg_choice:
187                         print_choice_help(&arg[i], prefix);
188                         break;
189                 case isl_arg_bool:
190                         print_bool_help(&arg[i], prefix);
191                         break;
192                 }
193         }
194
195         for (i = 0; arg[i].type != isl_arg_end; ++i) {
196                 if (arg[i].type != isl_arg_child)
197                         continue;
198
199                 printf("\n");
200                 print_help(arg[i].u.child.child, arg[i].long_name);
201         }
202 }
203
204 static void print_help_and_exit(struct isl_arg *arg, const char *prog)
205 {
206         const char *slash;
207
208         slash = strrchr(prog, '/');
209         if (slash)
210                 printf("Usage: %s [OPTION...]\n\n", slash + 1);
211
212         print_help(arg, NULL);
213
214         exit(0);
215 }
216
217 static int parse_choice_option(struct isl_arg *decl, const char *arg,
218         const char *prefix, void *opt)
219 {
220         int i;
221         const char *equal;
222         const char *name;
223
224         if (strncmp(arg, "--", 2))
225                 return 0;
226
227         name = arg + 2;
228         equal = strchr(name, '=');
229         if (!equal)
230                 return 0;
231
232         if (prefix) {
233                 size_t prefix_len = strlen(prefix);
234                 if (strncmp(name, prefix, prefix_len) == 0 &&
235                     name[prefix_len] == '-')
236                         name += prefix_len + 1;
237         }
238
239         if (strncmp(name, decl->long_name, equal - name))
240                 return 0;
241
242         for (i = 0; decl->u.choice.choice[i].name; ++i) {
243                 if (strcmp(equal + 1, decl->u.choice.choice[i].name))
244                         continue;
245
246                 *(unsigned *)(((char *)opt) + decl->offset) =
247                         decl->u.choice.choice[i].value;
248
249                 return 1;
250         }
251
252         return 0;
253 }
254
255 static int parse_bool_option(struct isl_arg *decl, const char *arg, void *opt)
256 {
257         int i;
258
259         if ((arg[0] == '-' && arg[1] == decl->short_name && arg[2] == '\0') ||
260             (strncmp(arg, "--", 2) == 0 &&
261              strcmp(arg + 2, decl->long_name) == 0)) {
262                 *(unsigned *)(((char *)opt) + decl->offset) = 1;
263
264                 return 1;
265         }
266
267         return 0;
268 }
269
270 static int parse_option(struct isl_arg *decl, const char *arg,
271         const char *prefix, void *opt);
272
273 static int parse_child_option(struct isl_arg *decl, const char *arg, void *opt)
274 {
275         return parse_option(decl->u.child.child, arg, decl->long_name,
276                                 *(void **)(((char *)opt) + decl->offset));
277 }
278
279 static int parse_option(struct isl_arg *decl, const char *arg,
280         const char *prefix, void *opt)
281 {
282         int i;
283
284         for (i = 0; decl[i].type != isl_arg_end; ++i) {
285                 switch (decl[i].type) {
286                 case isl_arg_choice:
287                         if (parse_choice_option(&decl[i], arg, prefix, opt))
288                                 return 1;
289                         break;
290                 case isl_arg_bool:
291                         if (parse_bool_option(&decl[i], arg, opt))
292                                 return 1;
293                         break;
294                 case isl_arg_child:
295                         if (parse_child_option(&decl[i], arg, opt))
296                                 return 1;
297                         break;
298                 }
299         }
300
301         return 0;
302 }
303
304 static int drop_argument(int argc, char **argv, int drop)
305 {
306         for (; drop < argc; ++drop)
307                 argv[drop] = argv[drop + 1];
308
309         return argc - 1;
310 }
311
312 int isl_arg_parse(struct isl_arg *arg, int argc, char **argv, void *opt,
313         unsigned flags)
314 {
315         int skip = 0;
316         int i;
317
318         for (i = 1; i < argc; ++i) {
319                 if (strcmp(argv[i], "--help") == 0)
320                         print_help_and_exit(arg, argv[0]);
321         }
322
323         while (argc > 1 + skip) {
324                 if (parse_option(arg, argv[1 + skip], NULL, opt))
325                         argc = drop_argument(argc, argv, 1 + skip);
326                 else if (ISL_FL_ISSET(flags, ISL_ARG_ALL)) {
327                         fprintf(stderr, "unrecognized option: %s\n",
328                                         argv[1 + skip]);
329                         exit(-1);
330                 } else
331                         ++skip;
332         }
333
334         return argc;
335 }