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

Reply via email to