From 7cdbc908d8fe19744284a4f0fb5deb6b01758177 Mon Sep 17 00:00:00 2001 From: Kalle Olavi Niemitalo Date: Sun, 3 Feb 2008 13:07:43 +0200 Subject: [PATCH] config: Rewrite "set" to "unset" and vice versa. Also, replace OPT_WATERMARK with OPT_MUST_SAVE, which has the opposite meaning. Watermarking of aliases does not yet work correctly in this version. Neither does the "include" command. --- src/config/conf.c | 91 ++++++++++++++++++++++++++------------------ src/config/options.c | 20 +++++++--- src/config/options.h | 31 ++++++++++----- 3 files changed, 89 insertions(+), 53 deletions(-) diff --git a/src/config/conf.c b/src/config/conf.c index 2dd41b8e..aad84af7 100644 --- a/src/config/conf.c +++ b/src/config/conf.c @@ -192,8 +192,8 @@ skip_to_unquoted_newline_or_comment(struct conf_parsing_pos *pos) /* Parse a command. Returns error code. */ /* If dynamic string credentials are supplied, we will mirror the command at * the end of the string; however, we won't load the option value to the tree, - * and we will even write option value from the tree to the output string. We - * will only possibly set OPT_WATERMARK flag to the option (if enabled). */ + * and we will even write option value from the tree to the output string. + * We will only possibly clear OPT_MUST_SAVE flag in the option. */ static enum parse_error parse_set(struct option *opt_tree, struct conf_parsing_state *state, @@ -242,6 +242,24 @@ parse_set(struct option *opt_tree, struct conf_parsing_state *state, show_parse_error(state, ERROR_OPTION); skip_option_value(&state->pos); return ERROR_OPTION; + /* TODO: Distinguish between two scenarios: + * - A newer version of ELinks has saved an + * option that this version does not recognize. + * The option must be preserved. (This works.) + * - The user has added an option, saved + * elinks.conf, restarted ELinks, deleted the + * option, and is now saving elinks.conf again. + * The option should be rewritten to "unset". + * (This does not work yet.) + * In both cases, ELinks has no struct option + * for that name. Possible fixes: + * - If the tree has OPT_AUTOCREATE, then + * assume the user had created that option, + * and rewrite it to "unset". Otherwise, + * keep it. + * - When the user deletes an option, just mark + * it with OPT_DELETED, and keep it in memory + * as long as OPT_TOUCHED is set. */ } if (!option_types[opt->type].read) { @@ -274,21 +292,24 @@ parse_set(struct option *opt_tree, struct conf_parsing_state *state, } } else { /* rewriting a configuration file */ - if (opt->flags & OPT_DELETED) - opt->flags &= ~OPT_WATERMARK; - else - opt->flags |= OPT_WATERMARK; - if (option_types[opt->type].write) { + if (opt->flags & OPT_DELETED) { + /* Replace the "set" command with an + * "unset" command. */ + add_to_string(mirror, "unset "); + add_bytes_to_string(mirror, optname_orig, + optname_len); + state->mirrored = state->pos.look; + } else if (option_types[opt->type].write) { add_bytes_to_string(mirror, state->mirrored, pos_before_value.look - state->mirrored); option_types[opt->type].write(opt, mirror); state->mirrored = state->pos.look; } + /* Remember that the option need not be + * written to the end of the file. */ + opt->flags &= ~OPT_MUST_SAVE; } - /* This is not needed since this will be WATERMARK'd when - * saving it. We won't need to save it as touched. */ - /* if (!str) opt->flags |= OPT_TOUCHED; */ mem_free(val); } @@ -303,9 +324,6 @@ parse_unset(struct option *opt_tree, struct conf_parsing_state *state, size_t optname_len; unsigned char *optname_copy; - /* XXX: This does not handle the autorewriting well and is mostly a - * quick hack than anything now. --pasky */ - skip_white(&state->pos); if (!*state->pos.look) return show_parse_error(state, ERROR_PARSE); @@ -342,10 +360,23 @@ parse_unset(struct option *opt_tree, struct conf_parsing_state *state, else mark_option_as_deleted(opt); } else { /* rewriting a configuration file */ - if (opt->flags & OPT_DELETED) - opt->flags |= OPT_WATERMARK; - else - opt->flags &= ~OPT_WATERMARK; + if (opt->flags & OPT_DELETED) { + /* The "unset" command is already in the file, + * and unlike with "set", there is no value + * to be updated. */ + } else if (option_types[opt->type].write) { + /* Replace the "unset" command with a + * "set" command. */ + add_to_string(mirror, "set "); + add_bytes_to_string(mirror, optname_orig, + optname_len); + add_to_string(mirror, " = "); + option_types[opt->type].write(opt, mirror); + state->mirrored = state->pos.look; + } + /* Remember that the option need not be + * written to the end of the file. */ + opt->flags &= ~OPT_MUST_SAVE; } } @@ -718,7 +749,6 @@ load_config(void) static int indentation = 2; /* 0 -> none, 1 -> only option full name+type, 2 -> only desc, 3 -> both */ static int comments = 3; -static int touching = 0; static inline unsigned char * conf_i18n(unsigned char *s, int i18n) @@ -745,12 +775,6 @@ smart_config_output_fn(struct string *string, struct option *option, if (option->type == OPT_ALIAS) return; - /* XXX: OPT_LANGUAGE shouldn't have any bussiness here, but we're just - * weird in that area. */ - if (touching && !(option->flags & OPT_TOUCHED) - && option->type != OPT_LANGUAGE) - return; - switch (action) { case 0: if (!(comments & 1)) break; @@ -870,23 +894,18 @@ create_config_string(unsigned char *prefix, unsigned char *name, if (!init_string(&config)) return NULL; - if (savestyle == 3) { - touching = 1; - savestyle = 1; - } else { - touching = 0; - } + prepare_mustsave_flags(options->value.tree, + savestyle == 1 || savestyle == 2); /* Scaring. */ if (savestyle == 2 - || (savestyle < 2 - && (load_config_file(prefix, name, options, &config, 0) - || !config.length))) { + || load_config_file(prefix, name, options, &config, 0) + || !config.length) { /* At first line, and in English, write ELinks version, may be * of some help in future. Please keep that format for it. * --Zas */ add_to_string(&config, "## ELinks " VERSION " configuration file\n\n"); - assert(savestyle >= 0 && savestyle <= 2); + assert(savestyle >= 0 && savestyle <= 3); switch (savestyle) { case 0: add_to_string(&config, conf_i18n(N_( @@ -896,7 +915,7 @@ create_config_string(unsigned char *prefix, unsigned char *name, "## and all your formatting, own comments etc will be kept as-is.\n"), i18n)); break; - case 1: + case 1: case 3: add_to_string(&config, conf_i18n(N_( "## This is ELinks configuration file. You can edit it manually,\n" "## if you wish so; this file is edited by ELinks when you save\n" @@ -953,8 +972,6 @@ create_config_string(unsigned char *prefix, unsigned char *name, done_string(&tmpstring); get_me_out: - unmark_options_tree(options->value.tree); - return config.source; } diff --git a/src/config/options.c b/src/config/options.c index e54816f2..6198051f 100644 --- a/src/config/options.c +++ b/src/config/options.c @@ -737,14 +737,22 @@ register_change_hooks(const struct change_hook_info *change_hooks) } void -unmark_options_tree(LIST_OF(struct option) *tree) +prepare_mustsave_flags(LIST_OF(struct option) *tree, int set_all) { struct option *option; foreach (option, *tree) { - option->flags &= ~OPT_WATERMARK; + /* XXX: OPT_LANGUAGE shouldn't have any bussiness + * here, but we're just weird in that area. */ + if (set_all + || (option->flags & (OPT_TOUCHED | OPT_DELETED)) + || option->type == OPT_LANGUAGE) + option->flags |= OPT_MUST_SAVE; + else + option->flags &= ~OPT_MUST_SAVE; + if (option->type == OPT_TREE) - unmark_options_tree(option->value.tree); + prepare_mustsave_flags(option->value.tree, set_all); } } @@ -770,7 +778,7 @@ check_nonempty_tree(LIST_OF(struct option) *options) if (opt->type == OPT_TREE) { if (check_nonempty_tree(opt->value.tree)) return 1; - } else if (!(opt->flags & OPT_WATERMARK)) { + } else if (opt->flags & OPT_MUST_SAVE) { return 1; } } @@ -791,14 +799,14 @@ smart_config_string(struct string *str, int print_comment, int i18n, int do_print_comment = 1; if (option->flags & OPT_HIDDEN || - option->flags & OPT_WATERMARK || option->type == OPT_ALIAS || !strcmp(option->name, "_template_")) continue; /* Is there anything to be printed anyway? */ if (option->type == OPT_TREE - && !check_nonempty_tree(option->value.tree)) + ? !check_nonempty_tree(option->value.tree) + : !(option->flags & OPT_MUST_SAVE)) continue; /* We won't pop out the description when we're in autocreate diff --git a/src/config/options.h b/src/config/options.h index c1d32896..2d6f506a 100644 --- a/src/config/options.h +++ b/src/config/options.h @@ -24,15 +24,26 @@ enum option_flags { * this category when adding an option. The 'template' for the added * hiearchy piece (category) is stored as "_template_" category. */ OPT_AUTOCREATE = 2, - /* This is used just for marking various options for some very dark, - * nasty and dirty purposes. This watermarking should be kept inside - * some very closed and clearly bounded piece of ELinks module, not - * spreaded along whole ELinks code, and you should clear it everytime - * when sneaking outside of the module (except some trivial common - * utility functions). Basically, you don't want to use this flag - * normally ;). It doesn't affect how the option is handled by common - * option handling functions in any way. */ - OPT_WATERMARK = 4, + /* The option has been modified in some way and must be saved + * to elinks.conf. ELinks uses this flag only while it is + * saving the options. When the config.saving_style option + * has value 3, saving works like this: + * - First, ELinks sets OPT_MUST_SAVE in the options that have + * OPT_TOUCHED or OPT_DELETED, and clears it in the rest. + * - ELinks then parses the old configuration file. If it + * contains a "set" or "unset" command for this option, + * ELinks rewrites the command and clears OPT_MUST_SAVE. + * - After ELinks has rewritten the configuration file, it + * appends the options that still have the OPT_MUST_SAVE + * flag. + * Other saving styles are variants of this: + * - 0: ELinks does not append any options to the + * configuration file. So OPT_MUST_SAVE has no effect. + * - 1: ELinks initially sets OPT_MUST_SAVE in all options, + * regardless of OPT_TOUCHED and OPT_DELETED. + * - 2: ELinks initially sets OPT_MUST_SAVE in all options, + * and does not read any configuration files. */ + OPT_MUST_SAVE = 4, /* This is used to mark options modified after the last save. That's * being useful if you want to save only the options whose value * changed. */ @@ -161,7 +172,7 @@ extern void register_change_hooks(const struct change_hook_info *change_hooks); extern LIST_OF(struct option) *init_options_tree(void); -extern void unmark_options_tree(LIST_OF(struct option) *); +extern void prepare_mustsave_flags(LIST_OF(struct option) *, int set_all); extern void untouch_options(LIST_OF(struct option) *); extern void smart_config_string(struct string *, int, int,