2 * This file is part of libFirm.
3 * Copyright (C) 2012 IPD Goos, Universit"at Karlsruhe, Germany
13 #include "lc_opts_t.h"
14 #include "lc_opts_enum.h"
16 #include "lc_printf.h"
21 #define ERR_STRING "In argument \"%s\": "
25 #define HELP_TEMPL "%-15s %-10s %-45s"
26 #define HELP_TEMPL_VALS HELP_TEMPL " [%s] (%s)"
28 static struct obstack obst;
30 static void set_name(lc_opt_entry_t *ent, const char *name)
33 ent->hash = hash_str(name);
36 #define entry_matches(ent,hash_val,str) \
37 ((ent)->hash == hash_val && strcmp((ent)->name, (str)) == 0)
39 #define entries_equal(e1,e2) entry_matches(e1, (e2)->hash, (e2)->name)
41 static lc_opt_err_info_t *set_error(lc_opt_err_info_t *err, int error, const char *arg)
52 int lc_opt_raise_error(const lc_opt_err_info_t *err, lc_opt_error_handler_t *handler,
59 if (err && lc_opt_is_error(err)) {
63 vsnprintf(buf, sizeof(buf), fmt, args);
72 static lc_opt_entry_t *init_entry(lc_opt_entry_t *ent, lc_opt_entry_t *parent,
73 const char *name, const char *desc)
75 const char *copied_name;
76 const char *copied_desc;
78 obstack_grow0(&obst, name, strlen(name));
79 copied_name = (char*)obstack_finish(&obst);
80 obstack_grow0(&obst, desc, strlen(desc));
81 copied_desc = (char*)obstack_finish(&obst);
83 memset(ent, 0, sizeof(*ent));
84 set_name(ent, copied_name);
85 ent->desc = copied_desc;
90 static lc_opt_entry_t *init_grp(lc_opt_entry_t *ent, lc_opt_err_info_t *err)
93 INIT_LIST_HEAD(&ent->v.grp.grps);
94 INIT_LIST_HEAD(&ent->v.grp.opts);
96 set_error(err, lc_opt_err_none, "");
98 if (ent->parent->is_grp)
99 list_add_tail(&ent->list, &lc_get_grp_special(ent->parent)->grps);
101 set_error(err, lc_opt_err_grp_expected, ent->parent->name);
107 static lc_opt_entry_t *init_opt(lc_opt_entry_t *ent,
109 void *val, size_t length,
110 lc_opt_callback_t *cb,
112 lc_opt_dump_vals_t *dump_vals,
113 lc_opt_err_info_t *err)
115 lc_opt_special_t *s = lc_get_opt_special(ent);
118 set_error(err, lc_opt_err_none, "");
119 list_add_tail(&ent->list, &lc_get_grp_special(ent->parent)->opts);
125 s->dump_vals = dump_vals;
132 lc_opt_entry_t *lc_opt_root_grp(void)
134 static lc_opt_entry_t root_group;
135 static int inited = 0;
141 init_entry(&root_group, NULL, "root", "The root node");
142 init_grp(&root_group, NULL);
148 int lc_opt_grp_is_root(const lc_opt_entry_t *ent)
150 return ent->parent == NULL;
153 static const char *get_type_name(lc_opt_type_t type)
157 #define XXX(t) case lc_opt_type_ ## t: res = #t; break
173 const char *lc_opt_get_type_name(const lc_opt_entry_t *ent)
175 return get_type_name(lc_get_opt_special(ent)->type);
178 lc_opt_entry_t *lc_opt_get_grp(lc_opt_entry_t *parent, const char *name)
180 lc_opt_entry_t *ent = lc_opt_find_grp(parent, name, NULL);
183 ent = OALLOC(&obst, lc_opt_entry_t);
184 init_entry(ent, parent, name, "");
191 lc_opt_entry_t *lc_opt_add_opt(lc_opt_entry_t *parent,
192 const char *name, const char *desc,
193 lc_opt_type_t type, void *value, size_t length,
194 lc_opt_callback_t *cb, lc_opt_dump_t *dump,
195 lc_opt_dump_vals_t *dump_vals,
196 lc_opt_err_info_t *err)
198 lc_opt_entry_t *res = NULL;
200 if (parent->is_grp) {
201 lc_opt_entry_t *ent = lc_opt_find_opt(parent, name, NULL);
204 res = OALLOC(&obst, lc_opt_entry_t);
205 init_entry(res, parent, name, desc);
206 init_opt(res, type, value, length, cb, dump, dump_vals, err);
208 set_error(err, lc_opt_err_opt_already_there, name);
210 set_error(err, lc_opt_err_grp_expected, name);
216 static lc_opt_entry_t *lc_opt_find_ent(const struct list_head *head, const char *name,
217 int error_to_use, lc_opt_err_info_t *err)
219 lc_opt_entry_t *found = NULL;
220 int error = error_to_use;
221 unsigned hash = hash_str(name);
223 if (!list_empty(head)) {
224 list_for_each_entry(lc_opt_entry_t, ent, head, list) {
225 if (entry_matches(ent, hash, name)) {
226 error = lc_opt_err_none;
233 set_error(err, error, name);
237 lc_opt_entry_t *lc_opt_find_grp(const lc_opt_entry_t *grp, const char *name, lc_opt_err_info_t *err)
239 return grp ? lc_opt_find_ent(&lc_get_grp_special(grp)->grps,
240 name, lc_opt_err_grp_not_found, err) : NULL;
243 lc_opt_entry_t *lc_opt_find_opt(const lc_opt_entry_t *grp, const char *name, lc_opt_err_info_t *err)
245 return grp ? lc_opt_find_ent(&lc_get_grp_special(grp)->opts,
246 name, lc_opt_err_opt_not_found, err) : NULL;
249 static const lc_opt_entry_t *resolve_up_to_last(const lc_opt_entry_t *root,
250 const char * const *names, int pos, int n, lc_opt_err_info_t *err)
257 ent = lc_opt_find_grp(root, names[pos], err);
258 return ent ? resolve_up_to_last(ent, names, pos + 1, n, err) : NULL;
261 static const char *path_delim = "/.";
263 static lc_opt_entry_t *resolve_up_to_last_str_rec(lc_opt_entry_t *from,
265 const char **last_name)
268 lc_opt_entry_t *res = from;
269 size_t end = strcspn(path, path_delim);
271 if (path[end] != '\0') {
272 /* skip all delimiters */
273 size_t next = strspn(path + end, path_delim);
275 /* copy the part of the path into a buffer */
276 char *buf = (char*)malloc((end+1) * sizeof(buf[0]));
277 strncpy(buf, path, end);
280 /* resolve the group and free */
281 from = lc_opt_get_grp(from, buf);
284 res = resolve_up_to_last_str_rec(from, path + end + next, last_name);
287 else if (last_name != NULL) {
294 static lc_opt_entry_t *resolve_up_to_last_str(lc_opt_entry_t *root, const char *path, const char **last_name)
296 size_t next = strspn(path, path_delim);
298 /* if l != 0 we saw deliminators, so we resolve from the root */
300 root = lc_opt_root_grp();
302 return resolve_up_to_last_str_rec(root, path + next, last_name);
305 lc_opt_entry_t *lc_opt_resolve_grp(const lc_opt_entry_t *root,
306 const char * const *names, int n, lc_opt_err_info_t *err)
308 const lc_opt_entry_t *grp = resolve_up_to_last(root, names, 0, n - 1, err);
309 return lc_opt_find_grp(grp, names[n - 1], err);
312 lc_opt_entry_t *lc_opt_resolve_opt(const lc_opt_entry_t *root,
313 const char * const *names, int n, lc_opt_err_info_t *err)
315 const lc_opt_entry_t *grp = resolve_up_to_last(root, names, 0, n - 1, err);
316 return lc_opt_find_opt(grp, names[n - 1], err);
319 static char *strtolower(char *buf, size_t n, const char *str)
322 for (i = 0; i < n; ++i)
323 buf[i] = tolower((unsigned char)str[i]);
327 int lc_opt_std_cb(const char *name, lc_opt_type_t type, void *data, size_t length, ...)
334 va_start(args, length);
339 case lc_opt_type_bit:
340 integer = va_arg(args, int);
342 *(unsigned*)data |= length;
344 *(unsigned*)data &= ~length;
347 case lc_opt_type_boolean:
348 *((int *) data) = va_arg(args, int);
351 case lc_opt_type_string:
352 strncpy((char*)data, va_arg(args, const char *), length);
355 case lc_opt_type_int:
356 *((int *) data) = va_arg(args, int);
359 case lc_opt_type_double:
360 *((double *) data) = va_arg(args, double);
371 int lc_opt_std_dump(char *buf, size_t n, const char *name, lc_opt_type_t type, void *data, size_t length)
379 case lc_opt_type_bit:
380 res = snprintf(buf, n, "%x", *((unsigned *) data));
382 case lc_opt_type_boolean:
383 res = snprintf(buf, n, "%s", *((int *) data) ? "true" : "false");
385 case lc_opt_type_string:
386 strncpy(buf, (const char*)data, n);
389 case lc_opt_type_int:
390 res = snprintf(buf, n, "%d", *((int *) data));
392 case lc_opt_type_double:
393 res = snprintf(buf, n, "%g", *((double *) data));
409 int lc_opt_bool_dump_vals(char *buf, size_t n, const char *name, lc_opt_type_t type, void *data, size_t length)
415 strncpy(buf, "true, false", n);
419 int lc_opt_occurs(lc_opt_entry_t *opt, const char *value, lc_opt_err_info_t *err)
421 static const struct {
436 int error = lc_opt_err_illegal_format;
437 lc_opt_special_t *s = lc_get_opt_special(opt);
442 } val_storage, *val = &val_storage;
445 set_error(err, lc_opt_err_opt_not_found, "");
450 set_error(err, lc_opt_err_no_callback, "");
457 case lc_opt_type_int:
458 if (sscanf(value, "%i", (int *) val)) {
459 error = lc_opt_err_unknown_value;
460 if (s->cb(opt->name, s->type, s->value, s->length, val->integer))
461 error = lc_opt_err_none;
465 case lc_opt_type_double:
466 if (sscanf(value, "%lf", (double *) val)) {
467 error = lc_opt_err_unknown_value;
468 if (s->cb(opt->name, s->type, s->value, s->length, val->dbl))
469 error = lc_opt_err_none;
473 case lc_opt_type_boolean:
474 case lc_opt_type_bit:
475 strtolower(buf, sizeof(buf), value);
476 for (i = 0; i < ARRAY_SIZE(bool_strings); ++i) {
477 if (strcmp(buf, bool_strings[i].str) == 0) {
478 val->integer = bool_strings[i].val;
479 error = lc_opt_err_none;
484 if (error == lc_opt_err_none) {
485 error = lc_opt_err_unknown_value;
486 if (s->cb(opt->name, s->type, s->value, s->length, val->integer))
487 error = lc_opt_err_none;
492 case lc_opt_type_string:
493 case lc_opt_type_enum:
494 error = lc_opt_err_unknown_value;
495 if (s->cb(opt->name, s->type, s->value, s->length, value))
496 error = lc_opt_err_none;
498 case lc_opt_type_invalid:
502 set_error(err, error, value);
503 return error == lc_opt_err_none;
506 char *lc_opt_value_to_string(char *buf, size_t len, const lc_opt_entry_t *ent)
508 const lc_opt_special_t *s = lc_get_opt_special(ent);
510 s->dump(buf, len, ent->name, s->type, s->value, s->length);
512 strncpy(buf, "<n/a>", len);
517 static char *lc_opt_values_to_string(char *buf, size_t len, const lc_opt_entry_t *ent)
519 const lc_opt_special_t *s = lc_get_opt_special(ent);
521 s->dump_vals(buf, len, ent->name, s->type, s->value, s->length);
526 int lc_opt_add_table(lc_opt_entry_t *root, const lc_opt_table_entry_t *table)
529 lc_opt_err_info_t err;
531 for (i = 0; table[i].name != NULL; ++i) {
533 const lc_opt_table_entry_t *tab = &table[i];
534 lc_opt_entry_t *grp = resolve_up_to_last_str(root, tab->name, &name);
536 lc_opt_add_opt(grp, name, tab->desc, tab->type, tab->value, tab->len, tab->cb, tab->dump, tab->dump_vals, &err);
537 if (err.error != lc_opt_err_none)
544 static void lc_opt_print_grp_path_rec(char *buf, size_t len, const lc_opt_entry_t *ent, char separator, lc_opt_entry_t *stop_ent)
548 if (!lc_opt_grp_is_root(ent)) {
550 lc_opt_print_grp_path_rec(buf, len, ent->parent, separator, stop_ent);
552 if (l > 0 && l < len-1) {
558 strncat(buf, ent->name, len-1);
561 static char *lc_opt_print_grp_path(char *buf, size_t len, const lc_opt_entry_t *ent, char separator, lc_opt_entry_t *stop_ent)
565 lc_opt_print_grp_path_rec(buf, len, ent, separator, stop_ent);
570 * dump the option tree.
571 * @param ent starting entity
572 * @param separator separator char
573 * @param stop_ent stop at this entity when dumping the name
574 * @param f output file
576 static void lc_opt_print_help_rec(lc_opt_entry_t *ent, char separator, lc_opt_entry_t *stop_ent, FILE *f)
578 lc_grp_special_t *s = lc_get_grp_special(ent);
583 if (!list_empty(&s->opts)) {
584 lc_opt_print_grp_path(grp_name, sizeof(grp_name), ent, separator, stop_ent);
587 fprintf(f, "%s:\n", grp_name);
589 list_for_each_entry(lc_opt_entry_t, e, &s->opts, list) {
592 lc_opt_value_to_string(value, sizeof(value), e);
593 lc_opt_values_to_string(values, sizeof(values), e);
594 fprintf(f, HELP_TEMPL_VALS "\n", e->name, lc_opt_get_type_name(e), e->desc, value, values);
598 list_for_each_entry(lc_opt_entry_t, e, &s->grps, list) {
599 lc_opt_print_help_rec(e, separator, stop_ent, f);
604 void lc_opt_print_help(lc_opt_entry_t *ent, FILE *f)
606 fprintf(f, HELP_TEMPL_VALS "\n", "option", "type", "description", "default", "possible options");
607 lc_opt_print_help_rec(ent, '.', NULL, f);
610 void lc_opt_print_help_for_entry(lc_opt_entry_t *ent, char separator, FILE *f)
612 fprintf(f, HELP_TEMPL_VALS "\n", "option", "type", "description", "default", "possible options");
613 lc_opt_print_help_rec(ent, separator, ent, f);
617 static void indent(FILE *f, int n)
620 for (i = 0; i < n; ++i)
624 static void lc_opt_print_tree_lc_opt_indent(lc_opt_entry_t *ent, FILE *f, int level)
627 lc_opt_special_t *s = lc_get_opt_special(ent);
630 fprintf(f, "%c%s(\"%s\"):%s = %s\n", s->is_set ? '+' : '-', ent->name,
631 ent->desc, lc_opt_get_type_name(ent), lc_opt_value_to_string(buf, sizeof(buf), ent));
634 static void lc_opt_print_tree_grp_indent(lc_opt_entry_t *ent, FILE *f, int level)
639 s = lc_get_grp_special(ent);
641 fprintf(f, "/%s\n", ent->name);
643 list_for_each_entry(lc_opt_entry_t, e, &s->grps, list) {
644 lc_opt_print_tree_grp_indent(e, f, level + 2);
647 list_for_each_entry(lc_opt_entry_t, e, &s->opts, list) {
648 lc_opt_print_tree_lc_opt_indent(e, f, level + 2);
653 void lc_opt_print_tree(lc_opt_entry_t *ent, FILE *f)
655 lc_opt_print_tree_grp_indent(ent, f, 0);
658 static int lc_opts_default_error_handler(const char *prefix, const lc_opt_err_info_t *err)
660 fprintf(stderr, "%s: %s; %s\n", prefix, err->msg, err->arg);
664 int lc_opt_from_single_arg(const lc_opt_entry_t *root,
665 const char *opt_prefix,
666 const char *arg, lc_opt_error_handler_t *handler)
668 const lc_opt_entry_t *grp = root;
669 size_t n = strlen(arg);
670 size_t n_prefix = opt_prefix != NULL ? strlen(opt_prefix) : 0;
674 lc_opt_err_info_t err;
675 const char *end, *eqsign;
677 if (n >= n_prefix && (n_prefix == 0 || strncmp(opt_prefix, arg, n_prefix) == 0)) {
678 arg = arg + n_prefix;
680 /* find the next delimiter (the -) and extract the string up to
682 end = strchr(arg, OPT_DELIM);
683 eqsign = strchr(arg, '=');
684 if (eqsign && eqsign < end)
686 while (end != NULL) {
688 * Copy the part of the option into the buffer and add the
691 char *buf = (char*)obstack_copy0(&obst, arg, end - arg);
693 /* Resolve the group inside the group */
694 grp = lc_opt_find_grp(grp, buf, &err);
695 error = lc_opt_raise_error(&err, handler, ERR_STRING, arg);
699 /* Find the next option part delimiter. */
701 end = strchr(arg, OPT_DELIM);
702 eqsign = strchr(arg, '=');
703 if (eqsign && eqsign < end)
705 obstack_free(&obst, buf);
713 * Now, we are at the last option part:
714 * --grp1-grp2-...-grpn-opt=value
715 * Check, for the = and evaluate the option string. If the = is
716 * missing, we should have a boolean option, but that is checked
719 end = strchr(arg, '=');
720 buf = (char*)obstack_copy0(&obst, arg, end ? end - arg : (int) strlen(arg));
721 opt = lc_opt_find_opt(grp, buf, &err);
722 error = lc_opt_raise_error(&err, handler, ERR_STRING, arg);
726 * Now evaluate the parameter of the option (the part after
727 * the =) if it was given.
729 arg = end ? end + 1 : "true";
731 /* Set the value of the option. */
732 lc_opt_occurs(opt, arg, &err);
733 ret = !lc_opt_raise_error(&err, handler, ERR_STRING, arg);
741 int lc_opt_from_argv(const lc_opt_entry_t *root,
742 const char *opt_prefix,
743 int argc, const char *argv[],
744 lc_opt_error_handler_t *handler)
750 handler = lc_opts_default_error_handler;
752 for (i = 0; i < argc; ++i) {
753 options_set |= lc_opt_from_single_arg(root, opt_prefix, argv[i], handler);
759 static int opt_arg_type(const lc_arg_occ_t *occ)
762 return lc_arg_type_ptr;
765 static int opt_arg_emit(lc_appendable_t *app, const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
769 lc_opt_entry_t *opt = (lc_opt_entry_t*)arg->v_ptr;
773 switch (occ->conversion) {
775 lc_opt_value_to_string(buf, sizeof(buf), opt);
778 s = lc_opt_get_type_name(opt);
791 res = lc_appendable_snadd(app, s, strlen(s));
796 static const lc_arg_handler_t lc_opt_arg_handler = {
802 /* lc_printf facility for options */
804 const lc_arg_env_t *lc_opt_get_arg_env(void)
806 static lc_arg_env_t *env = NULL;
809 env = lc_arg_new_env();
811 lc_arg_register(env, "opt:value", 'V', &lc_opt_arg_handler);
812 lc_arg_register(env, "opt:type", 'T', &lc_opt_arg_handler);
813 lc_arg_register(env, "opt:desc", 'D', &lc_opt_arg_handler);
814 lc_arg_register(env, "opt:name", 'O', &lc_opt_arg_handler);