Now that the ports tree has been unlocked, here's again the update of elinks to 0.11.4 + bug fixes from git.
Several critical bugs were fixed in 0.11.3, 0.11.4 and in the git tree, see: http://elinks.or.cz/release.html Tested on i386 and amd64 without X11. Best regards, -- Frank Denis - j [at] pureftpd.org - http://00f.net - http://www.cotery.com
diff -urN elinks/Makefile elinks.new/Makefile --- elinks/Makefile Tue Jul 15 17:06:54 2008 +++ elinks.new/Makefile Tue Jul 15 17:06:34 2008 @@ -1,7 +1,7 @@ # $OpenBSD: Makefile,v 1.9 2007/09/15 20:38:21 merdely Exp $ COMMENT= full-featured text WWW browser -DISTNAME= elinks-0.11.2 +DISTNAME= elinks-0.11.4 EXTRACT_SUFX= .tar.bz2 CATEGORIES= www MASTER_SITES= http://elinks.cz/download/ diff -urN elinks/distinfo elinks.new/distinfo --- elinks/distinfo Tue Jul 15 17:06:54 2008 +++ elinks.new/distinfo Tue Jul 15 17:06:34 2008 @@ -1,5 +1,5 @@ -MD5 (elinks-0.11.2.tar.bz2) = Wo+Dr7Unz0Q/WLNyE2qB/A== -RMD160 (elinks-0.11.2.tar.bz2) = qdk4z9+nG+KCt1luH+1Xl/Lv1qU= -SHA1 (elinks-0.11.2.tar.bz2) = R2acOOHl67NQFampqPnImIIb1Ag= -SHA256 (elinks-0.11.2.tar.bz2) = kayJRxXvzeeFSN/kcDrnAvCPtKlBhyiOuborMCWNVYU= -SIZE (elinks-0.11.2.tar.bz2) = 2497270 +MD5 (elinks-0.11.4.tar.bz2) = iANqUY68TxFQp+FLKfnY2w== +RMD160 (elinks-0.11.4.tar.bz2) = A0HAG0cn122GTLqop8brtjfN6hw= +SHA1 (elinks-0.11.4.tar.bz2) = Tt38152j4OPaHBhmaO+AT1/sUM0= +SHA256 (elinks-0.11.4.tar.bz2) = WG4JVmjO2PufKVjGuNpmJFJV0vd/YAdV5rbQC0twV7Q= +SIZE (elinks-0.11.4.tar.bz2) = 2479650 diff -urN elinks/patches/patch-configure elinks.new/patches/patch-configure --- elinks/patches/patch-configure Tue Jul 15 17:06:54 2008 +++ elinks.new/patches/patch-configure Tue Jul 15 17:06:34 2008 @@ -1,31 +1,16 @@ -$OpenBSD: patch-configure,v 1.2 2006/10/21 17:56:48 jasper Exp $ ---- configure.orig Sun Jan 29 08:10:47 2006 -+++ configure Thu Oct 19 12:52:57 2006 -@@ -17103,7 +17103,7 @@ if test -z "$disable_lua"; then +$OpenBSD$ +--- configure.orig Tue Jul 15 16:20:59 2008 ++++ configure Tue Jul 15 16:22:20 2008 +@@ -17623,7 +17623,7 @@ if test -z "$disable_lua"; then for luadir in "$withval" "" /usr /usr/local; do - for suffix in "" 50 51; do + for suffix in "" 50; do if test "$cf_result" = no; then - LUA_LIBS="-llua$suffix -llualib$suffix -lm" + LUA_LIBS="-llua$suffix -lm" if test ! -z "$luadir"; then LUA_LIBS="-L$luadir/lib $LUA_LIBS" -@@ -17127,10 +17127,10 @@ int - main () - { - lua_State *L = lua_open(); -- lua_baselibopen(L); -- lua_mathlibopen(L); -- lua_strlibopen(L); -- lua_tablibopen(L); -+ luaopen_base(L); -+ luaopen_math(L); -+ luaopen_string(L); -+ luaopen_table(L); - lua_pushboolean(L, 1); - lua_close(L); - ; -@@ -22892,10 +22892,6 @@ ALL_CFLAGS="$CFLAGS $CPPFLAGS" +@@ -23672,10 +23672,6 @@ ALL_CFLAGS="$CFLAGS $CPPFLAGS" diff -urN elinks/patches/patch-src_config_conf_c elinks.new/patches/patch-src_config_conf_c --- elinks/patches/patch-src_config_conf_c Thu Jan 1 01:00:00 1970 +++ elinks.new/patches/patch-src_config_conf_c Tue Jul 15 17:06:34 2008 @@ -0,0 +1,882 @@ +$OpenBSD$ +--- src/config/conf.c.orig Fri Jun 20 22:19:54 2008 ++++ src/config/conf.c Tue Jul 15 16:56:22 2008 +@@ -56,16 +56,63 @@ + * value to an option, but sometimes you may want to first create the option + * ;). Then this will come handy. */ + ++struct conf_parsing_state { ++ /** This part may be copied to a local variable as a bookmark ++ * and restored later. So it must not contain any pointers ++ * that would have to be freed in that situation. */ ++ struct conf_parsing_pos { ++ /** Points to the next character to be parsed from the ++ * configuration file. */ ++ unsigned char *look; + +-/* Skip comments and whitespace, +- * setting [EMAIL PROTECTED] to the number of lines skipped. */ +-static unsigned char * +-skip_white(unsigned char *start, int *line) ++ /** The line number corresponding to #look. This is ++ * shown in error messages. */ ++ int line; ++ } pos; ++ ++ /** When ELinks is rewriting the configuration file, @c mirrored ++ * indicates the end of the part that has already been copied ++ * to the mirror string. Otherwise, @c mirrored is not used. ++ * ++ * @invariant @c mirrored @<= @c pos.look */ ++ unsigned char *mirrored; ++ ++ /** File name for error messages. If NULL then do not display ++ * error messages. */ ++ const unsigned char *filename; ++}; ++ ++/** Tell the user about an error in the configuration file. ++ * @return @a err, for convenience. */ ++static enum parse_error ++show_parse_error(const struct conf_parsing_state *state, enum parse_error err) + { ++ static const unsigned char error_msg[][40] = { ++ "no error", /* ERROR_NONE */ ++ "unknown command", /* ERROR_COMMAND */ ++ "parse error", /* ERROR_PARSE */ ++ "unknown option", /* ERROR_OPTION */ ++ "bad value", /* ERROR_VALUE */ ++ "no memory left", /* ERROR_NOMEM */ ++ }; ++ ++ if (state->filename) { ++ fprintf(stderr, "%s:%d: %s\n", ++ state->filename, state->pos.line, error_msg[err]); ++ } ++ return err; ++} ++ ++/** Skip comments and whitespace. */ ++static void ++skip_white(struct conf_parsing_pos *pos) ++{ ++ unsigned char *start = pos->look; ++ + while (*start) { + while (isspace(*start)) { + if (*start == '\n') { +- (*line)++; ++ pos->line++; + } + start++; + } +@@ -73,85 +120,208 @@ skip_white(unsigned char *start, int *line) + if (*start == '#') { + start += strcspn(start, "\n"); + } else { +- return start; ++ pos->look = start; ++ return; + } + } + +- return start; ++ pos->look = start; + } + ++/** Skip a quoted string. ++ * This function allows "mismatching quotes' because str_rd() does so. */ ++static void ++skip_quoted(struct conf_parsing_pos *pos) ++{ ++ assert(isquote(*pos->look)); ++ if_assert_failed return; ++ pos->look++; ++ ++ for (;;) { ++ if (!*pos->look) ++ return; ++ if (isquote(*pos->look)) { ++ pos->look++; ++ return; ++ } ++ if (*pos->look == '\\' && pos->look[1]) ++ pos->look++; ++ if (*pos->look == '\n') ++ pos->line++; ++ pos->look++; ++ } ++} ++ ++/** Skip the value of an option. ++ * ++ * This job is normally done by the reader function that corresponds ++ * to the type of the option. However, if ELinks does not recognize ++ * the name of the option, it cannot look up the type and has to use ++ * this function instead. */ ++static void ++skip_option_value(struct conf_parsing_pos *pos) ++{ ++ if (isquote(*pos->look)) { ++ /* Looks like OPT_STRING, OPT_CODEPAGE, OPT_LANGUAGE, ++ * or OPT_COLOR. */ ++ skip_quoted(pos); ++ } else { ++ /* Looks like OPT_BOOL, OPT_INT, or OPT_LONG. */ ++ while (isasciialnum(*pos->look) || *pos->look == '.' ++ || *pos->look == '+' || *pos->look == '-') ++ pos->look++; ++ } ++} ++ ++/** Skip to the next newline or comment that is not part of a quoted ++ * string. When ELinks hits a parse error in the configuration file, ++ * it calls this in order to find the place where is should resume ++ * parsing. This is intended to prevent ELinks from treating words ++ * in strings as commands. */ ++static void ++skip_to_unquoted_newline_or_comment(struct conf_parsing_pos *pos) ++{ ++ while (*pos->look && *pos->look != '#' && *pos->look != '\n') { ++ if (isquote(*pos->look)) ++ skip_quoted(pos); ++ else ++ pos->look++; ++ } ++} ++ + /* 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 set or clear OPT_MUST_SAVE flag in the option. */ + + static enum parse_error +-parse_set(struct option *opt_tree, unsigned char **file, int *line, ++parse_set(struct option *opt_tree, struct conf_parsing_state *state, + struct string *mirror, int is_system_conf) + { +- unsigned char *orig_pos = *file; +- unsigned char *optname; +- unsigned char bin; ++ const unsigned char *optname_orig; ++ size_t optname_len; ++ unsigned char *optname_copy; + +- *file = skip_white(*file, line); +- if (!**file) return ERROR_PARSE; ++ skip_white(&state->pos); ++ if (!*state->pos.look) return show_parse_error(state, ERROR_PARSE); + + /* Option name */ +- optname = *file; +- while (isident(**file) || **file == '*' || **file == '.' || **file == '+') +- (*file)++; ++ optname_orig = state->pos.look; ++ while (isident(*state->pos.look) || *state->pos.look == '*' ++ || *state->pos.look == '.' || *state->pos.look == '+') ++ state->pos.look++; ++ optname_len = state->pos.look - optname_orig; + +- bin = **file; +- **file = '\0'; +- optname = stracpy(optname); +- if (!optname) return ERROR_NOMEM; +- **file = bin; ++ skip_white(&state->pos); + +- *file = skip_white(*file, line); +- + /* Equal sign */ +- if (**file != '=') { mem_free(optname); return ERROR_PARSE; } +- (*file)++; /* '=' */ +- *file = skip_white(*file, line); +- if (!**file) { mem_free(optname); return ERROR_VALUE; } ++ if (*state->pos.look != '=') ++ return show_parse_error(state, ERROR_PARSE); ++ state->pos.look++; /* '=' */ ++ skip_white(&state->pos); ++ if (!*state->pos.look) ++ return show_parse_error(state, ERROR_VALUE); + +- /* Mirror what we already have */ +- if (mirror) add_bytes_to_string(mirror, orig_pos, *file - orig_pos); ++ optname_copy = memacpy(optname_orig, optname_len); ++ if (!optname_copy) return show_parse_error(state, ERROR_NOMEM); + + /* Option value */ + { + struct option *opt; + unsigned char *val; ++ const struct conf_parsing_pos pos_before_value = state->pos; + +- opt = mirror ? get_opt_rec_real(opt_tree, optname) : get_opt_rec(opt_tree, optname); +- mem_free(optname); ++ opt = mirror ++ ? get_opt_rec_real(opt_tree, optname_copy) ++ : get_opt_rec(opt_tree, optname_copy); ++ mem_free(optname_copy); ++ optname_copy = NULL; + +- if (!opt || (opt->flags & OPT_HIDDEN)) ++ if (!opt || (opt->flags & OPT_HIDDEN)) { ++ 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) ++ if (!option_types[opt->type].read) { ++ show_parse_error(state, ERROR_VALUE); ++ skip_option_value(&state->pos); + return ERROR_VALUE; ++ } + +- val = option_types[opt->type].read(opt, file, line); +- if (!val) return ERROR_VALUE; ++ val = option_types[opt->type].read(opt, &state->pos.look, ++ &state->pos.line); ++ if (!val) { ++ /* The reader function failed. Jump back to ++ * the beginning of the value and skip it with ++ * the generic code. For the error message, ++ * use the line number at the beginning of the ++ * value, because the ending position is not ++ * interesting if there is an unclosed quote. */ ++ state->pos = pos_before_value; ++ show_parse_error(state, ERROR_VALUE); ++ skip_option_value(&state->pos); ++ return ERROR_VALUE; ++ } + +- if (mirror) { +- if (opt->flags & OPT_DELETED) +- opt->flags &= ~OPT_WATERMARK; ++ if (!mirror) { ++ /* loading a configuration file */ ++ if (!option_types[opt->type].set ++ || !option_types[opt->type].set(opt, val)) { ++ mem_free(val); ++ return show_parse_error(state, ERROR_VALUE); ++ } ++ } else if (is_system_conf) { ++ /* scanning a file that will not be rewritten */ ++ struct option *flagsite = indirect_option(opt); ++ ++ if (!(flagsite->flags & OPT_DELETED) ++ && option_types[opt->type].equals ++ && option_types[opt->type].equals(opt, val)) ++ flagsite->flags &= ~OPT_MUST_SAVE; + else +- opt->flags |= OPT_WATERMARK; +- if (option_types[opt->type].write) { ++ flagsite->flags |= OPT_MUST_SAVE; ++ } else { ++ /* rewriting a configuration file */ ++ struct option *flagsite = indirect_option(opt); ++ ++ if (flagsite->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; + } +- } else if (!option_types[opt->type].set +- || !option_types[opt->type].set(opt, val)) { +- mem_free(val); +- return ERROR_VALUE; ++ /* Remember that the option need not be ++ * written to the end of the file. */ ++ flagsite->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); + } + +@@ -159,49 +329,76 @@ parse_set(struct option *opt_tree, unsigned char **fil + } + + static enum parse_error +-parse_unset(struct option *opt_tree, unsigned char **file, int *line, ++parse_unset(struct option *opt_tree, struct conf_parsing_state *state, + struct string *mirror, int is_system_conf) + { +- unsigned char *orig_pos = *file; +- unsigned char *optname; +- unsigned char bin; ++ const unsigned char *optname_orig; ++ 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); + +- *file = skip_white(*file, line); +- if (!**file) return ERROR_PARSE; +- + /* Option name */ +- optname = *file; +- while (isident(**file) || **file == '*' || **file == '.' || **file == '+') +- (*file)++; ++ optname_orig = state->pos.look; ++ while (isident(*state->pos.look) || *state->pos.look == '*' ++ || *state->pos.look == '.' || *state->pos.look == '+') ++ state->pos.look++; ++ optname_len = state->pos.look - optname_orig; + +- bin = **file; +- **file = '\0'; +- optname = stracpy(optname); +- if (!optname) return ERROR_NOMEM; +- **file = bin; ++ optname_copy = memacpy(optname_orig, optname_len); ++ if (!optname_copy) return show_parse_error(state, ERROR_NOMEM); + +- /* Mirror what we have */ +- if (mirror) add_bytes_to_string(mirror, orig_pos, *file - orig_pos); +- + { + struct option *opt; + +- opt = get_opt_rec_real(opt_tree, optname); +- mem_free(optname); ++ opt = get_opt_rec_real(opt_tree, optname_copy); ++ mem_free(optname_copy); ++ optname_copy = NULL; + +- if (!opt || (opt->flags & OPT_HIDDEN)) +- return ERROR_OPTION; ++ if (!opt || (opt->flags & OPT_HIDDEN)) { ++ /* The user wanted to delete the option, and ++ * it has already been deleted; this is not an ++ * error. This might happen if a version of ++ * ELinks has a built-in URL rewriting rule, ++ * the user disables it, and a later version ++ * no longer has it. */ ++ return ERROR_NONE; ++ } + + if (!mirror) { ++ /* loading a configuration file */ + if (opt->flags & OPT_ALLOC) delete_option(opt); +- } else { +- if (opt->flags & OPT_DELETED) +- opt->flags |= OPT_WATERMARK; ++ else mark_option_as_deleted(opt); ++ } else if (is_system_conf) { ++ /* scanning a file that will not be rewritten */ ++ struct option *flagsite = indirect_option(opt); ++ ++ if (flagsite->flags & OPT_DELETED) ++ flagsite->flags &= ~OPT_MUST_SAVE; + else +- opt->flags &= ~OPT_WATERMARK; ++ flagsite->flags |= OPT_MUST_SAVE; ++ } else { ++ /* rewriting a configuration file */ ++ struct option *flagsite = indirect_option(opt); ++ ++ if (flagsite->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. */ ++ flagsite->flags &= ~OPT_MUST_SAVE; + } + } + +@@ -209,73 +406,90 @@ parse_unset(struct option *opt_tree, unsigned char **f + } + + static enum parse_error +-parse_bind(struct option *opt_tree, unsigned char **file, int *line, ++parse_bind(struct option *opt_tree, struct conf_parsing_state *state, + struct string *mirror, int is_system_conf) + { +- unsigned char *orig_pos = *file, *next_pos; + unsigned char *keymap, *keystroke, *action; + enum parse_error err = ERROR_NONE; ++ struct conf_parsing_pos before_error; + +- *file = skip_white(*file, line); +- if (!*file) return ERROR_PARSE; ++ skip_white(&state->pos); ++ if (!*state->pos.look) return show_parse_error(state, ERROR_PARSE); + + /* Keymap */ +- keymap = option_types[OPT_STRING].read(NULL, file, line); +- *file = skip_white(*file, line); +- if (!keymap || !**file) +- return ERROR_OPTION; ++ before_error = state->pos; ++ keymap = option_types[OPT_STRING].read(NULL, &state->pos.look, ++ &state->pos.line); ++ skip_white(&state->pos); ++ if (!keymap || !*state->pos.look) { ++ state->pos = before_error; ++ return show_parse_error(state, ERROR_PARSE); ++ } + + /* Keystroke */ +- keystroke = option_types[OPT_STRING].read(NULL, file, line); +- *file = skip_white(*file, line); +- if (!keystroke || !**file) { +- mem_free(keymap); +- return ERROR_OPTION; ++ before_error = state->pos; ++ keystroke = option_types[OPT_STRING].read(NULL, &state->pos.look, ++ &state->pos.line); ++ skip_white(&state->pos); ++ if (!keystroke || !*state->pos.look) { ++ mem_free(keymap); mem_free_if(keystroke); ++ state->pos = before_error; ++ return show_parse_error(state, ERROR_PARSE); + } + + /* Equal sign */ +- *file = skip_white(*file, line); +- if (**file != '=') { ++ skip_white(&state->pos); ++ if (*state->pos.look != '=') { + mem_free(keymap); mem_free(keystroke); +- return ERROR_PARSE; ++ return show_parse_error(state, ERROR_PARSE); + } +- (*file)++; /* '=' */ ++ state->pos.look++; /* '=' */ + +- *file = skip_white(*file, line); +- if (!**file) { ++ skip_white(&state->pos); ++ if (!*state->pos.look) { + mem_free(keymap); mem_free(keystroke); +- return ERROR_PARSE; ++ return show_parse_error(state, ERROR_PARSE); + } + + /* Action */ +- next_pos = *file; +- action = option_types[OPT_STRING].read(NULL, file, line); ++ before_error = state->pos; ++ action = option_types[OPT_STRING].read(NULL, &state->pos.look, ++ &state->pos.line); + if (!action) { +- mem_free(keymap); +- return ERROR_VALUE; ++ mem_free(keymap); mem_free(keystroke); ++ state->pos = before_error; ++ return show_parse_error(state, ERROR_PARSE); + } + +- if (mirror) { +- /* Mirror what we already have */ +- unsigned char *act_str = bind_act(keymap, keystroke); +- +- if (act_str) { +- add_bytes_to_string(mirror, orig_pos, +- next_pos - orig_pos); +- add_to_string(mirror, act_str); +- mem_free(act_str); +- } else { +- err = ERROR_VALUE; +- } +- } else { ++ if (!mirror) { ++ /* loading a configuration file */ + /* We don't bother to bind() if -default-keys. */ + if (!get_cmd_opt_bool("default-keys") + && bind_do(keymap, keystroke, action, is_system_conf)) { + /* bind_do() tried but failed. */ +- err = ERROR_VALUE; ++ err = show_parse_error(state, ERROR_VALUE); + } else { + err = ERROR_NONE; + } ++ } else if (is_system_conf) { ++ /* scanning a file that will not be rewritten */ ++ /* TODO */ ++ } else { ++ /* rewriting a configuration file */ ++ /* Mirror what we already have. If the keystroke has ++ * been unbound, then act_str is simply "none" and ++ * this does not require special handling. */ ++ unsigned char *act_str = bind_act(keymap, keystroke); ++ ++ if (act_str) { ++ add_bytes_to_string(mirror, state->mirrored, ++ before_error.look - state->mirrored); ++ add_to_string(mirror, act_str); ++ mem_free(act_str); ++ state->mirrored = state->pos.look; ++ } else { ++ err = show_parse_error(state, ERROR_VALUE); ++ } + } + mem_free(keymap); mem_free(keystroke); mem_free(action); + return err; +@@ -285,28 +499,32 @@ static int load_config_file(unsigned char *, unsigned + struct string *, int); + + static enum parse_error +-parse_include(struct option *opt_tree, unsigned char **file, int *line, ++parse_include(struct option *opt_tree, struct conf_parsing_state *state, + struct string *mirror, int is_system_conf) + { +- unsigned char *orig_pos = *file; + unsigned char *fname; + struct string dumbstring; ++ struct conf_parsing_pos before_error; + +- if (!init_string(&dumbstring)) return ERROR_NOMEM; ++ if (!init_string(&dumbstring)) ++ return show_parse_error(state, ERROR_NOMEM); + +- *file = skip_white(*file, line); +- if (!*file) return ERROR_PARSE; ++ skip_white(&state->pos); ++ if (!*state->pos.look) { ++ done_string(&dumbstring); ++ return show_parse_error(state, ERROR_PARSE); ++ } + + /* File name */ +- fname = option_types[OPT_STRING].read(NULL, file, line); ++ before_error = state->pos; ++ fname = option_types[OPT_STRING].read(NULL, &state->pos.look, ++ &state->pos.line); + if (!fname) { + done_string(&dumbstring); +- return ERROR_VALUE; ++ state->pos = before_error; ++ return show_parse_error(state, ERROR_PARSE); + } + +- /* Mirror what we already have */ +- if (mirror) add_bytes_to_string(mirror, orig_pos, *file - orig_pos); +- + /* We want load_config_file() to watermark stuff, but not to load + * anything, polluting our beloved options tree - thus, we will feed it + * with some dummy string which we will destroy later; still better +@@ -316,10 +534,11 @@ parse_include(struct option *opt_tree, unsigned char * + * CONFDIR/<otherfile> ;). --pasky */ + if (load_config_file(fname[0] == '/' ? (unsigned char *) "" + : elinks_home, +- fname, opt_tree, &dumbstring, is_system_conf)) { ++ fname, opt_tree, ++ mirror ? &dumbstring : NULL, 1)) { + done_string(&dumbstring); + mem_free(fname); +- return ERROR_VALUE; ++ return show_parse_error(state, ERROR_VALUE); + } + + done_string(&dumbstring); +@@ -329,13 +548,13 @@ parse_include(struct option *opt_tree, unsigned char * + + + struct parse_handler { +- unsigned char *command; ++ const unsigned char *command; + enum parse_error (*handler)(struct option *opt_tree, +- unsigned char **file, int *line, ++ struct conf_parsing_state *state, + struct string *mirror, int is_system_conf); + }; + +-static struct parse_handler parse_handlers[] = { ++static const struct parse_handler parse_handlers[] = { + { "set", parse_set }, + { "unset", parse_unset }, + { "bind", parse_bind }, +@@ -344,102 +563,113 @@ static struct parse_handler parse_handlers[] = { + }; + + +-enum parse_error +-parse_config_command(struct option *options, unsigned char **file, int *line, ++static enum parse_error ++parse_config_command(struct option *options, struct conf_parsing_state *state, + struct string *mirror, int is_system_conf) + { +- struct parse_handler *handler; ++ const struct parse_handler *handler; + ++ /* If we're mirroring, then everything up to this point must ++ * have already been mirrored. */ ++ assert(mirror == NULL || state->mirrored == state->pos.look); ++ if_assert_failed return show_parse_error(state, ERROR_PARSE); ++ + for (handler = parse_handlers; handler->command; + handler++) { + int cmdlen = strlen(handler->command); + +- if (!strncmp(*file, handler->command, cmdlen) +- && isspace((*file)[cmdlen])) { ++ if (!strncmp(state->pos.look, handler->command, cmdlen) ++ && isspace(state->pos.look[cmdlen])) { + enum parse_error err; +- struct string mirror2 = NULL_STRING; +- struct string *m2 = NULL; + +- /* Mirror what we already have */ +- if (mirror && init_string(&mirror2)) { +- m2 = &mirror2; +- add_bytes_to_string(m2, *file, cmdlen); +- } +- +- +- *file += cmdlen; +- err = handler->handler(options, file, line, m2, ++ state->pos.look += cmdlen; ++ err = handler->handler(options, state, mirror, + is_system_conf); +- if (!err && mirror && m2) { +- add_string_to_string(mirror, m2); ++ if (mirror) { ++ /* Mirror any characters that the handler ++ * consumed but did not already mirror. */ ++ add_bytes_to_string(mirror, state->mirrored, ++ state->pos.look - state->mirrored); ++ state->mirrored = state->pos.look; + } +- if (m2) done_string(m2); + return err; + } + } + +- return ERROR_COMMAND; ++ return show_parse_error(state, ERROR_COMMAND); + } + ++#ifdef CONFIG_EXMODE ++enum parse_error ++parse_config_exmode_command(unsigned char *cmd) ++{ ++ struct conf_parsing_state state = {{ 0 }}; ++ ++ state.pos.look = cmd; ++ state.pos.line = 0; ++ state.mirrored = NULL; /* not read because mirror is NULL too */ ++ state.filename = NULL; /* prevent error messages */ ++ ++ return parse_config_command(config_options, &state, NULL, 0); ++} ++#endif /* CONFIG_EXMODE */ ++ + void + parse_config_file(struct option *options, unsigned char *name, + unsigned char *file, struct string *mirror, + int is_system_conf) + { +- int line = 1; ++ struct conf_parsing_state state = {{ 0 }}; + int error_occurred = 0; +- enum parse_error err = 0; +- enum verbose_level verbose = get_cmd_opt_int("verbose"); +- unsigned char error_msg[][40] = { +- "no error", +- "parse error", +- "unknown command", +- "unknown option", +- "bad value", +- "no memory left", +- }; + +- while (file && *file) { +- unsigned char *orig_pos = file; ++ state.pos.look = file; ++ state.pos.line = 1; ++ state.mirrored = file; ++ if (!mirror && get_cmd_opt_int("verbose") >= VERBOSE_WARNINGS) ++ state.filename = name; + ++ while (state.pos.look && *state.pos.look) { ++ enum parse_error err = ERROR_NONE; ++ + /* Skip all possible comments and whitespace. */ +- file = skip_white(file, &line); ++ skip_white(&state.pos); + + /* Mirror what we already have */ +- if (mirror) +- add_bytes_to_string(mirror, orig_pos, file - orig_pos); ++ if (mirror) { ++ add_bytes_to_string(mirror, state.mirrored, ++ state.pos.look - state.mirrored); ++ state.mirrored = state.pos.look; ++ } + + /* Second chance to escape from the hell. */ +- if (!*file) break; ++ if (!*state.pos.look) break; + +- err = parse_config_command(options, &file, &line, mirror, ++ err = parse_config_command(options, &state, mirror, + is_system_conf); ++ switch (err) { ++ case ERROR_NONE: ++ break; + +- if (err == ERROR_COMMAND) { +- orig_pos = file; ++ case ERROR_COMMAND: ++ case ERROR_PARSE: + /* Jump over this crap we can't understand. */ +- while (!isspace(*file) && *file != '#' && *file) +- file++; ++ skip_to_unquoted_newline_or_comment(&state.pos); + + /* Mirror what we already have */ +- if (mirror) add_bytes_to_string(mirror, orig_pos, +- file - orig_pos); +- } +- +- if (!mirror && err) { +- /* TODO: Make this a macro and report error directly +- * as it's stumbled upon; line info may not be accurate +- * anymore now (?). --pasky */ +- if (verbose >= VERBOSE_WARNINGS) { +- fprintf(stderr, "%s:%d: %s\n", +- name, line, error_msg[err]); +- error_occurred = 1; ++ if (mirror) { ++ add_bytes_to_string(mirror, state.mirrored, ++ state.pos.look - state.mirrored); ++ state.mirrored = state.pos.look; + } +- err = 0; ++ ++ /* fall through */ ++ default: ++ error_occurred = 1; ++ break; + } + } + +- if (!error_occurred) return; ++ if (!error_occurred || !state.filename) return; + + /* If an error occurred make sure that the user is notified and is able + * to see it. First sound the bell. Then, if the text viewer is going to +@@ -543,7 +773,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) +@@ -570,12 +799,6 @@ smart_config_output_fn(struct string *string, struct o + 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; +@@ -695,25 +918,18 @@ create_config_string(unsigned char *prefix, unsigned c + + 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); + +- if (savestyle == 2) watermark_deleted_options(options->value.tree); +- + /* 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_( +@@ -723,7 +939,7 @@ create_config_string(unsigned char *prefix, unsigned c + "## 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" +@@ -780,8 +996,6 @@ create_config_string(unsigned char *prefix, unsigned c + done_string(&tmpstring); + + get_me_out: +- unmark_options_tree(options->value.tree); +- + return config.source; + } + +@@ -809,6 +1023,8 @@ write_config_file(unsigned char *prefix, unsigned char + if (ssi) { + secure_fputs(ssi, cfg_str); + ret = secure_close(ssi); ++ if (!ret) ++ untouch_options(options->value.tree); + } + + write_config_dialog(term, config_file, secsave_errno, ret); diff -urN elinks/patches/patch-src_config_conf_h elinks.new/patches/patch-src_config_conf_h --- elinks/patches/patch-src_config_conf_h Thu Jan 1 01:00:00 1970 +++ elinks.new/patches/patch-src_config_conf_h Tue Jul 15 17:06:34 2008 @@ -0,0 +1,17 @@ +$OpenBSD$ +--- src/config/conf.h.orig Fri Jun 20 22:19:54 2008 ++++ src/config/conf.h Tue Jul 15 16:56:22 2008 +@@ -14,10 +14,9 @@ enum parse_error { + }; + + void load_config(void); +-enum parse_error parse_config_command(struct option *options, +- unsigned char **file, int *line, +- struct string *mirror, +- int is_system_conf); ++#ifdef CONFIG_EXMODE ++enum parse_error parse_config_exmode_command(unsigned char *cmd); ++#endif + void parse_config_file(struct option *options, unsigned char *name, + unsigned char *file, struct string *mirror, + int is_system_conf); diff -urN elinks/patches/patch-src_config_options_c elinks.new/patches/patch-src_config_options_c --- elinks/patches/patch-src_config_options_c Thu Jan 1 01:00:00 1970 +++ elinks.new/patches/patch-src_config_options_c Tue Jul 15 17:06:34 2008 @@ -0,0 +1,128 @@ +$OpenBSD$ +--- src/config/options.c.orig Fri Jun 20 22:19:54 2008 ++++ src/config/options.c Tue Jul 15 16:56:22 2008 +@@ -157,7 +157,14 @@ debug_check_option_syntax(struct option *option) + /* Ugly kludge */ + static int no_autocreate = 0; + +-/* Get record of option of given name, or NULL if there's no such option. */ ++/** Get record of option of given name, or NULL if there's no such option. ++ * ++ * If the specified option is an ::OPT_ALIAS, this function returns the ++ * alias, rather than the option to which the alias refers. It must ++ * work this way because the alias may have the ::OPT_ALIAS_NEGATE flag. ++ * Instead, if the caller tries to read or set the value of the alias, ++ * the functions associated with ::OPT_ALIAS will forward the operation ++ * to the underlying option. However, see indirect_option(). */ + struct option * + get_opt_rec(struct option *tree, unsigned char *name_) + { +@@ -241,6 +248,27 @@ get_opt_rec_real(struct option *tree, unsigned char *n + return opt; + } + ++/** If @a opt is an alias, return the option to which it refers. ++ * ++ * @warning Because the alias may have the ::OPT_ALIAS_NEGATE flag, ++ * the caller must not access the value of the returned option as if ++ * it were also the value of the alias. However, it is safe to access ++ * flags such as ::OPT_MUST_SAVE and ::OPT_DELETED. */ ++struct option * ++indirect_option(struct option *alias) ++{ ++ struct option *real; ++ ++ if (alias->type != OPT_ALIAS) return alias; /* not an error */ ++ ++ real = get_opt_rec(config_options, alias->value.string); ++ assertm(real != NULL, "%s aliased to unknown option %s!", ++ alias->name, alias->value.string); ++ if_assert_failed return alias; ++ ++ return real; ++} ++ + /* Fetch pointer to value of certain option. It is guaranteed to never return + * NULL. Note that you are supposed to use wrapper get_opt(). */ + union option_value * +@@ -724,27 +752,35 @@ register_change_hooks(struct change_hook_info *change_ + } + + void +-unmark_options_tree(struct list_head *tree) ++prepare_mustsave_flags(struct list_head *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); + } + } + + void +-watermark_deleted_options(struct list_head *tree) ++untouch_options(struct list_head *tree) + { + struct option *option; + + foreach (option, *tree) { +- if (option->flags & OPT_DELETED) +- option->flags |= OPT_WATERMARK; +- else if (option->type == OPT_TREE) +- watermark_deleted_options(option->value.tree); ++ option->flags &= ~OPT_TOUCHED; ++ ++ if (option->type == OPT_TREE) ++ untouch_options(option->value.tree); + } + } + +@@ -757,7 +793,7 @@ check_nonempty_tree(struct list_head *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; + } + } +@@ -777,14 +813,14 @@ smart_config_string(struct string *str, int print_comm + 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 +@@ -850,10 +886,6 @@ smart_config_string(struct string *str, int print_comm + + fn(str, option, path, depth, /*pc*/1, 3, i18n); + } +- +- /* TODO: We should maybe clear the touched flag only when really +- * saving the stuff...? --pasky */ +- option->flags &= ~OPT_TOUCHED; + } + } + diff -urN elinks/patches/patch-src_config_options_h elinks.new/patches/patch-src_config_options_h --- elinks/patches/patch-src_config_options_h Thu Jan 1 01:00:00 1970 +++ elinks.new/patches/patch-src_config_options_h Tue Jul 15 17:06:34 2008 @@ -0,0 +1,65 @@ +$OpenBSD$ +--- src/config/options.h.orig Fri Jun 20 22:19:54 2008 ++++ src/config/options.h Tue Jul 15 16:56:22 2008 +@@ -24,15 +24,33 @@ 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 and any ++ * files named in "include" commands. ++ * - If the old configuration file contains a "set" or "unset" ++ * command for this option, ELinks rewrites the command and ++ * clears OPT_MUST_SAVE. ++ * - If an included file contains a "set" or "unset" command ++ * for this option, ELinks compares the value of the option ++ * to the value given in the command. ELinks clears ++ * OPT_MUST_SAVE if the values match, or sets it if they ++ * differ. ++ * - After ELinks has rewritten the configuration file and ++ * parsed the included files, 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. */ +@@ -150,8 +168,8 @@ extern void register_change_hooks(struct change_hook_i + + + extern struct list_head *init_options_tree(void); +-extern void unmark_options_tree(struct list_head *); +-void watermark_deleted_options(struct list_head *); ++extern void prepare_mustsave_flags(struct list_head *, int set_all); ++extern void untouch_options(struct list_head *); + + extern void smart_config_string(struct string *, int, int, struct list_head *, unsigned char *, int, + void (*)(struct string *, struct option *, unsigned char *, int, int, int, int)); +@@ -200,6 +218,7 @@ extern void checkout_option_values(struct option_resol + + extern struct option *get_opt_rec(struct option *, unsigned char *); + extern struct option *get_opt_rec_real(struct option *, unsigned char *); ++struct option *indirect_option(struct option *); + #ifdef CONFIG_DEBUG + extern union option_value *get_opt_(unsigned char *, int, enum option_type, struct option *, unsigned char *); + #define get_opt(tree, name, type) get_opt_(__FILE__, __LINE__, type, tree, name) diff -urN elinks/patches/patch-src_config_opttypes_c elinks.new/patches/patch-src_config_opttypes_c --- elinks/patches/patch-src_config_opttypes_c Thu Jan 1 01:00:00 1970 +++ elinks.new/patches/patch-src_config_opttypes_c Tue Jul 15 17:06:34 2008 @@ -0,0 +1,256 @@ +$OpenBSD$ +--- src/config/opttypes.c.orig Fri Jun 20 22:19:54 2008 ++++ src/config/opttypes.c Tue Jul 15 16:56:22 2008 +@@ -90,19 +90,6 @@ exec_cmd(struct option *o, unsigned char ***argv, int + * possibly changing ptr to structure containing target name and pointer to + * options list? --pasky */ + +-#define wrap_or_(name_, call_, ret_) \ +-{ \ +- struct option *real = get_opt_rec(config_options, opt->value.string); \ +- \ +- assertm(real, "%s aliased to unknown option %s!", opt->name, opt->value.string); \ +- if_assert_failed { return ret_; } \ +- \ +- if (option_types[real->type].name_) \ +- return option_types[real->type].call_; \ +- \ +- return ret_; \ +-} +- + static unsigned char * + redir_cmd(struct option *opt, unsigned char ***argv, int *argc) + { +@@ -124,8 +111,23 @@ redir_cmd(struct option *opt, unsigned char ***argv, i + + static unsigned char * + redir_rd(struct option *opt, unsigned char **file, int *line) +- wrap_or_(read, read(real, file, line), NULL); ++{ ++ struct option *real = get_opt_rec(config_options, opt->value.string); ++ unsigned char *ret = NULL; + ++ assertm(real != NULL, "%s aliased to unknown option %s!", opt->name, opt->value.string); ++ if_assert_failed { return ret; } ++ ++ if (option_types[real->type].read) { ++ ret = option_types[real->type].read(real, file, line); ++ if (ret && (opt->flags & OPT_ALIAS_NEGATE) && real->type == OPT_BOOL) { ++ *(long *) ret = !*(long *) ret; ++ } ++ } ++ ++ return ret; ++} ++ + static void + redir_wr(struct option *opt, struct string *string) + { +@@ -148,21 +150,42 @@ redir_set(struct option *opt, unsigned char *str) + if_assert_failed { return ret; } + + if (option_types[real->type].set) { +- ret = option_types[real->type].set(real, str); ++ long negated; ++ + if ((opt->flags & OPT_ALIAS_NEGATE) && real->type == OPT_BOOL) { +- real->value.number = !real->value.number; ++ negated = !*(long *) str; ++ str = (unsigned char *) &negated; + } ++ ret = option_types[real->type].set(real, str); + } + + return ret; + } + +- + static int +-redir_add(struct option *opt, unsigned char *str) +- wrap_or_(add, add(real, str), 0); ++redir_eq(struct option *opt, const unsigned char *str) ++{ ++ struct option *real = get_opt_rec(config_options, opt->value.string); ++ int ret = 0; + ++ assertm(real != NULL, "%s aliased to unknown option %s!", opt->name, opt->value.string); ++ if_assert_failed { return ret; } + ++ if (option_types[real->type].equals) { ++ long negated; ++ ++ if ((opt->flags & OPT_ALIAS_NEGATE) && real->type == OPT_BOOL) { ++ negated = !*(const long *) str; ++ str = (unsigned char *) &negated; ++ } ++ ret = option_types[real->type].equals(real, str); ++ } ++ ++ return ret; ++} ++ ++ ++ + /* Support functions for config file parsing. */ + + static void +@@ -206,6 +229,12 @@ num_set(struct option *opt, unsigned char *str) + return 1; + } + ++static int ++num_eq(struct option *opt, const unsigned char *str) ++{ ++ return str && opt->value.number == *(const long *) str; ++} ++ + static void + num_wr(struct option *option, struct string *string) + { +@@ -213,6 +242,25 @@ num_wr(struct option *option, struct string *string) + } + + ++static int ++long_set(struct option *opt, unsigned char *str) ++{ ++ opt->value.big_number = *((long *) str); ++ return 1; ++} ++ ++static int ++long_eq(struct option *opt, const unsigned char *str) ++{ ++ return str && opt->value.big_number == *(const long *) str; ++} ++ ++static void ++long_wr(struct option *option, struct string *string) ++{ ++ add_knum_to_string(string, option->value.big_number); ++} ++ + static unsigned char * + str_rd(struct option *opt, unsigned char **file, int *line) + { +@@ -234,14 +282,14 @@ str_rd(struct option *opt, unsigned char **file, int * + while (*str && (commandline || !isquote(*str))) { + if (*str == '\\') { + /* FIXME: This won't work on crlf systems. */ +- if (str[1] == '\n') { str[1] = ' '; str++; } ++ if (str[1] == '\n') { str[1] = ' '; str++; (*line)++; } + /* When there's quote char, we will just move on there, + * thus we will never test for it in while () condition + * and we will treat it just as '"', ignoring the + * backslash itself. */ +- if (isquote(str[1])) str++; ++ else if (isquote(str[1])) str++; + /* \\ means \. */ +- if (str[1] == '\\') str++; ++ else if (str[1] == '\\') str++; + } + + if (*str == '\n') (*line)++; +@@ -276,6 +324,12 @@ str_set(struct option *opt, unsigned char *str) + return 1; + } + ++static int ++str_eq(struct option *opt, const unsigned char *str) ++{ ++ return str && strcmp(opt->value.string, str) == 0; ++} ++ + static void + str_wr(struct option *o, struct string *s) + { +@@ -306,6 +360,12 @@ cp_set(struct option *opt, unsigned char *str) + return 1; + } + ++static int ++cp_eq(struct option *opt, const unsigned char *str) ++{ ++ return str && get_cp_index(str) == opt->value.number; ++} ++ + static void + cp_wr(struct option *o, struct string *s) + { +@@ -325,6 +385,16 @@ lang_set(struct option *opt, unsigned char *str) + return 1; + } + ++static int ++lang_eq(struct option *opt, const unsigned char *str) ++{ ++#ifdef CONFIG_NLS ++ return str && name_to_language(str) == opt->value.number; ++#else ++ return 1; /* All languages are the same. */ ++#endif ++} ++ + static void + lang_wr(struct option *o, struct string *s) + { +@@ -346,6 +416,15 @@ color_set(struct option *opt, unsigned char *str) + return !decode_color(str, strlen(str), &opt->value.color); + } + ++static int ++color_eq(struct option *opt, const unsigned char *str) ++{ ++ color_T color; ++ ++ return str && !decode_color(str, strlen(str), &color) ++ && color == opt->value.color; ++} ++ + static void + color_wr(struct option *opt, struct string *str) + { +@@ -386,21 +465,32 @@ tree_dup(struct option *opt, struct option *template) + } + + const struct option_type_info option_types[] = { +- { N_("Boolean"), bool_cmd, num_rd, num_wr, NULL, num_set, NULL, N_("[0|1]") }, +- { N_("Integer"), gen_cmd, num_rd, num_wr, NULL, num_set, NULL, N_("<num>") }, +- { N_("Longint"), gen_cmd, num_rd, num_wr, NULL, num_set, NULL, N_("<num>") }, +- { N_("String"), gen_cmd, str_rd, str_wr, str_dup, str_set, NULL, N_("<str>") }, ++ /* The OPT_ comments below are here to be found by grep. */ + +- { N_("Codepage"), gen_cmd, str_rd, cp_wr, NULL, cp_set, NULL, N_("<codepage>") }, +- { N_("Language"), gen_cmd, str_rd, lang_wr, NULL, lang_set, NULL, N_("<language>") }, +- { N_("Color"), gen_cmd, str_rd, color_wr, NULL, color_set, NULL, N_("<color|#rrggbb>") }, ++ /* OPT_BOOL */ ++ { N_("Boolean"), bool_cmd, num_rd, num_wr, NULL, num_set, num_eq, N_("[0|1]") }, ++ /* OPT_INT */ ++ { N_("Integer"), gen_cmd, num_rd, num_wr, NULL, num_set, num_eq, N_("<num>") }, ++ /* OPT_LONG */ ++ { N_("Longint"), gen_cmd, num_rd, long_wr, NULL, long_set, long_eq, N_("<num>") }, ++ /* OPT_STRING */ ++ { N_("String"), gen_cmd, str_rd, str_wr, str_dup, str_set, str_eq, N_("<str>") }, + +- { N_("Special"), exec_cmd, NULL, NULL, NULL, NULL, NULL, "" }, ++ /* OPT_CODEPAGE */ ++ { N_("Codepage"), gen_cmd, str_rd, cp_wr, NULL, cp_set, cp_eq, N_("<codepage>") }, ++ /* OPT_LANGUAGE */ ++ { N_("Language"), gen_cmd, str_rd, lang_wr, NULL, lang_set, lang_eq, N_("<language>") }, ++ /* OPT_COLOR */ ++ { N_("Color"), gen_cmd, str_rd, color_wr, NULL, color_set, color_eq, N_("<color|#rrggbb>") }, + +- { N_("Alias"), redir_cmd, redir_rd, redir_wr, NULL, redir_set, redir_add, "" }, ++ /* OPT_COMMAND */ ++ { N_("Special"), exec_cmd, NULL, NULL, NULL, NULL, NULL, "" }, + +- /* tree */ +- { N_("Folder"), NULL, NULL, NULL, tree_dup, NULL, NULL, "" }, ++ /* OPT_ALIAS */ ++ { N_("Alias"), redir_cmd, redir_rd, redir_wr, NULL, redir_set, redir_eq, "" }, ++ ++ /* OPT_TREE */ ++ { N_("Folder"), NULL, NULL, NULL, tree_dup, NULL, NULL, "" }, + }; + + unsigned char * diff -urN elinks/patches/patch-src_config_opttypes_h elinks.new/patches/patch-src_config_opttypes_h --- elinks/patches/patch-src_config_opttypes_h Thu Jan 1 01:00:00 1970 +++ elinks.new/patches/patch-src_config_opttypes_h Tue Jul 15 17:06:34 2008 @@ -0,0 +1,12 @@ +$OpenBSD$ +--- src/config/opttypes.h.orig Fri Jun 20 22:19:54 2008 ++++ src/config/opttypes.h Tue Jul 15 16:56:22 2008 +@@ -11,7 +11,7 @@ struct option_type_info { + void (*write)(struct option *, struct string *); + void (*dup)(struct option *, struct option *); + int (*set)(struct option *, unsigned char *); +- int (*add)(struct option *, unsigned char *); ++ int (*equals)(struct option *, const unsigned char *); + unsigned char *help_str; + }; + diff -urN elinks/patches/patch-src_dialogs_exmode_c elinks.new/patches/patch-src_dialogs_exmode_c --- elinks/patches/patch-src_dialogs_exmode_c Thu Jan 1 01:00:00 1970 +++ elinks.new/patches/patch-src_dialogs_exmode_c Tue Jul 15 17:06:34 2008 @@ -0,0 +1,21 @@ +$OpenBSD$ +--- src/dialogs/exmode.c.orig Fri Jun 20 22:19:54 2008 ++++ src/dialogs/exmode.c Tue Jul 15 16:56:22 2008 +@@ -63,7 +63,6 @@ static int + exmode_confcmd_handler(struct session *ses, unsigned char *command, + unsigned char *args) + { +- int dummyline = 0; + enum parse_error err; + + assert(ses && command && args); +@@ -74,8 +73,7 @@ exmode_confcmd_handler(struct session *ses, unsigned c + /* Undo the arguments separation. */ + if (*args) *(--args) = ' '; + +- err = parse_config_command(config_options, &command, &dummyline, NULL, +- 0); ++ err = parse_config_exmode_command(command); + return err; + } + diff -urN elinks/patches/patch-src_protocol_http_http_c elinks.new/patches/patch-src_protocol_http_http_c --- elinks/patches/patch-src_protocol_http_http_c Thu Jan 1 01:00:00 1970 +++ elinks.new/patches/patch-src_protocol_http_http_c Tue Jul 15 17:06:34 2008 @@ -0,0 +1,12 @@ +$OpenBSD$ +--- src/protocol/http/http.c.orig Fri Jun 20 22:19:55 2008 ++++ src/protocol/http/http.c Tue Jul 15 16:56:22 2008 +@@ -1423,7 +1423,7 @@ http_got_header(struct socket *socket, struct read_buf + #endif + unsigned char *d; + struct uri *uri = conn->proxied_uri; /* Set to the real uri */ +- struct http_version version; ++ struct http_version version = { 0, 9 }; + enum connection_state state = (conn->state != S_PROC ? S_GETH : S_PROC); + int a, h = 200; + int cf; diff -urN elinks/patches/patch-src_scripting_lua_core_c elinks.new/patches/patch-src_scripting_lua_core_c --- elinks/patches/patch-src_scripting_lua_core_c Tue Jul 15 17:06:54 2008 +++ elinks.new/patches/patch-src_scripting_lua_core_c Tue Jul 15 17:06:34 2008 @@ -1,7 +1,7 @@ $OpenBSD: patch-src_scripting_lua_core_c,v 1.1 2006/10/21 17:56:48 jasper Exp $ ---- src/scripting/lua/core.c.orig Sun Jan 29 08:10:39 2006 -+++ src/scripting/lua/core.c Thu Oct 19 14:10:34 2006 -@@ -633,7 +633,7 @@ do_hooks_file(LS, unsigned char *prefix, +--- src/scripting/lua/core.c.orig Fri Jun 20 22:19:55 2008 ++++ src/scripting/lua/core.c Tue Jul 15 16:20:43 2008 +@@ -641,7 +641,7 @@ do_hooks_file(LS, unsigned char *prefix, unsigned char if (file_can_read(file)) { int oldtop = lua_gettop(S); @@ -10,7 +10,7 @@ sleep(3); /* Let some time to see error messages. */ lua_settop(S, oldtop); } -@@ -644,13 +644,24 @@ do_hooks_file(LS, unsigned char *prefix, +@@ -652,13 +652,24 @@ do_hooks_file(LS, unsigned char *prefix, unsigned char void init_lua(struct module *module) { @@ -40,7 +40,7 @@ lua_register(L, LUA_ALERT, l_alert); lua_register(L, "current_url", l_current_url); -@@ -755,7 +766,7 @@ handle_ret_eval(struct session *ses) +@@ -763,7 +774,7 @@ handle_ret_eval(struct session *ses) int oldtop = lua_gettop(L); if (prepare_lua(ses) == 0) { diff -urN elinks/pkg/PLIST elinks.new/pkg/PLIST --- elinks/pkg/PLIST Tue Jul 15 17:06:54 2008 +++ elinks.new/pkg/PLIST Tue Jul 15 17:06:34 2008 @@ -1,5 +1,5 @@ @comment $OpenBSD: PLIST,v 1.2 2006/01/29 15:41:00 sturm Exp $ -bin/elinks [EMAIL PROTECTED] bin/elinks @comment lib/charset.alias @man man/man1/elinks.1 @man man/man5/elinks.conf.5