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 *@line 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
+@bin bin/elinks
 @comment lib/charset.alias
 @man man/man1/elinks.1
 @man man/man5/elinks.conf.5
