nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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 struct isl_arg help_arg[] = { |
||
18 | ISL_ARG_PHANTOM_BOOL('h', "help", NULL, "print this help, then exit") |
||
19 | }; |
||
20 | |||
21 | static void set_default_choice(struct isl_arg *arg, void *opt) |
||
22 | { |
||
23 | *(unsigned *)(((char *)opt) + arg->offset) = arg->u.choice.default_value; |
||
24 | } |
||
25 | |||
26 | static void set_default_flags(struct isl_arg *arg, void *opt) |
||
27 | { |
||
28 | *(unsigned *)(((char *)opt) + arg->offset) = arg->u.flags.default_value; |
||
29 | } |
||
30 | |||
31 | static void set_default_bool(struct isl_arg *arg, void *opt) |
||
32 | { |
||
33 | if (arg->offset == (size_t) -1) |
||
34 | return; |
||
35 | *(unsigned *)(((char *)opt) + arg->offset) = arg->u.b.default_value; |
||
36 | } |
||
37 | |||
38 | static void set_default_child(struct isl_arg *arg, void *opt) |
||
39 | { |
||
40 | void *child; |
||
41 | |||
42 | if (arg->offset == (size_t) -1) |
||
43 | child = opt; |
||
44 | else { |
||
45 | child = calloc(1, arg->u.child.child->options_size); |
||
46 | *(void **)(((char *)opt) + arg->offset) = child; |
||
47 | } |
||
48 | |||
49 | if (child) |
||
50 | isl_args_set_defaults(arg->u.child.child, child); |
||
51 | } |
||
52 | |||
53 | static void set_default_user(struct isl_arg *arg, void *opt) |
||
54 | { |
||
55 | arg->u.user.init(((char *)opt) + arg->offset); |
||
56 | } |
||
57 | |||
58 | static void set_default_int(struct isl_arg *arg, void *opt) |
||
59 | { |
||
60 | *(int *)(((char *)opt) + arg->offset) = arg->u.i.default_value; |
||
61 | } |
||
62 | |||
63 | static void set_default_long(struct isl_arg *arg, void *opt) |
||
64 | { |
||
65 | *(long *)(((char *)opt) + arg->offset) = arg->u.l.default_value; |
||
66 | } |
||
67 | |||
68 | static void set_default_ulong(struct isl_arg *arg, void *opt) |
||
69 | { |
||
70 | *(unsigned long *)(((char *)opt) + arg->offset) = arg->u.ul.default_value; |
||
71 | } |
||
72 | |||
73 | static void set_default_str(struct isl_arg *arg, void *opt) |
||
74 | { |
||
75 | const char *str = NULL; |
||
76 | if (arg->u.str.default_value) |
||
77 | str = strdup(arg->u.str.default_value); |
||
78 | *(const char **)(((char *)opt) + arg->offset) = str; |
||
79 | } |
||
80 | |||
81 | static void set_default_str_list(struct isl_arg *arg, void *opt) |
||
82 | { |
||
83 | *(const char ***)(((char *) opt) + arg->offset) = NULL; |
||
84 | *(int *)(((char *) opt) + arg->u.str_list.offset_n) = 0; |
||
85 | } |
||
86 | |||
87 | void isl_args_set_defaults(struct isl_args *args, void *opt) |
||
88 | { |
||
89 | int i; |
||
90 | |||
91 | for (i = 0; args->args[i].type != isl_arg_end; ++i) { |
||
92 | switch (args->args[i].type) { |
||
93 | case isl_arg_choice: |
||
94 | set_default_choice(&args->args[i], opt); |
||
95 | break; |
||
96 | case isl_arg_flags: |
||
97 | set_default_flags(&args->args[i], opt); |
||
98 | break; |
||
99 | case isl_arg_bool: |
||
100 | set_default_bool(&args->args[i], opt); |
||
101 | break; |
||
102 | case isl_arg_child: |
||
103 | set_default_child(&args->args[i], opt); |
||
104 | break; |
||
105 | case isl_arg_user: |
||
106 | set_default_user(&args->args[i], opt); |
||
107 | break; |
||
108 | case isl_arg_int: |
||
109 | set_default_int(&args->args[i], opt); |
||
110 | break; |
||
111 | case isl_arg_long: |
||
112 | set_default_long(&args->args[i], opt); |
||
113 | break; |
||
114 | case isl_arg_ulong: |
||
115 | set_default_ulong(&args->args[i], opt); |
||
116 | break; |
||
117 | case isl_arg_arg: |
||
118 | case isl_arg_str: |
||
119 | set_default_str(&args->args[i], opt); |
||
120 | break; |
||
121 | case isl_arg_str_list: |
||
122 | set_default_str_list(&args->args[i], opt); |
||
123 | break; |
||
124 | case isl_arg_alias: |
||
125 | case isl_arg_footer: |
||
126 | case isl_arg_version: |
||
127 | case isl_arg_end: |
||
128 | break; |
||
129 | } |
||
130 | } |
||
131 | } |
||
132 | |||
133 | static void free_str_list(struct isl_arg *arg, void *opt) |
||
134 | { |
||
135 | int i; |
||
136 | int n = *(int *)(((char *) opt) + arg->u.str_list.offset_n); |
||
137 | char **list = *(char ***)(((char *) opt) + arg->offset); |
||
138 | |||
139 | for (i = 0; i < n; ++i) |
||
140 | free(list[i]); |
||
141 | free(list); |
||
142 | } |
||
143 | |||
144 | static void free_args(struct isl_arg *arg, void *opt) |
||
145 | { |
||
146 | int i; |
||
147 | |||
148 | for (i = 0; arg[i].type != isl_arg_end; ++i) { |
||
149 | switch (arg[i].type) { |
||
150 | case isl_arg_child: |
||
151 | if (arg[i].offset == (size_t) -1) |
||
152 | free_args(arg[i].u.child.child->args, opt); |
||
153 | else |
||
154 | isl_args_free(arg[i].u.child.child, |
||
155 | *(void **)(((char *)opt) + arg[i].offset)); |
||
156 | break; |
||
157 | case isl_arg_arg: |
||
158 | case isl_arg_str: |
||
159 | free(*(char **)(((char *)opt) + arg[i].offset)); |
||
160 | break; |
||
161 | case isl_arg_str_list: |
||
162 | free_str_list(&arg[i], opt); |
||
163 | break; |
||
164 | case isl_arg_user: |
||
165 | if (arg[i].u.user.clear) |
||
166 | arg[i].u.user.clear(((char *)opt) + arg[i].offset); |
||
167 | break; |
||
168 | case isl_arg_alias: |
||
169 | case isl_arg_bool: |
||
170 | case isl_arg_choice: |
||
171 | case isl_arg_flags: |
||
172 | case isl_arg_int: |
||
173 | case isl_arg_long: |
||
174 | case isl_arg_ulong: |
||
175 | case isl_arg_version: |
||
176 | case isl_arg_footer: |
||
177 | case isl_arg_end: |
||
178 | break; |
||
179 | } |
||
180 | } |
||
181 | } |
||
182 | |||
183 | void isl_args_free(struct isl_args *args, void *opt) |
||
184 | { |
||
185 | if (!opt) |
||
186 | return; |
||
187 | |||
188 | free_args(args->args, opt); |
||
189 | |||
190 | free(opt); |
||
191 | } |
||
192 | |||
193 | static int print_arg_help(struct isl_arg *decl, const char *prefix, int no) |
||
194 | { |
||
195 | int len = 0; |
||
196 | |||
197 | if (!decl->long_name) { |
||
198 | printf(" -%c", decl->short_name); |
||
199 | return 4; |
||
200 | } |
||
201 | |||
202 | if (decl->short_name) { |
||
203 | printf(" -%c, --", decl->short_name); |
||
204 | len += 8; |
||
205 | } else if (decl->flags & ISL_ARG_SINGLE_DASH) { |
||
206 | printf(" -"); |
||
207 | len += 3; |
||
208 | } else { |
||
209 | printf(" --"); |
||
210 | len += 8; |
||
211 | } |
||
212 | |||
213 | if (prefix) { |
||
214 | printf("%s-", prefix); |
||
215 | len += strlen(prefix) + 1; |
||
216 | } |
||
217 | if (no) { |
||
218 | printf("no-"); |
||
219 | len += 3; |
||
220 | } |
||
221 | printf("%s", decl->long_name); |
||
222 | len += strlen(decl->long_name); |
||
223 | |||
224 | while ((++decl)->type == isl_arg_alias) { |
||
225 | printf(", --"); |
||
226 | len += 4; |
||
227 | if (no) { |
||
228 | printf("no-"); |
||
229 | len += 3; |
||
230 | } |
||
231 | printf("%s", decl->long_name); |
||
232 | len += strlen(decl->long_name); |
||
233 | } |
||
234 | |||
235 | return len; |
||
236 | } |
||
237 | |||
238 | const void *isl_memrchr(const void *s, int c, size_t n) |
||
239 | { |
||
240 | const char *p = s; |
||
241 | while (n-- > 0) |
||
242 | if (p[n] == c) |
||
243 | return p + n; |
||
244 | return NULL; |
||
245 | } |
||
246 | |||
247 | static int wrap_msg(const char *s, int indent, int pos) |
||
248 | { |
||
249 | int len; |
||
250 | int wrap_len = 75 - indent; |
||
251 | |||
252 | if (pos + 1 >= indent) |
||
253 | printf("\n%*s", indent, ""); |
||
254 | else |
||
255 | printf("%*s", indent - pos, ""); |
||
256 | |||
257 | len = strlen(s); |
||
258 | while (len > wrap_len) { |
||
259 | const char *space = isl_memrchr(s, ' ', wrap_len); |
||
260 | int l; |
||
261 | |||
262 | if (!space) |
||
263 | space = strchr(s + wrap_len, ' '); |
||
264 | if (!space) |
||
265 | break; |
||
266 | l = space - s; |
||
267 | printf("%.*s", l, s); |
||
268 | s = space + 1; |
||
269 | len -= l + 1; |
||
270 | printf("\n%*s", indent, ""); |
||
271 | } |
||
272 | |||
273 | printf("%s", s); |
||
274 | return len; |
||
275 | } |
||
276 | |||
277 | static int print_help_msg(struct isl_arg *decl, int pos) |
||
278 | { |
||
279 | if (!decl->help_msg) |
||
280 | return pos; |
||
281 | |||
282 | return wrap_msg(decl->help_msg, 30, pos); |
||
283 | } |
||
284 | |||
285 | static void print_default(struct isl_arg *decl, const char *def, int pos) |
||
286 | { |
||
287 | const char *default_prefix = "[default: "; |
||
288 | const char *default_suffix = "]"; |
||
289 | int len; |
||
290 | |||
291 | len = strlen(default_prefix) + strlen(def) + strlen(default_suffix); |
||
292 | |||
293 | if (!decl->help_msg) { |
||
294 | if (pos >= 29) |
||
295 | printf("\n%30s", ""); |
||
296 | else |
||
297 | printf("%*s", 30 - pos, ""); |
||
298 | pos = 0; |
||
299 | } else { |
||
300 | if (pos + len >= 48) |
||
301 | printf("\n%30s", ""); |
||
302 | else |
||
303 | printf(" "); |
||
304 | } |
||
305 | printf("%s%s%s", default_prefix, def, default_suffix); |
||
306 | } |
||
307 | |||
308 | static void print_default_choice(struct isl_arg *decl, void *opt, int pos) |
||
309 | { |
||
310 | int i; |
||
311 | const char *s = "none"; |
||
312 | unsigned *p; |
||
313 | |||
314 | p = (unsigned *)(((char *) opt) + decl->offset); |
||
315 | for (i = 0; decl->u.choice.choice[i].name; ++i) |
||
316 | if (decl->u.choice.choice[i].value == *p) { |
||
317 | s = decl->u.choice.choice[i].name; |
||
318 | break; |
||
319 | } |
||
320 | |||
321 | print_default(decl, s, pos); |
||
322 | } |
||
323 | |||
324 | static void print_choice_help(struct isl_arg *decl, const char *prefix, |
||
325 | void *opt) |
||
326 | { |
||
327 | int i; |
||
328 | int pos; |
||
329 | |||
330 | pos = print_arg_help(decl, prefix, 0); |
||
331 | printf("="); |
||
332 | pos++; |
||
333 | |||
334 | for (i = 0; decl->u.choice.choice[i].name; ++i) { |
||
335 | if (i) { |
||
336 | printf("|"); |
||
337 | pos++; |
||
338 | } |
||
339 | printf("%s", decl->u.choice.choice[i].name); |
||
340 | pos += strlen(decl->u.choice.choice[i].name); |
||
341 | } |
||
342 | |||
343 | pos = print_help_msg(decl, pos); |
||
344 | print_default_choice(decl, opt, pos); |
||
345 | |||
346 | printf("\n"); |
||
347 | } |
||
348 | |||
349 | static void print_default_flags(struct isl_arg *decl, void *opt, int pos) |
||
350 | { |
||
351 | int i, first; |
||
352 | const char *default_prefix = "[default: "; |
||
353 | const char *default_suffix = "]"; |
||
354 | int len = strlen(default_prefix) + strlen(default_suffix); |
||
355 | unsigned *p; |
||
356 | |||
357 | p = (unsigned *)(((char *) opt) + decl->offset); |
||
358 | for (i = 0; decl->u.flags.flags[i].name; ++i) |
||
359 | if ((*p & decl->u.flags.flags[i].mask) == |
||
360 | decl->u.flags.flags[i].value) |
||
361 | len += strlen(decl->u.flags.flags[i].name); |
||
362 | |||
363 | if (!decl->help_msg) { |
||
364 | if (pos >= 29) |
||
365 | printf("\n%30s", ""); |
||
366 | else |
||
367 | printf("%*s", 30 - pos, ""); |
||
368 | pos = 0; |
||
369 | } else { |
||
370 | if (pos + len >= 48) |
||
371 | printf("\n%30s", ""); |
||
372 | else |
||
373 | printf(" "); |
||
374 | } |
||
375 | printf("%s", default_prefix); |
||
376 | |||
377 | for (first = 1, i = 0; decl->u.flags.flags[i].name; ++i) |
||
378 | if ((*p & decl->u.flags.flags[i].mask) == |
||
379 | decl->u.flags.flags[i].value) { |
||
380 | if (!first) |
||
381 | printf(","); |
||
382 | printf("%s", decl->u.flags.flags[i].name); |
||
383 | first = 0; |
||
384 | } |
||
385 | |||
386 | printf("%s", default_suffix); |
||
387 | } |
||
388 | |||
389 | static void print_flags_help(struct isl_arg *decl, const char *prefix, |
||
390 | void *opt) |
||
391 | { |
||
392 | int i, j; |
||
393 | int pos; |
||
394 | |||
395 | pos = print_arg_help(decl, prefix, 0); |
||
396 | printf("="); |
||
397 | pos++; |
||
398 | |||
399 | for (i = 0; decl->u.flags.flags[i].name; ++i) { |
||
400 | if (i) { |
||
401 | printf(","); |
||
402 | pos++; |
||
403 | } |
||
404 | for (j = i; |
||
405 | decl->u.flags.flags[j].mask == decl->u.flags.flags[i].mask; |
||
406 | ++j) { |
||
407 | if (j != i) { |
||
408 | printf("|"); |
||
409 | pos++; |
||
410 | } |
||
411 | printf("%s", decl->u.flags.flags[j].name); |
||
412 | pos += strlen(decl->u.flags.flags[j].name); |
||
413 | } |
||
414 | i = j - 1; |
||
415 | } |
||
416 | |||
417 | pos = print_help_msg(decl, pos); |
||
418 | print_default_flags(decl, opt, pos); |
||
419 | |||
420 | printf("\n"); |
||
421 | } |
||
422 | |||
423 | static void print_bool_help(struct isl_arg *decl, const char *prefix, void *opt) |
||
424 | { |
||
425 | int pos; |
||
426 | unsigned *p = opt ? (unsigned *)(((char *) opt) + decl->offset) : NULL; |
||
427 | int no = p ? *p == 1 : 0; |
||
428 | pos = print_arg_help(decl, prefix, no); |
||
429 | pos = print_help_msg(decl, pos); |
||
430 | if (decl->offset != (size_t) -1) |
||
431 | print_default(decl, no ? "yes" : "no", pos); |
||
432 | printf("\n"); |
||
433 | } |
||
434 | |||
435 | static int print_argument_name(struct isl_arg *decl, const char *name, int pos) |
||
436 | { |
||
437 | printf("%c<%s>", decl->long_name ? '=' : ' ', name); |
||
438 | return pos + 3 + strlen(name); |
||
439 | } |
||
440 | |||
441 | static void print_int_help(struct isl_arg *decl, const char *prefix, void *opt) |
||
442 | { |
||
443 | int pos; |
||
444 | char val[20]; |
||
445 | int *p = (int *)(((char *) opt) + decl->offset); |
||
446 | pos = print_arg_help(decl, prefix, 0); |
||
447 | pos = print_argument_name(decl, decl->argument_name, pos); |
||
448 | pos = print_help_msg(decl, pos); |
||
449 | snprintf(val, sizeof(val), "%d", *p); |
||
450 | print_default(decl, val, pos); |
||
451 | printf("\n"); |
||
452 | } |
||
453 | |||
454 | static void print_long_help(struct isl_arg *decl, const char *prefix, void *opt) |
||
455 | { |
||
456 | int pos; |
||
457 | long *p = (long *)(((char *) opt) + decl->offset); |
||
458 | pos = print_arg_help(decl, prefix, 0); |
||
459 | if (*p != decl->u.l.default_selected) { |
||
460 | printf("["); |
||
461 | pos++; |
||
462 | } |
||
463 | printf("=long"); |
||
464 | pos += 5; |
||
465 | if (*p != decl->u.l.default_selected) { |
||
466 | printf("]"); |
||
467 | pos++; |
||
468 | } |
||
469 | print_help_msg(decl, pos); |
||
470 | printf("\n"); |
||
471 | } |
||
472 | |||
473 | static void print_ulong_help(struct isl_arg *decl, const char *prefix) |
||
474 | { |
||
475 | int pos; |
||
476 | pos = print_arg_help(decl, prefix, 0); |
||
477 | printf("=ulong"); |
||
478 | pos += 6; |
||
479 | print_help_msg(decl, pos); |
||
480 | printf("\n"); |
||
481 | } |
||
482 | |||
483 | static void print_str_help(struct isl_arg *decl, const char *prefix, void *opt) |
||
484 | { |
||
485 | int pos; |
||
486 | const char *a = decl->argument_name ? decl->argument_name : "string"; |
||
487 | const char **p = (const char **)(((char *) opt) + decl->offset); |
||
488 | pos = print_arg_help(decl, prefix, 0); |
||
489 | pos = print_argument_name(decl, a, pos); |
||
490 | pos = print_help_msg(decl, pos); |
||
491 | if (*p) |
||
492 | print_default(decl, *p, pos); |
||
493 | printf("\n"); |
||
494 | } |
||
495 | |||
496 | static void print_str_list_help(struct isl_arg *decl, const char *prefix) |
||
497 | { |
||
498 | int pos; |
||
499 | const char *a = decl->argument_name ? decl->argument_name : "string"; |
||
500 | pos = print_arg_help(decl, prefix, 0); |
||
501 | pos = print_argument_name(decl, a, pos); |
||
502 | pos = print_help_msg(decl, pos); |
||
503 | printf("\n"); |
||
504 | } |
||
505 | |||
506 | static void print_help(struct isl_arg *arg, const char *prefix, void *opt) |
||
507 | { |
||
508 | int i; |
||
509 | int any = 0; |
||
510 | |||
511 | for (i = 0; arg[i].type != isl_arg_end; ++i) { |
||
512 | if (arg[i].flags & ISL_ARG_HIDDEN) |
||
513 | continue; |
||
514 | switch (arg[i].type) { |
||
515 | case isl_arg_flags: |
||
516 | print_flags_help(&arg[i], prefix, opt); |
||
517 | any = 1; |
||
518 | break; |
||
519 | case isl_arg_choice: |
||
520 | print_choice_help(&arg[i], prefix, opt); |
||
521 | any = 1; |
||
522 | break; |
||
523 | case isl_arg_bool: |
||
524 | print_bool_help(&arg[i], prefix, opt); |
||
525 | any = 1; |
||
526 | break; |
||
527 | case isl_arg_int: |
||
528 | print_int_help(&arg[i], prefix, opt); |
||
529 | any = 1; |
||
530 | break; |
||
531 | case isl_arg_long: |
||
532 | print_long_help(&arg[i], prefix, opt); |
||
533 | any = 1; |
||
534 | break; |
||
535 | case isl_arg_ulong: |
||
536 | print_ulong_help(&arg[i], prefix); |
||
537 | any = 1; |
||
538 | break; |
||
539 | case isl_arg_str: |
||
540 | print_str_help(&arg[i], prefix, opt); |
||
541 | any = 1; |
||
542 | break; |
||
543 | case isl_arg_str_list: |
||
544 | print_str_list_help(&arg[i], prefix); |
||
545 | any = 1; |
||
546 | break; |
||
547 | case isl_arg_alias: |
||
548 | case isl_arg_version: |
||
549 | case isl_arg_arg: |
||
550 | case isl_arg_footer: |
||
551 | case isl_arg_child: |
||
552 | case isl_arg_user: |
||
553 | case isl_arg_end: |
||
554 | break; |
||
555 | } |
||
556 | } |
||
557 | |||
558 | for (i = 0; arg[i].type != isl_arg_end; ++i) { |
||
559 | void *child; |
||
560 | |||
561 | if (arg[i].type != isl_arg_child) |
||
562 | continue; |
||
563 | if (arg[i].flags & ISL_ARG_HIDDEN) |
||
564 | continue; |
||
565 | |||
566 | if (any) |
||
567 | printf("\n"); |
||
568 | if (arg[i].help_msg) |
||
569 | printf(" %s\n", arg[i].help_msg); |
||
570 | if (arg[i].offset == (size_t) -1) |
||
571 | child = opt; |
||
572 | else |
||
573 | child = *(void **)(((char *) opt) + arg[i].offset); |
||
574 | print_help(arg[i].u.child.child->args, arg[i].long_name, child); |
||
575 | any = 1; |
||
576 | } |
||
577 | } |
||
578 | |||
579 | static const char *prog_name(const char *prog) |
||
580 | { |
||
581 | const char *slash; |
||
582 | |||
583 | slash = strrchr(prog, '/'); |
||
584 | if (slash) |
||
585 | prog = slash + 1; |
||
586 | if (strncmp(prog, "lt-", 3) == 0) |
||
587 | prog += 3; |
||
588 | |||
589 | return prog; |
||
590 | } |
||
591 | |||
592 | static int any_version(struct isl_arg *decl) |
||
593 | { |
||
594 | int i; |
||
595 | |||
596 | for (i = 0; decl[i].type != isl_arg_end; ++i) { |
||
597 | switch (decl[i].type) { |
||
598 | case isl_arg_version: |
||
599 | return 1; |
||
600 | case isl_arg_child: |
||
601 | if (any_version(decl[i].u.child.child->args)) |
||
602 | return 1; |
||
603 | break; |
||
604 | default: |
||
605 | break; |
||
606 | } |
||
607 | } |
||
608 | |||
609 | return 0; |
||
610 | } |
||
611 | |||
612 | static void print_help_and_exit(struct isl_arg *arg, const char *prog, |
||
613 | void *opt) |
||
614 | { |
||
615 | int i; |
||
616 | |||
617 | printf("Usage: %s [OPTION...]", prog_name(prog)); |
||
618 | |||
619 | for (i = 0; arg[i].type != isl_arg_end; ++i) |
||
620 | if (arg[i].type == isl_arg_arg) |
||
621 | printf(" %s", arg[i].argument_name); |
||
622 | |||
623 | printf("\n\n"); |
||
624 | |||
625 | print_help(arg, NULL, opt); |
||
626 | printf("\n"); |
||
627 | if (any_version(arg)) |
||
628 | printf(" -V, --version\n"); |
||
629 | print_bool_help(help_arg, NULL, NULL); |
||
630 | |||
631 | for (i = 0; arg[i].type != isl_arg_end; ++i) { |
||
632 | if (arg[i].type != isl_arg_footer) |
||
633 | continue; |
||
634 | wrap_msg(arg[i].help_msg, 0, 0); |
||
635 | printf("\n"); |
||
636 | } |
||
637 | |||
638 | exit(0); |
||
639 | } |
||
640 | |||
641 | static int match_long_name(struct isl_arg *decl, |
||
642 | const char *start, const char *end) |
||
643 | { |
||
644 | do { |
||
645 | if (end - start == strlen(decl->long_name) && |
||
646 | !strncmp(start, decl->long_name, end - start)) |
||
647 | return 1; |
||
648 | } while ((++decl)->type == isl_arg_alias); |
||
649 | |||
650 | return 0; |
||
651 | } |
||
652 | |||
653 | static const char *skip_dash_dash(struct isl_arg *decl, const char *arg) |
||
654 | { |
||
655 | if (!strncmp(arg, "--", 2)) |
||
656 | return arg + 2; |
||
657 | if ((decl->flags & ISL_ARG_SINGLE_DASH) && arg[0] == '-') |
||
658 | return arg + 1; |
||
659 | return NULL; |
||
660 | } |
||
661 | |||
662 | static const char *skip_name(struct isl_arg *decl, const char *arg, |
||
663 | const char *prefix, int need_argument, int *has_argument) |
||
664 | { |
||
665 | const char *equal; |
||
666 | const char *name; |
||
667 | const char *end; |
||
668 | |||
669 | if (arg[0] == '-' && arg[1] && arg[1] == decl->short_name) { |
||
670 | if (need_argument && !arg[2]) |
||
671 | return NULL; |
||
672 | if (has_argument) |
||
673 | *has_argument = arg[2] != '\0'; |
||
674 | return arg + 2; |
||
675 | } |
||
676 | if (!decl->long_name) |
||
677 | return NULL; |
||
678 | |||
679 | name = skip_dash_dash(decl, arg); |
||
680 | if (!name) |
||
681 | return NULL; |
||
682 | |||
683 | equal = strchr(name, '='); |
||
684 | if (need_argument && !equal) |
||
685 | return NULL; |
||
686 | |||
687 | if (has_argument) |
||
688 | *has_argument = !!equal; |
||
689 | end = equal ? equal : name + strlen(name); |
||
690 | |||
691 | if (prefix) { |
||
692 | size_t prefix_len = strlen(prefix); |
||
693 | if (strncmp(name, prefix, prefix_len) == 0 && |
||
694 | name[prefix_len] == '-') |
||
695 | name += prefix_len + 1; |
||
696 | } |
||
697 | |||
698 | if (!match_long_name(decl, name, end)) |
||
699 | return NULL; |
||
700 | |||
701 | return equal ? equal + 1 : end; |
||
702 | } |
||
703 | |||
704 | static int parse_choice_option(struct isl_arg *decl, char **arg, |
||
705 | const char *prefix, void *opt) |
||
706 | { |
||
707 | int i; |
||
708 | int has_argument; |
||
709 | const char *choice; |
||
710 | |||
711 | choice = skip_name(decl, arg[0], prefix, 0, &has_argument); |
||
712 | if (!choice) |
||
713 | return 0; |
||
714 | |||
715 | if (!has_argument && (!arg[1] || arg[1][0] == '-')) { |
||
716 | unsigned u = decl->u.choice.default_selected; |
||
717 | if (decl->u.choice.set) |
||
718 | decl->u.choice.set(opt, u); |
||
719 | else |
||
720 | *(unsigned *)(((char *)opt) + decl->offset) = u; |
||
721 | |||
722 | return 1; |
||
723 | } |
||
724 | |||
725 | if (!has_argument) |
||
726 | choice = arg[1]; |
||
727 | |||
728 | for (i = 0; decl->u.choice.choice[i].name; ++i) { |
||
729 | unsigned u; |
||
730 | |||
731 | if (strcmp(choice, decl->u.choice.choice[i].name)) |
||
732 | continue; |
||
733 | |||
734 | u = decl->u.choice.choice[i].value; |
||
735 | if (decl->u.choice.set) |
||
736 | decl->u.choice.set(opt, u); |
||
737 | else |
||
738 | *(unsigned *)(((char *)opt) + decl->offset) = u; |
||
739 | |||
740 | return has_argument ? 1 : 2; |
||
741 | } |
||
742 | |||
743 | return 0; |
||
744 | } |
||
745 | |||
746 | static int set_flag(struct isl_arg *decl, unsigned *val, const char *flag, |
||
747 | size_t len) |
||
748 | { |
||
749 | int i; |
||
750 | |||
751 | for (i = 0; decl->u.flags.flags[i].name; ++i) { |
||
752 | if (strncmp(flag, decl->u.flags.flags[i].name, len)) |
||
753 | continue; |
||
754 | |||
755 | *val &= ~decl->u.flags.flags[i].mask; |
||
756 | *val |= decl->u.flags.flags[i].value; |
||
757 | |||
758 | return 1; |
||
759 | } |
||
760 | |||
761 | return 0; |
||
762 | } |
||
763 | |||
764 | static int parse_flags_option(struct isl_arg *decl, char **arg, |
||
765 | const char *prefix, void *opt) |
||
766 | { |
||
767 | int has_argument; |
||
768 | const char *flags; |
||
769 | const char *comma; |
||
770 | unsigned val; |
||
771 | |||
772 | flags = skip_name(decl, arg[0], prefix, 0, &has_argument); |
||
773 | if (!flags) |
||
774 | return 0; |
||
775 | |||
776 | if (!has_argument && !arg[1]) |
||
777 | return 0; |
||
778 | |||
779 | if (!has_argument) |
||
780 | flags = arg[1]; |
||
781 | |||
782 | val = 0; |
||
783 | |||
784 | while ((comma = strchr(flags, ',')) != NULL) { |
||
785 | if (!set_flag(decl, &val, flags, comma - flags)) |
||
786 | return 0; |
||
787 | flags = comma + 1; |
||
788 | } |
||
789 | if (!set_flag(decl, &val, flags, strlen(flags))) |
||
790 | return 0; |
||
791 | |||
792 | *(unsigned *)(((char *)opt) + decl->offset) = val; |
||
793 | |||
794 | return has_argument ? 1 : 2; |
||
795 | } |
||
796 | |||
797 | static int parse_bool_option(struct isl_arg *decl, char **arg, |
||
798 | const char *prefix, void *opt) |
||
799 | { |
||
800 | const char *name; |
||
801 | unsigned *p = (unsigned *)(((char *)opt) + decl->offset); |
||
802 | |||
803 | if (skip_name(decl, arg[0], prefix, 0, NULL)) { |
||
804 | if ((decl->flags & ISL_ARG_BOOL_ARG) && arg[1]) { |
||
805 | char *endptr; |
||
806 | int val = strtol(arg[1], &endptr, 0); |
||
807 | if (*endptr == '\0' && (val == 0 || val == 1)) { |
||
808 | if (decl->u.b.set) |
||
809 | decl->u.b.set(opt, val); |
||
810 | else if (decl->offset != (size_t) -1) |
||
811 | *p = val; |
||
812 | return 2; |
||
813 | } |
||
814 | } |
||
815 | if (decl->u.b.set) |
||
816 | decl->u.b.set(opt, 1); |
||
817 | else if (decl->offset != (size_t) -1) |
||
818 | *p = 1; |
||
819 | |||
820 | return 1; |
||
821 | } |
||
822 | |||
823 | if (!decl->long_name) |
||
824 | return 0; |
||
825 | |||
826 | name = skip_dash_dash(decl, arg[0]); |
||
827 | if (!name) |
||
828 | return 0; |
||
829 | |||
830 | if (prefix) { |
||
831 | size_t prefix_len = strlen(prefix); |
||
832 | if (strncmp(name, prefix, prefix_len) == 0 && |
||
833 | name[prefix_len] == '-') { |
||
834 | name += prefix_len + 1; |
||
835 | prefix = NULL; |
||
836 | } |
||
837 | } |
||
838 | |||
839 | if (strncmp(name, "no-", 3)) |
||
840 | return 0; |
||
841 | name += 3; |
||
842 | |||
843 | if (prefix) { |
||
844 | size_t prefix_len = strlen(prefix); |
||
845 | if (strncmp(name, prefix, prefix_len) == 0 && |
||
846 | name[prefix_len] == '-') |
||
847 | name += prefix_len + 1; |
||
848 | } |
||
849 | |||
850 | if (match_long_name(decl, name, name + strlen(name))) { |
||
851 | if (decl->u.b.set) |
||
852 | decl->u.b.set(opt, 0); |
||
853 | else if (decl->offset != (size_t) -1) |
||
854 | *p = 0; |
||
855 | |||
856 | return 1; |
||
857 | } |
||
858 | |||
859 | return 0; |
||
860 | } |
||
861 | |||
862 | static int parse_str_option(struct isl_arg *decl, char **arg, |
||
863 | const char *prefix, void *opt) |
||
864 | { |
||
865 | int has_argument; |
||
866 | const char *s; |
||
867 | char **p = (char **)(((char *)opt) + decl->offset); |
||
868 | |||
869 | s = skip_name(decl, arg[0], prefix, 0, &has_argument); |
||
870 | if (!s) |
||
871 | return 0; |
||
872 | |||
873 | if (has_argument) { |
||
874 | free(*p); |
||
875 | *p = strdup(s); |
||
876 | return 1; |
||
877 | } |
||
878 | |||
879 | if (arg[1]) { |
||
880 | free(*p); |
||
881 | *p = strdup(arg[1]); |
||
882 | return 2; |
||
883 | } |
||
884 | |||
885 | return 0; |
||
886 | } |
||
887 | |||
888 | static int isl_arg_str_list_append(struct isl_arg *decl, void *opt, |
||
889 | const char *s) |
||
890 | { |
||
891 | int *n = (int *)(((char *) opt) + decl->u.str_list.offset_n); |
||
892 | char **list = *(char ***)(((char *) opt) + decl->offset); |
||
893 | |||
894 | list = realloc(list, (*n + 1) * sizeof(char *)); |
||
895 | if (!list) |
||
896 | return -1; |
||
897 | *(char ***)(((char *) opt) + decl->offset) = list; |
||
898 | list[*n] = strdup(s); |
||
899 | (*n)++; |
||
900 | return 0; |
||
901 | } |
||
902 | |||
903 | static int parse_str_list_option(struct isl_arg *decl, char **arg, |
||
904 | const char *prefix, void *opt) |
||
905 | { |
||
906 | int has_argument; |
||
907 | const char *s; |
||
908 | |||
909 | s = skip_name(decl, arg[0], prefix, 0, &has_argument); |
||
910 | if (!s) |
||
911 | return 0; |
||
912 | |||
913 | if (has_argument) { |
||
914 | isl_arg_str_list_append(decl, opt, s); |
||
915 | return 1; |
||
916 | } |
||
917 | |||
918 | if (arg[1]) { |
||
919 | isl_arg_str_list_append(decl, opt, arg[1]); |
||
920 | return 2; |
||
921 | } |
||
922 | |||
923 | return 0; |
||
924 | } |
||
925 | |||
926 | static int parse_int_option(struct isl_arg *decl, char **arg, |
||
927 | const char *prefix, void *opt) |
||
928 | { |
||
929 | int has_argument; |
||
930 | const char *val; |
||
931 | char *endptr; |
||
932 | int *p = (int *)(((char *)opt) + decl->offset); |
||
933 | |||
934 | val = skip_name(decl, arg[0], prefix, 0, &has_argument); |
||
935 | if (!val) |
||
936 | return 0; |
||
937 | |||
938 | if (has_argument) { |
||
939 | *p = atoi(val); |
||
940 | return 1; |
||
941 | } |
||
942 | |||
943 | if (arg[1]) { |
||
944 | int i = strtol(arg[1], &endptr, 0); |
||
945 | if (*endptr == '\0') { |
||
946 | *p = i; |
||
947 | return 2; |
||
948 | } |
||
949 | } |
||
950 | |||
951 | return 0; |
||
952 | } |
||
953 | |||
954 | static int parse_long_option(struct isl_arg *decl, char **arg, |
||
955 | const char *prefix, void *opt) |
||
956 | { |
||
957 | int has_argument; |
||
958 | const char *val; |
||
959 | char *endptr; |
||
960 | long *p = (long *)(((char *)opt) + decl->offset); |
||
961 | |||
962 | val = skip_name(decl, arg[0], prefix, 0, &has_argument); |
||
963 | if (!val) |
||
964 | return 0; |
||
965 | |||
966 | if (has_argument) { |
||
967 | long l = strtol(val, NULL, 0); |
||
968 | if (decl->u.l.set) |
||
969 | decl->u.l.set(opt, l); |
||
970 | else |
||
971 | *p = l; |
||
972 | return 1; |
||
973 | } |
||
974 | |||
975 | if (arg[1]) { |
||
976 | long l = strtol(arg[1], &endptr, 0); |
||
977 | if (*endptr == '\0') { |
||
978 | if (decl->u.l.set) |
||
979 | decl->u.l.set(opt, l); |
||
980 | else |
||
981 | *p = l; |
||
982 | return 2; |
||
983 | } |
||
984 | } |
||
985 | |||
986 | if (decl->u.l.default_value != decl->u.l.default_selected) { |
||
987 | if (decl->u.l.set) |
||
988 | decl->u.l.set(opt, decl->u.l.default_selected); |
||
989 | else |
||
990 | *p = decl->u.l.default_selected; |
||
991 | return 1; |
||
992 | } |
||
993 | |||
994 | return 0; |
||
995 | } |
||
996 | |||
997 | static int parse_ulong_option(struct isl_arg *decl, char **arg, |
||
998 | const char *prefix, void *opt) |
||
999 | { |
||
1000 | int has_argument; |
||
1001 | const char *val; |
||
1002 | char *endptr; |
||
1003 | unsigned long *p = (unsigned long *)(((char *)opt) + decl->offset); |
||
1004 | |||
1005 | val = skip_name(decl, arg[0], prefix, 0, &has_argument); |
||
1006 | if (!val) |
||
1007 | return 0; |
||
1008 | |||
1009 | if (has_argument) { |
||
1010 | *p = strtoul(val, NULL, 0); |
||
1011 | return 1; |
||
1012 | } |
||
1013 | |||
1014 | if (arg[1]) { |
||
1015 | unsigned long ul = strtoul(arg[1], &endptr, 0); |
||
1016 | if (*endptr == '\0') { |
||
1017 | *p = ul; |
||
1018 | return 2; |
||
1019 | } |
||
1020 | } |
||
1021 | |||
1022 | return 0; |
||
1023 | } |
||
1024 | |||
1025 | static int parse_option(struct isl_arg *decl, char **arg, |
||
1026 | const char *prefix, void *opt); |
||
1027 | |||
1028 | static int parse_child_option(struct isl_arg *decl, char **arg, |
||
1029 | const char *prefix, void *opt) |
||
1030 | { |
||
1031 | void *child; |
||
1032 | |||
1033 | if (decl->offset == (size_t) -1) |
||
1034 | child = opt; |
||
1035 | else { |
||
1036 | child = *(void **)(((char *)opt) + decl->offset); |
||
1037 | prefix = decl->long_name; |
||
1038 | } |
||
1039 | return parse_option(decl->u.child.child->args, arg, prefix, child); |
||
1040 | } |
||
1041 | |||
1042 | static int parse_option(struct isl_arg *decl, char **arg, |
||
1043 | const char *prefix, void *opt) |
||
1044 | { |
||
1045 | int i; |
||
1046 | |||
1047 | for (i = 0; decl[i].type != isl_arg_end; ++i) { |
||
1048 | int parsed = 0; |
||
1049 | switch (decl[i].type) { |
||
1050 | case isl_arg_choice: |
||
1051 | parsed = parse_choice_option(&decl[i], arg, prefix, opt); |
||
1052 | break; |
||
1053 | case isl_arg_flags: |
||
1054 | parsed = parse_flags_option(&decl[i], arg, prefix, opt); |
||
1055 | break; |
||
1056 | case isl_arg_int: |
||
1057 | parsed = parse_int_option(&decl[i], arg, prefix, opt); |
||
1058 | break; |
||
1059 | case isl_arg_long: |
||
1060 | parsed = parse_long_option(&decl[i], arg, prefix, opt); |
||
1061 | break; |
||
1062 | case isl_arg_ulong: |
||
1063 | parsed = parse_ulong_option(&decl[i], arg, prefix, opt); |
||
1064 | break; |
||
1065 | case isl_arg_bool: |
||
1066 | parsed = parse_bool_option(&decl[i], arg, prefix, opt); |
||
1067 | break; |
||
1068 | case isl_arg_str: |
||
1069 | parsed = parse_str_option(&decl[i], arg, prefix, opt); |
||
1070 | break; |
||
1071 | case isl_arg_str_list: |
||
1072 | parsed = parse_str_list_option(&decl[i], arg, prefix, |
||
1073 | opt); |
||
1074 | break; |
||
1075 | case isl_arg_child: |
||
1076 | parsed = parse_child_option(&decl[i], arg, prefix, opt); |
||
1077 | break; |
||
1078 | case isl_arg_alias: |
||
1079 | case isl_arg_arg: |
||
1080 | case isl_arg_footer: |
||
1081 | case isl_arg_user: |
||
1082 | case isl_arg_version: |
||
1083 | case isl_arg_end: |
||
1084 | break; |
||
1085 | } |
||
1086 | if (parsed) |
||
1087 | return parsed; |
||
1088 | } |
||
1089 | |||
1090 | return 0; |
||
1091 | } |
||
1092 | |||
1093 | static void print_version(struct isl_arg *decl) |
||
1094 | { |
||
1095 | int i; |
||
1096 | |||
1097 | for (i = 0; decl[i].type != isl_arg_end; ++i) { |
||
1098 | switch (decl[i].type) { |
||
1099 | case isl_arg_version: |
||
1100 | decl[i].u.version.print_version(); |
||
1101 | break; |
||
1102 | case isl_arg_child: |
||
1103 | print_version(decl[i].u.child.child->args); |
||
1104 | break; |
||
1105 | default: |
||
1106 | break; |
||
1107 | } |
||
1108 | } |
||
1109 | } |
||
1110 | |||
1111 | static void print_version_and_exit(struct isl_arg *decl) |
||
1112 | { |
||
1113 | print_version(decl); |
||
1114 | |||
1115 | exit(0); |
||
1116 | } |
||
1117 | |||
1118 | static int drop_argument(int argc, char **argv, int drop, int n) |
||
1119 | { |
||
1120 | for (; drop < argc; ++drop) |
||
1121 | argv[drop] = argv[drop + n]; |
||
1122 | |||
1123 | return argc - n; |
||
1124 | } |
||
1125 | |||
1126 | static int n_arg(struct isl_arg *arg) |
||
1127 | { |
||
1128 | int i; |
||
1129 | int n_arg = 0; |
||
1130 | |||
1131 | for (i = 0; arg[i].type != isl_arg_end; ++i) |
||
1132 | if (arg[i].type == isl_arg_arg) |
||
1133 | n_arg++; |
||
1134 | |||
1135 | return n_arg; |
||
1136 | } |
||
1137 | |||
1138 | static int next_arg(struct isl_arg *arg, int a) |
||
1139 | { |
||
1140 | for (++a; arg[a].type != isl_arg_end; ++a) |
||
1141 | if (arg[a].type == isl_arg_arg) |
||
1142 | return a; |
||
1143 | |||
1144 | return -1; |
||
1145 | } |
||
1146 | |||
1147 | /* Unless ISL_ARG_SKIP_HELP is set, check if any of the arguments is |
||
1148 | * equal to "--help" and if so call print_help_and_exit. |
||
1149 | */ |
||
1150 | void check_help(struct isl_args *args, int argc, char **argv, void *opt, |
||
1151 | unsigned flags) |
||
1152 | { |
||
1153 | int i; |
||
1154 | |||
1155 | if (ISL_FL_ISSET(flags, ISL_ARG_SKIP_HELP)) |
||
1156 | return; |
||
1157 | |||
1158 | for (i = 1; i < argc; ++i) { |
||
1159 | if (strcmp(argv[i], "--help") == 0) |
||
1160 | print_help_and_exit(args->args, argv[0], opt); |
||
1161 | } |
||
1162 | } |
||
1163 | |||
1164 | int isl_args_parse(struct isl_args *args, int argc, char **argv, void *opt, |
||
1165 | unsigned flags) |
||
1166 | { |
||
1167 | int a = -1; |
||
1168 | int skip = 0; |
||
1169 | int i; |
||
1170 | int n; |
||
1171 | |||
1172 | n = n_arg(args->args); |
||
1173 | |||
1174 | check_help(args, argc, argv, opt, flags); |
||
1175 | |||
1176 | for (i = 1; i < argc; ++i) { |
||
1177 | if ((strcmp(argv[i], "--version") == 0 || |
||
1178 | strcmp(argv[i], "-V") == 0) && any_version(args->args)) |
||
1179 | print_version_and_exit(args->args); |
||
1180 | } |
||
1181 | |||
1182 | while (argc > 1 + skip) { |
||
1183 | int parsed; |
||
1184 | if (argv[1 + skip][0] != '-') { |
||
1185 | a = next_arg(args->args, a); |
||
1186 | if (a >= 0) { |
||
1187 | char **p; |
||
1188 | p = (char **)(((char *)opt)+args->args[a].offset); |
||
1189 | free(*p); |
||
1190 | *p = strdup(argv[1 + skip]); |
||
1191 | argc = drop_argument(argc, argv, 1 + skip, 1); |
||
1192 | --n; |
||
1193 | } else if (ISL_FL_ISSET(flags, ISL_ARG_ALL)) { |
||
1194 | fprintf(stderr, "%s: extra argument: %s\n", |
||
1195 | prog_name(argv[0]), argv[1 + skip]); |
||
1196 | exit(-1); |
||
1197 | } else |
||
1198 | ++skip; |
||
1199 | continue; |
||
1200 | } |
||
1201 | parsed = parse_option(args->args, &argv[1 + skip], NULL, opt); |
||
1202 | if (parsed) |
||
1203 | argc = drop_argument(argc, argv, 1 + skip, parsed); |
||
1204 | else if (ISL_FL_ISSET(flags, ISL_ARG_ALL)) { |
||
1205 | fprintf(stderr, "%s: unrecognized option: %s\n", |
||
1206 | prog_name(argv[0]), argv[1 + skip]); |
||
1207 | exit(-1); |
||
1208 | } else |
||
1209 | ++skip; |
||
1210 | } |
||
1211 | |||
1212 | if (n > 0) { |
||
1213 | fprintf(stderr, "%s: expecting %d more argument(s)\n", |
||
1214 | prog_name(argv[0]), n); |
||
1215 | exit(-1); |
||
1216 | } |
||
1217 | |||
1218 | return argc; |
||
1219 | } |