2 * Copyright 2008-2009 Katholieke Universiteit Leuven
4 * Use of this software is governed by the GNU LGPLv2.1 license
6 * Written by Sven Verdoolaege, K.U.Leuven, Departement
7 * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
17 static void set_default_choice(struct isl_arg *arg, void *opt)
19 *(unsigned *)(((char *)opt) + arg->offset) = arg->u.choice.default_value;
22 static void set_default_flags(struct isl_arg *arg, void *opt)
24 *(unsigned *)(((char *)opt) + arg->offset) = arg->u.flags.default_value;
27 static void set_default_bool(struct isl_arg *arg, void *opt)
29 if (arg->offset == (size_t) -1)
31 *(unsigned *)(((char *)opt) + arg->offset) = arg->u.b.default_value;
34 static void set_default_child(struct isl_arg *arg, void *opt)
36 void *child = calloc(1, arg->u.child.size);
39 isl_arg_set_defaults(arg->u.child.child, child);
41 *(void **)(((char *)opt) + arg->offset) = child;
44 static void set_default_user(struct isl_arg *arg, void *opt)
46 arg->u.user.init(((char *)opt) + arg->offset);
49 static void set_default_long(struct isl_arg *arg, void *opt)
51 *(long *)(((char *)opt) + arg->offset) = arg->u.l.default_value;
54 static void set_default_ulong(struct isl_arg *arg, void *opt)
56 *(unsigned long *)(((char *)opt) + arg->offset) = arg->u.ul.default_value;
59 static void set_default_str(struct isl_arg *arg, void *opt)
61 const char *str = NULL;
62 if (arg->u.str.default_value)
63 str = strdup(arg->u.str.default_value);
64 *(const char **)(((char *)opt) + arg->offset) = str;
67 void isl_arg_set_defaults(struct isl_arg *arg, void *opt)
71 for (i = 0; arg[i].type != isl_arg_end; ++i) {
72 switch (arg[i].type) {
74 set_default_choice(&arg[i], opt);
77 set_default_flags(&arg[i], opt);
80 set_default_bool(&arg[i], opt);
83 set_default_child(&arg[i], opt);
86 set_default_user(&arg[i], opt);
89 set_default_long(&arg[i], opt);
92 set_default_ulong(&arg[i], opt);
96 set_default_str(&arg[i], opt);
105 void isl_arg_free(struct isl_arg *arg, void *opt)
112 for (i = 0; arg[i].type != isl_arg_end; ++i) {
113 switch (arg[i].type) {
115 isl_arg_free(arg[i].u.child.child,
116 *(void **)(((char *)opt) + arg[i].offset));
120 free(*(char **)(((char *)opt) + arg[i].offset));
123 if (arg[i].u.user.clear)
124 arg[i].u.user.clear(((char *)opt) + arg[i].offset);
131 case isl_arg_version:
140 static int print_arg_help(struct isl_arg *decl, const char *prefix, int no)
144 if (!decl->long_name) {
145 printf(" -%c", decl->short_name);
149 if (decl->short_name)
150 printf(" -%c, --", decl->short_name);
156 printf("%s-", prefix);
157 len += strlen(prefix) + 1;
163 printf("%s", decl->long_name);
164 len += strlen(decl->long_name);
169 const void *isl_memrchr(const void *s, int c, size_t n)
178 static int print_help_msg(struct isl_arg *decl, int pos)
187 printf("\n%30s", "");
189 printf("%*s", 30 - pos, "");
194 const char *space = isl_memrchr(s, ' ', 45);
198 space = strchr(s + 45, ' ');
202 printf("%.*s", l, s);
205 printf("\n%30s", "");
212 static void print_default(struct isl_arg *decl, const char *def, int pos)
215 const char *default_prefix = "[default: ";
216 const char *default_suffix = "]";
219 len = strlen(default_prefix) + strlen(def) + strlen(default_suffix);
221 if (!decl->help_msg) {
223 printf("\n%30s", "");
225 printf("%*s", 30 - pos, "");
229 printf("\n%30s", "");
233 printf("%s%s%s", default_prefix, def, default_suffix);
236 static void print_default_choice(struct isl_arg *decl, int pos)
239 const char *s = "none";
241 for (i = 0; decl->u.choice.choice[i].name; ++i)
242 if (decl->u.choice.choice[i].value == decl->u.choice.default_value) {
243 s = decl->u.choice.choice[i].name;
247 print_default(decl, s, pos);
250 static void print_choice_help(struct isl_arg *decl, const char *prefix)
255 pos = print_arg_help(decl, prefix, 0);
259 for (i = 0; decl->u.choice.choice[i].name; ++i) {
264 printf("%s", decl->u.choice.choice[i].name);
265 pos += strlen(decl->u.choice.choice[i].name);
268 pos = print_help_msg(decl, pos);
269 print_default_choice(decl, pos);
274 static void print_default_flags(struct isl_arg *decl, int pos)
277 const char *default_prefix = "[default: ";
278 const char *default_suffix = "]";
279 int len = strlen(default_prefix) + strlen(default_suffix);
281 for (i = 0; decl->u.flags.flags[i].name; ++i)
282 if ((decl->u.flags.default_value & decl->u.flags.flags[i].mask) ==
283 decl->u.flags.flags[i].value)
284 len += strlen(decl->u.flags.flags[i].name);
286 if (!decl->help_msg) {
288 printf("\n%30s", "");
290 printf("%*s", 30 - pos, "");
294 printf("\n%30s", "");
298 printf("%s", default_prefix);
300 for (first = 1, i = 0; decl->u.flags.flags[i].name; ++i)
301 if ((decl->u.flags.default_value & decl->u.flags.flags[i].mask) ==
302 decl->u.flags.flags[i].value) {
305 printf("%s", decl->u.flags.flags[i].name);
309 printf("%s", default_suffix);
312 static void print_flags_help(struct isl_arg *decl, const char *prefix)
317 pos = print_arg_help(decl, prefix, 0);
321 for (i = 0; decl->u.flags.flags[i].name; ++i) {
327 decl->u.flags.flags[j].mask == decl->u.flags.flags[i].mask;
333 printf("%s", decl->u.flags.flags[j].name);
334 pos += strlen(decl->u.flags.flags[j].name);
339 pos = print_help_msg(decl, pos);
340 print_default_flags(decl, pos);
345 static void print_bool_help(struct isl_arg *decl, const char *prefix)
348 int no = decl->u.b.default_value == 1;
349 pos = print_arg_help(decl, prefix, no);
350 pos = print_help_msg(decl, pos);
351 if (decl->offset != (size_t) -1)
352 print_default(decl, no ? "yes" : "no", pos);
356 static int print_argument_name(struct isl_arg *decl, const char *name, int pos)
358 printf("%c<%s>", decl->long_name ? '=' : ' ', name);
359 return pos + 3 + strlen(name);
362 static void print_long_help(struct isl_arg *decl, const char *prefix)
365 pos = print_arg_help(decl, prefix, 0);
366 if (decl->u.l.default_value != decl->u.l.default_selected) {
372 if (decl->u.l.default_value != decl->u.l.default_selected) {
376 print_help_msg(decl, pos);
380 static void print_ulong_help(struct isl_arg *decl, const char *prefix)
383 pos = print_arg_help(decl, prefix, 0);
386 print_help_msg(decl, pos);
390 static void print_str_help(struct isl_arg *decl, const char *prefix)
393 const char *a = decl->argument_name ? decl->argument_name : "string";
394 pos = print_arg_help(decl, prefix, 0);
395 pos = print_argument_name(decl, a, pos);
396 pos = print_help_msg(decl, pos);
397 if (decl->u.str.default_value)
398 print_default(decl, decl->u.str.default_value, pos);
402 static void print_help(struct isl_arg *arg, const char *prefix)
406 for (i = 0; arg[i].type != isl_arg_end; ++i) {
407 switch (arg[i].type) {
409 print_flags_help(&arg[i], prefix);
412 print_choice_help(&arg[i], prefix);
415 print_bool_help(&arg[i], prefix);
418 print_long_help(&arg[i], prefix);
421 print_ulong_help(&arg[i], prefix);
424 print_str_help(&arg[i], prefix);
426 case isl_arg_version:
435 for (i = 0; arg[i].type != isl_arg_end; ++i) {
436 if (arg[i].type != isl_arg_child)
441 printf(" %s\n", arg[i].help_msg);
442 print_help(arg[i].u.child.child, arg[i].long_name);
446 static const char *prog_name(const char *prog)
450 slash = strrchr(prog, '/');
453 if (strncmp(prog, "lt-", 3) == 0)
459 static int any_version(struct isl_arg *decl)
463 for (i = 0; decl[i].type != isl_arg_end; ++i) {
464 switch (decl[i].type) {
465 case isl_arg_version:
468 if (any_version(decl[i].u.child.child))
479 static void print_help_and_exit(struct isl_arg *arg, const char *prog)
483 printf("Usage: %s [OPTION...]", prog_name(prog));
485 for (i = 0; arg[i].type != isl_arg_end; ++i)
486 if (arg[i].type == isl_arg_arg)
487 printf(" %s", arg[i].argument_name);
491 print_help(arg, NULL);
492 if (any_version(arg)) {
494 printf(" -V, --version\n");
500 static const char *skip_name(struct isl_arg *decl, const char *arg,
501 const char *prefix, int need_argument, int *has_argument)
507 if (arg[0] == '-' && arg[1] && arg[1] == decl->short_name) {
508 if (need_argument && !arg[2])
511 *has_argument = arg[2] != '\0';
514 if (!decl->long_name)
517 if (strncmp(arg, "--", 2))
521 equal = strchr(name, '=');
522 if (need_argument && !equal)
526 *has_argument = !!equal;
527 end = equal ? equal : name + strlen(name);
530 size_t prefix_len = strlen(prefix);
531 if (strncmp(name, prefix, prefix_len) == 0 &&
532 name[prefix_len] == '-')
533 name += prefix_len + 1;
536 if (end - name != strlen(decl->long_name) ||
537 strncmp(name, decl->long_name, end - name))
540 return equal ? equal + 1 : end;
543 static int parse_choice_option(struct isl_arg *decl, char **arg,
544 const char *prefix, void *opt)
550 choice = skip_name(decl, arg[0], prefix, 0, &has_argument);
554 if (!has_argument && (!arg[1] || arg[1][0] == '-')) {
555 unsigned u = decl->u.choice.default_selected;
556 if (decl->u.choice.set)
557 decl->u.choice.set(opt, u);
559 *(unsigned *)(((char *)opt) + decl->offset) = u;
567 for (i = 0; decl->u.choice.choice[i].name; ++i) {
570 if (strcmp(choice, decl->u.choice.choice[i].name))
573 u = decl->u.choice.choice[i].value;
574 if (decl->u.choice.set)
575 decl->u.choice.set(opt, u);
577 *(unsigned *)(((char *)opt) + decl->offset) = u;
579 return has_argument ? 1 : 2;
585 static int set_flag(struct isl_arg *decl, unsigned *val, const char *flag,
590 for (i = 0; decl->u.flags.flags[i].name; ++i) {
591 if (strncmp(flag, decl->u.flags.flags[i].name, len))
594 *val &= ~decl->u.flags.flags[i].mask;
595 *val |= decl->u.flags.flags[i].value;
603 static int parse_flags_option(struct isl_arg *decl, char **arg,
604 const char *prefix, void *opt)
611 flags = skip_name(decl, arg[0], prefix, 0, &has_argument);
615 if (!has_argument && !arg[1])
621 val = *(unsigned *)(((char *)opt) + decl->offset);
623 while ((comma = strchr(flags, ',')) != NULL) {
624 if (!set_flag(decl, &val, flags, comma - flags))
628 if (!set_flag(decl, &val, flags, strlen(flags)))
631 *(unsigned *)(((char *)opt) + decl->offset) = val;
633 return has_argument ? 1 : 2;
636 static int parse_bool_option(struct isl_arg *decl, const char *arg,
637 const char *prefix, void *opt)
639 unsigned *p = (unsigned *)(((char *)opt) + decl->offset);
641 if (skip_name(decl, arg, prefix, 0, NULL)) {
643 decl->u.b.set(opt, 1);
644 else if (decl->offset != (size_t) -1)
650 if (!decl->long_name)
653 if (strncmp(arg, "--", 2))
658 size_t prefix_len = strlen(prefix);
659 if (strncmp(arg, prefix, prefix_len) == 0 &&
660 arg[prefix_len] == '-') {
661 arg += prefix_len + 1;
666 if (strncmp(arg, "no-", 3))
671 size_t prefix_len = strlen(prefix);
672 if (strncmp(arg, prefix, prefix_len) == 0 &&
673 arg[prefix_len] == '-')
674 arg += prefix_len + 1;
677 if (!strcmp(arg, decl->long_name)) {
679 decl->u.b.set(opt, 0);
680 else if (decl->offset != (size_t) -1)
689 static int parse_str_option(struct isl_arg *decl, char **arg,
690 const char *prefix, void *opt)
694 char **p = (char **)(((char *)opt) + decl->offset);
696 s = skip_name(decl, arg[0], prefix, 0, &has_argument);
715 static int parse_long_option(struct isl_arg *decl, char **arg,
716 const char *prefix, void *opt)
721 long *p = (long *)(((char *)opt) + decl->offset);
723 val = skip_name(decl, arg[0], prefix, 0, &has_argument);
728 long l = strtol(val, NULL, 0);
730 decl->u.l.set(opt, l);
737 long l = strtol(arg[1], &endptr, 0);
738 if (*endptr == '\0') {
740 decl->u.l.set(opt, l);
747 if (decl->u.l.default_value != decl->u.l.default_selected) {
749 decl->u.l.set(opt, decl->u.l.default_selected);
751 *p = decl->u.l.default_selected;
758 static int parse_ulong_option(struct isl_arg *decl, char **arg,
759 const char *prefix, void *opt)
764 unsigned long *p = (unsigned long *)(((char *)opt) + decl->offset);
766 val = skip_name(decl, arg[0], prefix, 0, &has_argument);
771 *p = strtoul(val, NULL, 0);
776 unsigned long ul = strtoul(arg[1], &endptr, 0);
777 if (*endptr == '\0') {
786 static int parse_option(struct isl_arg *decl, char **arg,
787 const char *prefix, void *opt);
789 static int parse_child_option(struct isl_arg *decl, char **arg, void *opt)
791 return parse_option(decl->u.child.child, arg, decl->long_name,
792 *(void **)(((char *)opt) + decl->offset));
795 static int parse_option(struct isl_arg *decl, char **arg,
796 const char *prefix, void *opt)
800 for (i = 0; decl[i].type != isl_arg_end; ++i) {
802 switch (decl[i].type) {
804 parsed = parse_choice_option(&decl[i], arg, prefix, opt);
807 parsed = parse_flags_option(&decl[i], arg, prefix, opt);
810 parsed = parse_long_option(&decl[i], arg, prefix, opt);
813 parsed = parse_ulong_option(&decl[i], arg, prefix, opt);
816 parsed = parse_bool_option(&decl[i], *arg, prefix, opt);
819 parsed = parse_str_option(&decl[i], arg, prefix, opt);
822 parsed = parse_child_option(&decl[i], arg, opt);
826 case isl_arg_version:
837 static void print_version(struct isl_arg *decl)
841 for (i = 0; decl[i].type != isl_arg_end; ++i) {
842 switch (decl[i].type) {
843 case isl_arg_version:
844 decl[i].u.version.print_version();
847 print_version(decl[i].u.child.child);
855 static void print_version_and_exit(struct isl_arg *decl)
862 static int drop_argument(int argc, char **argv, int drop, int n)
864 for (; drop < argc; ++drop)
865 argv[drop] = argv[drop + n];
870 static int n_arg(struct isl_arg *arg)
875 for (i = 0; arg[i].type != isl_arg_end; ++i)
876 if (arg[i].type == isl_arg_arg)
882 static int next_arg(struct isl_arg *arg, int a)
884 for (++a; arg[a].type != isl_arg_end; ++a)
885 if (arg[a].type == isl_arg_arg)
891 int isl_arg_parse(struct isl_arg *arg, int argc, char **argv, void *opt,
901 for (i = 1; i < argc; ++i) {
902 if (strcmp(argv[i], "--help") == 0)
903 print_help_and_exit(arg, argv[0]);
906 for (i = 1; i < argc; ++i) {
907 if ((strcmp(argv[i], "--version") == 0 ||
908 strcmp(argv[i], "-V") == 0) && any_version(arg))
909 print_version_and_exit(arg);
912 while (argc > 1 + skip) {
914 if (argv[1 + skip][0] != '-') {
915 a = next_arg(arg, a);
918 p = (char **)(((char *)opt)+arg[a].offset);
920 *p = strdup(argv[1 + skip]);
921 argc = drop_argument(argc, argv, 1 + skip, 1);
923 } else if (ISL_FL_ISSET(flags, ISL_ARG_ALL)) {
924 fprintf(stderr, "%s: extra argument: %s\n",
925 prog_name(argv[0]), argv[1 + skip]);
931 parsed = parse_option(arg, &argv[1 + skip], NULL, opt);
933 argc = drop_argument(argc, argv, 1 + skip, parsed);
934 else if (ISL_FL_ISSET(flags, ISL_ARG_ALL)) {
935 fprintf(stderr, "%s: unrecognized option: %s\n",
936 prog_name(argv[0]), argv[1 + skip]);
943 fprintf(stderr, "%s: expecting %d more argument(s)\n",
944 prog_name(argv[0]), n);