From fd22173b291b943a2e2cb2f28552c2f18478236b Mon Sep 17 00:00:00 2001 From: Miciah Dashiel Butler Masters Date: Tue, 28 Aug 2007 17:11:52 +0000 Subject: [PATCH] Introduce option tree shadowing Introduce get_option_shadow. This routine takes an option, the tree under which that option resides, and another tree. It returns a corresponding option with parallel ancestry in the second tree, creating that option and ancestry if it does not already exist. Add enum copy_option_flags. Add the CO_NO_LISTBOX_ITEM flag, which is used to suppress listbox creation for shadowed trees. Add the CO_SHALLOW flag, which is used to suppress the duplication of unwanted children for shadowed trees. Add a flags parameter to copy_option and tree_dup (and out of necessity, struct option_type_info and str_dup). --- src/config/options.c | 51 +++++++++++++++++++++++++++++++++++++++---- src/config/options.h | 12 +++++++++- src/config/opttypes.c | 8 ++++--- src/config/opttypes.h | 2 +- 4 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/config/options.c b/src/config/options.c index c912cef2d..93a7decc5 100644 --- a/src/config/options.c +++ b/src/config/options.c @@ -210,7 +210,7 @@ get_opt_rec(struct option *tree, const unsigned char *name_) * option. By having _template_ OPT_AUTOCREATE and _template_ * inside, you can have even multi-level autocreating. */ - option = copy_option(template); + option = copy_option(template, 0); if (!option) { mem_free(aname); return NULL; @@ -618,7 +618,7 @@ delete_option(struct option *option) } struct option * -copy_option(struct option *template) +copy_option(struct option *template, int flags) { struct option *option = mem_calloc(1, sizeof(*option)); @@ -633,7 +633,8 @@ copy_option(struct option *template) option->desc = template->desc; option->change_hook = template->change_hook; - option->box_item = init_option_listbox_item(option); + if (!(flags & CO_NO_LISTBOX_ITEM)) + option->box_item = init_option_listbox_item(option); if (option->box_item) { if (template->box_item) { option->box_item->type = template->box_item->type; @@ -642,7 +643,7 @@ copy_option(struct option *template) } if (option_types[template->type].dup) { - option_types[template->type].dup(option, template); + option_types[template->type].dup(option, template, flags); } else { option->value = template->value; } @@ -650,6 +651,48 @@ copy_option(struct option *template) return option; } +/* Return the shadow option in @shadow_tree of @option in @tree. If @option + * isn't yet shadowed in @shadow_tree, shadow it (i.e. create a copy + * in @shadow_tree) along with any ancestors that aren't shadowed. */ +struct option * +get_option_shadow(struct option *option, struct option *tree, + struct option *shadow_tree) +{ + + struct option *shadow_option = NULL; + + assert(option); + assert(tree); + assert(shadow_tree); + + if (option == tree) { + shadow_option = shadow_tree; + } else if (option->root && option->name) { + struct option *shadow_root; + + shadow_root = get_option_shadow(option->root, tree, + shadow_tree); + if (!shadow_root) return NULL; + + shadow_option = get_opt_rec_real(shadow_root, option->name); + if (!shadow_option) { + shadow_option = copy_option(option, + CO_SHALLOW + | CO_NO_LISTBOX_ITEM); + if (shadow_option) { + shadow_option->root = shadow_root; + /* No need to sort, is there? It isn't shown + * in the options manager. -- Miciah */ + add_to_list_end(*shadow_root->value.tree, + shadow_option); + } + + } + } + + return shadow_option; +} + LIST_OF(struct option) * init_options_tree(void) { diff --git a/src/config/options.h b/src/config/options.h index 635fc07b2..cc17b6784 100644 --- a/src/config/options.h +++ b/src/config/options.h @@ -169,7 +169,17 @@ extern void smart_config_string(struct string *, int, int, void (*)(struct string *, struct option *, unsigned char *, int, int, int, int)); -extern struct option *copy_option(struct option *); +enum copy_option_flags { + /* Do not create a listbox option for the new option. */ + CO_NO_LISTBOX_ITEM = (1 << 0), + + /* Do not copy children. */ + CO_SHALLOW = (1 << 1), +}; + +extern struct option *copy_option(struct option *, int); +struct option *get_option_shadow(struct option *, struct option *, + struct option *); extern void delete_option(struct option *); void mark_option_as_deleted(struct option *); diff --git a/src/config/opttypes.c b/src/config/opttypes.c index 3aee42161..ab0118299 100644 --- a/src/config/opttypes.c +++ b/src/config/opttypes.c @@ -295,7 +295,7 @@ str_wr(struct option *o, struct string *s) } static void -str_dup(struct option *opt, struct option *template) +str_dup(struct option *opt, struct option *template, int flags) { unsigned char *new = mem_alloc(MAX_STR_LEN); @@ -366,7 +366,7 @@ color_wr(struct option *opt, struct string *str) } static void -tree_dup(struct option *opt, struct option *template) +tree_dup(struct option *opt, struct option *template, int flags) { LIST_OF(struct option) *new = init_options_tree(); LIST_OF(struct option) *tree = template->value.tree; @@ -375,8 +375,10 @@ tree_dup(struct option *opt, struct option *template) if (!new) return; opt->value.tree = new; + if (flags & CO_SHALLOW) return; + foreachback (option, *tree) { - struct option *new_opt = copy_option(option); + struct option *new_opt = copy_option(option, flags); if (!new_opt) continue; object_nolock(new_opt, "option"); diff --git a/src/config/opttypes.h b/src/config/opttypes.h index 0bbbfdb09..4ddafbff5 100644 --- a/src/config/opttypes.h +++ b/src/config/opttypes.h @@ -9,7 +9,7 @@ struct option_type_info { unsigned char *(*cmdline)(struct option *, unsigned char ***, int *); unsigned char *(*read)(struct option *, unsigned char **, int *); void (*write)(struct option *, struct string *); - void (*dup)(struct option *, struct option *); + void (*dup)(struct option *, struct option *, int); int (*set)(struct option *, unsigned char *); unsigned char *help_str; };