Enable Gold linker for cross-*-binutils build
[platform/upstream/binutils.git] / gdb / charset.c
index 0062e28..bc7bd65 100644 (file)
@@ -1,12 +1,12 @@
 /* Character set conversion support for GDB.
 
-   Copyright 2001, 2003 Free Software Foundation, Inc.
+   Copyright (C) 2001-2014 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 #include "charset.h"
 #include "gdbcmd.h"
-#include "gdb_assert.h"
-
-#include <stddef.h>
-#include "gdb_string.h"
+#include "gdb_obstack.h"
+#include "gdb_wait.h"
+#include "charset-list.h"
+#include "vec.h"
+#include "environ.h"
+#include "arch-utils.h"
+#include "gdb_vecs.h"
 #include <ctype.h>
 
-#ifdef HAVE_ICONV
-#include <iconv.h>
+#ifdef USE_WIN32API
+#include <windows.h>
 #endif
-
 \f
 /* How GDB's character set support works
 
-   GDB has two global settings:
+   GDB has three global settings:
 
    - The `current host character set' is the character set GDB should
      use in talking to the user, and which (hopefully) the user's
-     terminal knows how to display properly.
+     terminal knows how to display properly.  Most users should not
+     change this.
 
    - The `current target character set' is the character set the
      program being debugged uses.
 
+   - The `current target wide character set' is the wide character set
+     the program being debugged uses, that is, the encoding used for
+     wchar_t.
+
    There are commands to set each of these, and mechanisms for
    choosing reasonable default values.  GDB has a global list of
    character sets that it can use as its host or target character
      characters the user enters in expressions (mostly host->target
      conversions),
 
-   and so on.
-
-   Now, many of these operations are specific to a particular
-   host/target character set pair.  If GDB supports N character sets,
-   there are N^2 possible pairs.  This means that, the larger GDB's
-   repertoire of character sets gets, the more expensive it gets to add
-   new character sets.
-
-   To make sure that GDB can do the right thing for every possible
-   pairing of host and target character set, while still allowing
-   GDB's repertoire to scale, we use a two-tiered approach:
-
-   - We maintain a global table of "translations" --- groups of
-     functions specific to a particular pair of character sets.
-
-   - However, a translation can be incomplete: some functions can be
-     omitted.  Where there is not a translation to specify exactly
-     what function to use, we provide reasonable defaults.  The
-     default behaviors try to use the "iconv" library functions, which
-     support a wide range of character sets.  However, even if iconv
-     is not available, there are fallbacks to support trivial
-     translations: when the host and target character sets are the
-     same.  */
+     and so on.
+     
+   To avoid excessive code duplication and maintenance efforts,
+   GDB simply requires a capable iconv function.  Users on platforms
+   without a suitable iconv can use the GNU iconv library.  */
 
 \f
-/* The character set and translation structures.  */
+#ifdef PHONY_ICONV
 
+/* Provide a phony iconv that does as little as possible.  Also,
+   arrange for there to be a single available character set.  */
 
-/* A character set GDB knows about.  GDB only supports character sets
-   with stateless encodings, in which every character is one byte
-   long.  */
-struct charset {
+#undef GDB_DEFAULT_HOST_CHARSET
+#define GDB_DEFAULT_HOST_CHARSET "ISO-8859-1"
+#define GDB_DEFAULT_TARGET_CHARSET "ISO-8859-1"
+#define GDB_DEFAULT_TARGET_WIDE_CHARSET "ISO-8859-1"
+#undef DEFAULT_CHARSET_NAMES
+#define DEFAULT_CHARSET_NAMES GDB_DEFAULT_HOST_CHARSET ,
+
+#undef iconv_t
+#define iconv_t int
+#undef iconv_open
+#define iconv_open phony_iconv_open
+#undef iconv
+#define iconv phony_iconv
+#undef iconv_close
+#define iconv_close phony_iconv_close
+
+#undef ICONV_CONST
+#define ICONV_CONST const
+
+/* Some systems don't have EILSEQ, so we define it here, but not as
+   EINVAL, because callers of `iconv' want to distinguish EINVAL and
+   EILSEQ.  This is what iconv.h from libiconv does as well.  Note
+   that wchar.h may also define EILSEQ, so this needs to be after we
+   include wchar.h, which happens in defs.h through gdb_wchar.h.  */
+#ifndef EILSEQ
+#define EILSEQ ENOENT
+#endif
 
-  /* A singly-linked list of all known charsets.  */
-  struct charset *next;
+static iconv_t
+phony_iconv_open (const char *to, const char *from)
+{
+  /* We allow conversions from UTF-32BE, wchar_t, and the host charset.
+     We allow conversions to wchar_t and the host charset.  */
+  if (strcmp (from, "UTF-32BE") && strcmp (from, "wchar_t")
+      && strcmp (from, GDB_DEFAULT_HOST_CHARSET))
+    return -1;
+  if (strcmp (to, "wchar_t") && strcmp (to, GDB_DEFAULT_HOST_CHARSET))
+    return -1;
 
-  /* The name of the character set.  Comparisons on character set
-     names are case-sensitive.  */
-  const char *name;
+  /* Return 1 if we are converting from UTF-32BE, 0 otherwise.  This is
+     used as a flag in calls to iconv.  */
+  return !strcmp (from, "UTF-32BE");
+}
 
-  /* Non-zero iff this character set can be used as a host character
-     set.  At present, GDB basically assumes that the host character
-     set is a superset of ASCII.  */
-  int valid_host_charset;
+static int
+phony_iconv_close (iconv_t arg)
+{
+  return 0;
+}
 
-  /* Pointers to charset-specific functions that depend only on a
-     single character set, and data pointers to pass to them.  */
-  int (*host_char_print_literally) (void *baton,
-                                    int host_char);
-  void *host_char_print_literally_baton;
+static size_t
+phony_iconv (iconv_t utf_flag, const char **inbuf, size_t *inbytesleft,
+            char **outbuf, size_t *outbytesleft)
+{
+  if (utf_flag)
+    {
+      while (*inbytesleft >= 4)
+       {
+         size_t j;
+         unsigned long c = 0;
+
+         for (j = 0; j < 4; ++j)
+           {
+             c <<= 8;
+             c += (*inbuf)[j] & 0xff;
+           }
+
+         if (c >= 256)
+           {
+             errno = EILSEQ;
+             return -1;
+           }
+         **outbuf = c & 0xff;
+         ++*outbuf;
+         --*outbytesleft;
+
+         ++*inbuf;
+         *inbytesleft -= 4;
+       }
+      if (*inbytesleft < 4)
+       {
+         errno = EINVAL;
+         return -1;
+       }
+    }
+  else
+    {
+      /* In all other cases we simply copy input bytes to the
+        output.  */
+      size_t amt = *inbytesleft;
+
+      if (amt > *outbytesleft)
+       amt = *outbytesleft;
+      memcpy (*outbuf, *inbuf, amt);
+      *inbuf += amt;
+      *outbuf += amt;
+      *inbytesleft -= amt;
+      *outbytesleft -= amt;
+    }
 
-  int (*target_char_to_control_char) (void *baton,
-                                      int target_char,
-                                      int *target_ctrl_char);
-  void *target_char_to_control_char_baton;
-};
+  if (*inbytesleft)
+    {
+      errno = E2BIG;
+      return -1;
+    }
 
+  /* The number of non-reversible conversions -- but they were all
+     reversible.  */
+  return 0;
+}
 
-/* A translation from one character set to another.  */
-struct translation {
-
-  /* A singly-linked list of all known translations.  */
-  struct translation *next;
-
-  /* This structure describes functions going from the FROM character
-     set to the TO character set.  Comparisons on character set names
-     are case-sensitive.  */
-  const char *from, *to;
-
-  /* Pointers to translation-specific functions, and data pointers to
-     pass to them.  These pointers can be zero, indicating that GDB
-     should fall back on the default behavior.  We hope the default
-     behavior will be correct for many from/to pairs, reducing the
-     number of translations that need to be registered explicitly.  */
-  
-  /* TARGET_CHAR is in the `from' charset.
-     Returns a string in the `to' charset.  */
-  const char *(*c_target_char_has_backslash_escape) (void *baton,
-                                                     int target_char);
-  void *c_target_char_has_backslash_escape_baton;
-
-  /* HOST_CHAR is in the `from' charset.
-     TARGET_CHAR points to a char in the `to' charset.  */
-  int (*c_parse_backslash) (void *baton, int host_char, int *target_char);
-  void *c_parse_backslash_baton;
-
-  /* This is used for the host_char_to_target and target_char_to_host
-     functions.  */
-  int (*convert_char) (void *baton, int from, int *to);
-  void *convert_char_baton;
-};
+#endif
 
 
 \f
 /* The global lists of character sets and translations.  */
 
 
-#ifndef GDB_DEFAULT_HOST_CHARSET
-#define GDB_DEFAULT_HOST_CHARSET "ISO-8859-1"
-#endif
-
 #ifndef GDB_DEFAULT_TARGET_CHARSET
 #define GDB_DEFAULT_TARGET_CHARSET "ISO-8859-1"
 #endif
 
-static const char *host_charset_name = GDB_DEFAULT_HOST_CHARSET;
-static const char *target_charset_name = GDB_DEFAULT_TARGET_CHARSET;
+#ifndef GDB_DEFAULT_TARGET_WIDE_CHARSET
+#define GDB_DEFAULT_TARGET_WIDE_CHARSET "UTF-32"
+#endif
 
-static const char *host_charset_enum[] = 
+static const char *auto_host_charset_name = GDB_DEFAULT_HOST_CHARSET;
+static const char *host_charset_name = "auto";
+static void
+show_host_charset_name (struct ui_file *file, int from_tty,
+                       struct cmd_list_element *c,
+                       const char *value)
 {
-  "ASCII",
-  "ISO-8859-1",
-  0
-};
+  if (!strcmp (value, "auto"))
+    fprintf_filtered (file,
+                     _("The host character set is \"auto; currently %s\".\n"),
+                     auto_host_charset_name);
+  else
+    fprintf_filtered (file, _("The host character set is \"%s\".\n"), value);
+}
 
-static const char *target_charset_enum[] = 
+static const char *target_charset_name = "auto";
+static void
+show_target_charset_name (struct ui_file *file, int from_tty,
+                         struct cmd_list_element *c, const char *value)
 {
-  "ASCII",
-  "ISO-8859-1",
-  "EBCDIC-US",
-  "IBM1047",
-  0
-};
-
-/* The global list of all the charsets GDB knows about.  */
-static struct charset *all_charsets;
-
+  if (!strcmp (value, "auto"))
+    fprintf_filtered (file,
+                     _("The target character set is \"auto; "
+                       "currently %s\".\n"),
+                     gdbarch_auto_charset (get_current_arch ()));
+  else
+    fprintf_filtered (file, _("The target character set is \"%s\".\n"),
+                     value);
+}
 
+static const char *target_wide_charset_name = "auto";
 static void
-register_charset (struct charset *cs)
+show_target_wide_charset_name (struct ui_file *file, 
+                              int from_tty,
+                              struct cmd_list_element *c, 
+                              const char *value)
 {
-  struct charset **ptr;
-
-  /* Put the new charset on the end, so that the list ends up in the
-     same order as the registrations in the _initialize function.  */
-  for (ptr = &all_charsets; *ptr; ptr = &(*ptr)->next)
-    ;
-
-  cs->next = 0;
-  *ptr = cs;
+  if (!strcmp (value, "auto"))
+    fprintf_filtered (file,
+                     _("The target wide character set is \"auto; "
+                       "currently %s\".\n"),
+                     gdbarch_auto_wide_charset (get_current_arch ()));
+  else
+    fprintf_filtered (file, _("The target wide character set is \"%s\".\n"),
+                     value);
 }
 
-
-static struct charset *
-lookup_charset (const char *name)
+static const char *default_charset_names[] =
 {
-  struct charset *cs;
-
-  for (cs = all_charsets; cs; cs = cs->next)
-    if (! strcmp (name, cs->name))
-      return cs;
+  DEFAULT_CHARSET_NAMES
+  0
+};
 
-  return NULL;
-}
+static const char **charset_enum;
 
+\f
+/* If the target wide character set has big- or little-endian
+   variants, these are the corresponding names.  */
+static const char *target_wide_charset_be_name;
+static const char *target_wide_charset_le_name;
 
-/* The global list of translations.  */
-static struct translation *all_translations;
+/* The architecture for which the BE- and LE-names are valid.  */
+static struct gdbarch *be_le_arch;
 
+/* A helper function which sets the target wide big- and little-endian
+   character set names, if possible.  */
 
 static void
-register_translation (struct translation *t)
+set_be_le_names (struct gdbarch *gdbarch)
 {
-  t->next = all_translations;
-  all_translations = t;
-}
+  int i, len;
+  const char *target_wide;
 
+  if (be_le_arch == gdbarch)
+    return;
+  be_le_arch = gdbarch;
 
-static struct translation *
-lookup_translation (const char *from, const char *to)
-{
-  struct translation *t;
+  target_wide_charset_le_name = NULL;
+  target_wide_charset_be_name = NULL;
 
-  for (t = all_translations; t; t = t->next)
-    if (! strcmp (from, t->from)
-        && ! strcmp (to, t->to))
-      return t;
+  target_wide = target_wide_charset_name;
+  if (!strcmp (target_wide, "auto"))
+    target_wide = gdbarch_auto_wide_charset (gdbarch);
 
-  return 0;
+  len = strlen (target_wide);
+  for (i = 0; charset_enum[i]; ++i)
+    {
+      if (strncmp (target_wide, charset_enum[i], len))
+       continue;
+      if ((charset_enum[i][len] == 'B'
+          || charset_enum[i][len] == 'L')
+         && charset_enum[i][len + 1] == 'E'
+         && charset_enum[i][len + 2] == '\0')
+       {
+         if (charset_enum[i][len] == 'B')
+           target_wide_charset_be_name = charset_enum[i];
+         else
+           target_wide_charset_le_name = charset_enum[i];
+       }
+    }
 }
 
+/* 'Set charset', 'set host-charset', 'set target-charset', 'set
+   target-wide-charset', 'set charset' sfunc's.  */
 
-\f
-/* Constructing charsets.  */
-
-/* Allocate, initialize and return a straightforward charset.
-   Use this function, rather than creating the structures yourself,
-   so that we can add new fields to the structure in the future without
-   having to tweak all the old charset descriptions.  */
-static struct charset *
-simple_charset (const char *name,
-                int valid_host_charset,
-                int (*host_char_print_literally) (void *baton, int host_char),
-                void *host_char_print_literally_baton,
-                int (*target_char_to_control_char) (void *baton,
-                                                    int target_char,
-                                                    int *target_ctrl_char),
-                void *target_char_to_control_char_baton)
+static void
+validate (struct gdbarch *gdbarch)
 {
-  struct charset *cs = xmalloc (sizeof (*cs));
-
-  memset (cs, 0, sizeof (*cs));
-  cs->name = name;
-  cs->valid_host_charset = valid_host_charset;
-  cs->host_char_print_literally = host_char_print_literally;
-  cs->host_char_print_literally_baton = host_char_print_literally_baton;
-  cs->target_char_to_control_char = target_char_to_control_char;
-  cs->target_char_to_control_char_baton = target_char_to_control_char_baton;
-
-  return cs;
+  iconv_t desc;
+  const char *host_cset = host_charset ();
+  const char *target_cset = target_charset (gdbarch);
+  const char *target_wide_cset = target_wide_charset_name;
+
+  if (!strcmp (target_wide_cset, "auto"))
+    target_wide_cset = gdbarch_auto_wide_charset (gdbarch);
+
+  desc = iconv_open (target_wide_cset, host_cset);
+  if (desc == (iconv_t) -1)
+    error (_("Cannot convert between character sets `%s' and `%s'"),
+          target_wide_cset, host_cset);
+  iconv_close (desc);
+
+  desc = iconv_open (target_cset, host_cset);
+  if (desc == (iconv_t) -1)
+    error (_("Cannot convert between character sets `%s' and `%s'"),
+          target_cset, host_cset);
+  iconv_close (desc);
+
+  /* Clear the cache.  */
+  be_le_arch = NULL;
 }
 
-
-\f
-/* ASCII functions.  */
-
-static int
-ascii_print_literally (void *baton, int c)
+/* This is the sfunc for the 'set charset' command.  */
+static void
+set_charset_sfunc (char *charset, int from_tty, 
+                  struct cmd_list_element *c)
 {
-  c &= 0xff;
-
-  return (0x20 <= c && c <= 0x7e);
+  /* CAREFUL: set the target charset here as well.  */
+  target_charset_name = host_charset_name;
+  validate (get_current_arch ());
 }
 
-
-static int
-ascii_to_control (void *baton, int c, int *ctrl_char)
+/* 'set host-charset' command sfunc.  We need a wrapper here because
+   the function needs to have a specific signature.  */
+static void
+set_host_charset_sfunc (char *charset, int from_tty,
+                       struct cmd_list_element *c)
 {
-  *ctrl_char = (c & 037);
-  return 1;
+  validate (get_current_arch ());
 }
 
-\f
-/* ISO-8859 family functions.  */
-
-
-static int
-iso_8859_print_literally (void *baton, int c)
+/* Wrapper for the 'set target-charset' command.  */
+static void
+set_target_charset_sfunc (char *charset, int from_tty,
+                         struct cmd_list_element *c)
 {
-  c &= 0xff;
-
-  return ((0x20 <= c && c <= 0x7e) /* ascii printables */
-          || (! sevenbit_strings && 0xA0 <= c)); /* iso 8859 printables */
+  validate (get_current_arch ());
 }
 
-
-static int
-iso_8859_to_control (void *baton, int c, int *ctrl_char)
+/* Wrapper for the 'set target-wide-charset' command.  */
+static void
+set_target_wide_charset_sfunc (char *charset, int from_tty,
+                              struct cmd_list_element *c)
 {
-  *ctrl_char = (c & 0200) | (c & 037);
-  return 1;
+  validate (get_current_arch ());
 }
 
-
-/* Construct an ISO-8859-like character set.  */
-static struct charset *
-iso_8859_family_charset (const char *name)
+/* sfunc for the 'show charset' command.  */
+static void
+show_charset (struct ui_file *file, int from_tty, 
+             struct cmd_list_element *c,
+             const char *name)
 {
-  return simple_charset (name, 1,
-                         iso_8859_print_literally, 0,
-                         iso_8859_to_control, 0);
+  show_host_charset_name (file, from_tty, c, host_charset_name);
+  show_target_charset_name (file, from_tty, c, target_charset_name);
+  show_target_wide_charset_name (file, from_tty, c, 
+                                target_wide_charset_name);
 }
 
-
 \f
-/* EBCDIC family functions.  */
-
+/* Accessor functions.  */
 
-static int
-ebcdic_print_literally (void *baton, int c)
+const char *
+host_charset (void)
 {
-  c &= 0xff;
-
-  return (64 <= c && c <= 254);
+  if (!strcmp (host_charset_name, "auto"))
+    return auto_host_charset_name;
+  return host_charset_name;
 }
 
-
-static int
-ebcdic_to_control (void *baton, int c, int *ctrl_char)
+const char *
+target_charset (struct gdbarch *gdbarch)
 {
-  /* There are no control character equivalents in EBCDIC.  Use
-     numeric escapes.  */
-  return 0;
+  if (!strcmp (target_charset_name, "auto"))
+    return gdbarch_auto_charset (gdbarch);
+  return target_charset_name;
 }
 
-
-/* Construct an EBCDIC-like character set.  */
-static struct charset *
-ebcdic_family_charset (const char *name)
+const char *
+target_wide_charset (struct gdbarch *gdbarch)
 {
-  return simple_charset (name, 0,
-                         ebcdic_print_literally, 0,
-                         ebcdic_to_control, 0);
-}
-                
-
-
-
-\f
-/* Fallback functions using iconv.  */
-
-#if defined(HAVE_ICONV)
-
-struct cached_iconv {
-  struct charset *from, *to;
-  iconv_t i;
-};
-
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
 
-/* Make sure the iconv cache *CI contains an iconv descriptor
-   translating from FROM to TO.  If it already does, fine; otherwise,
-   close any existing descriptor, and open up a new one.  On success,
-   return zero; on failure, return -1 and set errno.  */
-static int
-check_iconv_cache (struct cached_iconv *ci,
-                   struct charset *from,
-                   struct charset *to)
-{
-  iconv_t i;
-
-  /* Does the cached iconv descriptor match the conversion we're trying
-     to do now?  */
-  if (ci->from == from
-      && ci->to == to
-      && ci->i != (iconv_t) 0)
-    return 0;
-
-  /* It doesn't.  If we actually had any iconv descriptor open at
-     all, close it now.  */
-  if (ci->i != (iconv_t) 0)
+  set_be_le_names (gdbarch);
+  if (byte_order == BFD_ENDIAN_BIG)
     {
-      i = ci->i;
-      ci->i = (iconv_t) 0;
-      
-      if (iconv_close (i) == -1)
-        error ("Error closing `iconv' descriptor for "
-               "`%s'-to-`%s' character conversion: %s",
-               ci->from->name, ci->to->name, safe_strerror (errno));
+      if (target_wide_charset_be_name)
+       return target_wide_charset_be_name;
     }
-
-  /* Open a new iconv descriptor for the required conversion.  */
-  i = iconv_open (to->name, from->name);
-  if (i == (iconv_t) -1)
-    return -1;
-
-  ci->i = i;
-  ci->from = from;
-  ci->to = to;
-
-  return 0;
-}
-
-
-/* Convert FROM_CHAR using the cached iconv conversion *CI.  Return
-   non-zero if the conversion was successful, zero otherwise.  */
-static int
-cached_iconv_convert (struct cached_iconv *ci, int from_char, int *to_char)
-{
-  char from;
-  ICONV_CONST char *from_ptr = &from;
-  char to, *to_ptr = &to;
-  size_t from_left = sizeof (from), to_left = sizeof (to);
-
-  gdb_assert (ci->i != (iconv_t) 0);
-
-  from = from_char;
-  if (iconv (ci->i, &from_ptr, &from_left, &to_ptr, &to_left)
-      == (size_t) -1)
+  else
     {
-      /* These all suggest that the input or output character sets
-         have multi-byte encodings of some characters, which means
-         it's unsuitable for use as a GDB character set.  We should
-         never have selected it.  */
-      gdb_assert (errno != E2BIG && errno != EINVAL);
-
-      /* This suggests a bug in the code managing *CI.  */
-      gdb_assert (errno != EBADF);
-
-      /* This seems to mean that there is no equivalent character in
-         the `to' character set.  */
-      if (errno == EILSEQ)
-        return 0;
-
-      /* Anything else is mysterious.  */
-      internal_error ("Error converting character `%d' from `%s' to `%s' "
-                      "character set: %s",
-                      from_char, ci->from->name, ci->to->name,
-                      safe_strerror (errno));
+      if (target_wide_charset_le_name)
+       return target_wide_charset_le_name;
     }
 
-  /* If the pointers weren't advanced across the input, that also
-     suggests something was wrong.  */
-  gdb_assert (from_left == 0 && to_left == 0);
+  if (!strcmp (target_wide_charset_name, "auto"))
+    return gdbarch_auto_wide_charset (gdbarch);
 
-  *to_char = (unsigned char) to;
-  return 1;
+  return target_wide_charset_name;
 }
 
-
-static void
-register_iconv_charsets (void)
-{
-  /* Here we should check whether various character sets were
-     recognized by the local iconv implementation.
-
-     The first implementation registered a bunch of character sets
-     recognized by iconv, but then we discovered that iconv on Solaris
-     and iconv on GNU/Linux had no character sets in common.  So we
-     replaced them with the hard-coded tables that appear later in the
-     file.  */
-}
-
-#endif /* defined (HAVE_ICONV) */
-
 \f
-/* Fallback routines for systems without iconv.  */
+/* Host character set management.  For the time being, we assume that
+   the host character set is some superset of ASCII.  */
 
-#if ! defined (HAVE_ICONV) 
-struct cached_iconv { char nothing; };
-
-static int
-check_iconv_cache (struct cached_iconv *ci,
-                   struct charset *from,
-                   struct charset *to)
-{
-  errno = EINVAL;
-  return -1;
-}
-
-static int
-cached_iconv_convert (struct cached_iconv *ci, int from_char, int *to_char)
+char
+host_letter_to_control_character (char c)
 {
-  /* This function should never be called.  */
-  gdb_assert (0);
+  if (c == '?')
+    return 0177;
+  return c & 0237;
 }
 
-static void
-register_iconv_charsets (void)
-{
-}
+/* Convert a host character, C, to its hex value.  C must already have
+   been validated using isxdigit.  */
 
-#endif /* ! defined(HAVE_ICONV) */
-
-\f
-/* Default trivial conversion functions.  */
-
-static int
-identity_either_char_to_other (void *baton, int either_char, int *other_char)
+int
+host_hex_value (char c)
 {
-  *other_char = either_char;
-  return 1;
+  if (isdigit (c))
+    return c - '0';
+  if (c >= 'a' && c <= 'f')
+    return 10 + c - 'a';
+  gdb_assert (c >= 'A' && c <= 'F');
+  return 10 + c - 'A';
 }
 
-
 \f
-/* Default non-trivial conversion functions.  */
-
-
-static char backslashable[] = "abefnrtv";
-static char *backslashed[] = {"a", "b", "e", "f", "n", "r", "t", "v", "0"};
-static char represented[] = "\a\b\e\f\n\r\t\v";
+/* Public character management functions.  */
 
+/* A cleanup function which is run to close an iconv descriptor.  */
 
-/* Translate TARGET_CHAR into the host character set, and see if it
-   matches any of our standard escape sequences.  */
-static const char *
-default_c_target_char_has_backslash_escape (void *baton, int target_char)
+static void
+cleanup_iconv (void *p)
 {
-  int host_char;
-  const char *ix;
-
-  /* If target_char has no equivalent in the host character set,
-     assume it doesn't have a backslashed form.  */
-  if (! target_char_to_host (target_char, &host_char))
-    return NULL;
-
-  ix = strchr (represented, host_char);
-  if (ix)
-    return backslashed[ix - represented];
-  else
-    return NULL;
+  iconv_t *descp = p;
+  iconv_close (*descp);
 }
 
-
-/* Translate the backslash the way we would in the host character set,
-   and then try to translate that into the target character set.  */
-static int
-default_c_parse_backslash (void *baton, int host_char, int *target_char)
+void
+convert_between_encodings (const char *from, const char *to,
+                          const gdb_byte *bytes, unsigned int num_bytes,
+                          int width, struct obstack *output,
+                          enum transliterations translit)
 {
-  const char *ix;
+  iconv_t desc;
+  struct cleanup *cleanups;
+  size_t inleft;
+  ICONV_CONST char *inp;
+  unsigned int space_request;
+
+  /* Often, the host and target charsets will be the same.  */
+  if (!strcmp (from, to))
+    {
+      obstack_grow (output, bytes, num_bytes);
+      return;
+    }
 
-  ix = strchr (backslashable, host_char);
+  desc = iconv_open (to, from);
+  if (desc == (iconv_t) -1)
+    perror_with_name (_("Converting character sets"));
+  cleanups = make_cleanup (cleanup_iconv, &desc);
 
-  if (! ix)
-    return 0;
-  else
-    return host_char_to_target (represented[ix - backslashable],
-                                target_char);
-}
+  inleft = num_bytes;
+  inp = (ICONV_CONST char *) bytes;
 
+  space_request = num_bytes;
 
-/* Convert using a cached iconv descriptor.  */
-static int
-iconv_convert (void *baton, int from_char, int *to_char)
-{
-  struct cached_iconv *ci = baton;
-  return cached_iconv_convert (ci, from_char, to_char);
-}
+  while (inleft > 0)
+    {
+      char *outp;
+      size_t outleft, r;
+      int old_size;
+
+      old_size = obstack_object_size (output);
+      obstack_blank (output, space_request);
+
+      outp = (char *) obstack_base (output) + old_size;
+      outleft = space_request;
+
+      r = iconv (desc, &inp, &inleft, &outp, &outleft);
+
+      /* Now make sure that the object on the obstack only includes
+        bytes we have converted.  */
+      obstack_blank (output, - (int) outleft);
+
+      if (r == (size_t) -1)
+       {
+         switch (errno)
+           {
+           case EILSEQ:
+             {
+               int i;
+
+               /* Invalid input sequence.  */
+               if (translit == translit_none)
+                 error (_("Could not convert character "
+                          "to `%s' character set"), to);
+
+               /* We emit escape sequence for the bytes, skip them,
+                  and try again.  */
+               for (i = 0; i < width; ++i)
+                 {
+                   char octal[5];
+
+                   xsnprintf (octal, sizeof (octal), "\\%.3o", *inp & 0xff);
+                   obstack_grow_str (output, octal);
+
+                   ++inp;
+                   --inleft;
+                 }
+             }
+             break;
+
+           case E2BIG:
+             /* We ran out of space in the output buffer.  Make it
+                bigger next time around.  */
+             space_request *= 2;
+             break;
+
+           case EINVAL:
+             /* Incomplete input sequence.  FIXME: ought to report this
+                to the caller somehow.  */
+             inleft = 0;
+             break;
+
+           default:
+             perror_with_name (_("Internal error while "
+                                 "converting character sets"));
+           }
+       }
+    }
 
+  do_cleanups (cleanups);
+}
 
 \f
-/* Conversion tables.  */
-
-
-/* I'd much rather fall back on iconv whenever possible.  But the
-   character set names you use with iconv aren't standardized at all,
-   a lot of platforms have really meager character set coverage, etc.
-   I wanted to have at least something we could use to exercise the
-   test suite on all platforms.
-
-   In the long run, we should have a configure-time process explore
-   somehow which character sets the host platform supports, and some
-   arrangement that allows GDB users to use platform-indepedent names
-   for character sets.  */
-
-
-/* We generated these tables using iconv on a GNU/Linux machine.  */
-
-
-static int ascii_to_iso_8859_1_table[] = {
-    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, /* 16 */
-   16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 32 */
-   32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 48 */
-   48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 64 */
-   64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 80 */
-   80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 96 */
-   96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, /* 112 */
-  112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, /* 128 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1  /* 256 */
-};
-
-
-static int ascii_to_ebcdic_us_table[] = {
-    0,  1,  2,  3, 55, 45, 46, 47, 22,  5, 37, 11, 12, 13, 14, 15, /* 16 */
-   16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, /* 32 */
-   64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97, /* 48 */
-  240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111, /* 64 */
-  124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, /* 80 */
-  215,216,217,226,227,228,229,230,231,232,233, -1,224, -1, -1,109, /* 96 */
-  121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, /* 112 */
-  151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161,  7, /* 128 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1  /* 256 */
-};
-
-
-static int ascii_to_ibm1047_table[] = {
-    0,  1,  2,  3, 55, 45, 46, 47, 22,  5, 37, 11, 12, 13, 14, 15, /* 16 */
-   16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, /* 32 */
-   64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97, /* 48 */
-  240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111, /* 64 */
-  124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, /* 80 */
-  215,216,217,226,227,228,229,230,231,232,233,173,224,189, 95,109, /* 96 */
-  121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, /* 112 */
-  151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161,  7, /* 128 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1  /* 256 */
-};
-
-
-static int iso_8859_1_to_ascii_table[] = {
-    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, /* 16 */
-   16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 32 */
-   32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 48 */
-   48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 64 */
-   64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 80 */
-   80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 96 */
-   96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, /* 112 */
-  112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, /* 128 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1  /* 256 */
-};
-
-
-static int iso_8859_1_to_ebcdic_us_table[] = {
-    0,  1,  2,  3, 55, 45, 46, 47, 22,  5, 37, 11, 12, 13, 14, 15, /* 16 */
-   16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, /* 32 */
-   64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97, /* 48 */
-  240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111, /* 64 */
-  124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, /* 80 */
-  215,216,217,226,227,228,229,230,231,232,233, -1,224, -1, -1,109, /* 96 */
-  121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, /* 112 */
-  151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161,  7, /* 128 */
-   32, 33, 34, 35, 36, 21,  6, 23, 40, 41, 42, 43, 44,  9, 10, 27, /* 144 */
-   48, 49, 26, 51, 52, 53, 54,  8, 56, 57, 58, 59,  4, 20, 62,255, /* 160 */
-   -1, -1, 74, -1, -1, -1,106, -1, -1, -1, -1, -1, 95, -1, -1, -1, /* 176 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1  /* 256 */
-};
-
-
-static int iso_8859_1_to_ibm1047_table[] = {
-    0,  1,  2,  3, 55, 45, 46, 47, 22,  5, 37, 11, 12, 13, 14, 15, /* 16 */
-   16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, /* 32 */
-   64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97, /* 48 */
-  240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111, /* 64 */
-  124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, /* 80 */
-  215,216,217,226,227,228,229,230,231,232,233,173,224,189, 95,109, /* 96 */
-  121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, /* 112 */
-  151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161,  7, /* 128 */
-   32, 33, 34, 35, 36, 21,  6, 23, 40, 41, 42, 43, 44,  9, 10, 27, /* 144 */
-   48, 49, 26, 51, 52, 53, 54,  8, 56, 57, 58, 59,  4, 20, 62,255, /* 160 */
-   65,170, 74,177,159,178,106,181,187,180,154,138,176,202,175,188, /* 176 */
-  144,143,234,250,190,160,182,179,157,218,155,139,183,184,185,171, /* 192 */
-  100,101, 98,102, 99,103,158,104,116,113,114,115,120,117,118,119, /* 208 */
-  172,105,237,238,235,239,236,191,128,253,254,251,252,186,174, 89, /* 224 */
-   68, 69, 66, 70, 67, 71,156, 72, 84, 81, 82, 83, 88, 85, 86, 87, /* 240 */
-  140, 73,205,206,203,207,204,225,112,221,222,219,220,141,142,223  /* 256 */
-};
 
+/* An iterator that returns host wchar_t's from a target string.  */
+struct wchar_iterator
+{
+  /* The underlying iconv descriptor.  */
+  iconv_t desc;
 
-static int ebcdic_us_to_ascii_table[] = {
-    0,  1,  2,  3, -1,  9, -1,127, -1, -1, -1, 11, 12, 13, 14, 15, /* 16 */
-   16, 17, 18, 19, -1, -1,  8, -1, 24, 25, -1, -1, 28, 29, 30, 31, /* 32 */
-   -1, -1, -1, -1, -1, 10, 23, 27, -1, -1, -1, -1, -1,  5,  6,  7, /* 48 */
-   -1, -1, 22, -1, -1, -1, -1,  4, -1, -1, -1, -1, 20, 21, -1, 26, /* 64 */
-   32, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, 60, 40, 43,124, /* 80 */
-   38, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, 36, 42, 41, 59, -1, /* 96 */
-   45, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, 37, 95, 62, 63, /* 112 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, 96, 58, 35, 64, 39, 61, 34, /* 128 */
-   -1, 97, 98, 99,100,101,102,103,104,105, -1, -1, -1, -1, -1, -1, /* 144 */
-   -1,106,107,108,109,110,111,112,113,114, -1, -1, -1, -1, -1, -1, /* 160 */
-   -1,126,115,116,117,118,119,120,121,122, -1, -1, -1, -1, -1, -1, /* 176 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */
-  123, 65, 66, 67, 68, 69, 70, 71, 72, 73, -1, -1, -1, -1, -1, -1, /* 208 */
-  125, 74, 75, 76, 77, 78, 79, 80, 81, 82, -1, -1, -1, -1, -1, -1, /* 224 */
-   92, -1, 83, 84, 85, 86, 87, 88, 89, 90, -1, -1, -1, -1, -1, -1, /* 240 */
-   48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1, -1  /* 256 */
-};
+  /* The input string.  This is updated as convert characters.  */
+  const gdb_byte *input;
+  /* The number of bytes remaining in the input.  */
+  size_t bytes;
 
+  /* The width of an input character.  */
+  size_t width;
 
-static int ebcdic_us_to_iso_8859_1_table[] = {
-    0,  1,  2,  3,156,  9,134,127,151,141,142, 11, 12, 13, 14, 15, /* 16 */
-   16, 17, 18, 19,157,133,  8,135, 24, 25,146,143, 28, 29, 30, 31, /* 32 */
-  128,129,130,131,132, 10, 23, 27,136,137,138,139,140,  5,  6,  7, /* 48 */
-  144,145, 22,147,148,149,150,  4,152,153,154,155, 20, 21,158, 26, /* 64 */
-   32, -1, -1, -1, -1, -1, -1, -1, -1, -1,162, 46, 60, 40, 43,124, /* 80 */
-   38, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, 36, 42, 41, 59,172, /* 96 */
-   45, 47, -1, -1, -1, -1, -1, -1, -1, -1,166, 44, 37, 95, 62, 63, /* 112 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, 96, 58, 35, 64, 39, 61, 34, /* 128 */
-   -1, 97, 98, 99,100,101,102,103,104,105, -1, -1, -1, -1, -1, -1, /* 144 */
-   -1,106,107,108,109,110,111,112,113,114, -1, -1, -1, -1, -1, -1, /* 160 */
-   -1,126,115,116,117,118,119,120,121,122, -1, -1, -1, -1, -1, -1, /* 176 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */
-  123, 65, 66, 67, 68, 69, 70, 71, 72, 73, -1, -1, -1, -1, -1, -1, /* 208 */
-  125, 74, 75, 76, 77, 78, 79, 80, 81, 82, -1, -1, -1, -1, -1, -1, /* 224 */
-   92, -1, 83, 84, 85, 86, 87, 88, 89, 90, -1, -1, -1, -1, -1, -1, /* 240 */
-   48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1,159  /* 256 */
+  /* The output buffer and its size.  */
+  gdb_wchar_t *out;
+  size_t out_size;
 };
 
+/* Create a new iterator.  */
+struct wchar_iterator *
+make_wchar_iterator (const gdb_byte *input, size_t bytes, 
+                    const char *charset, size_t width)
+{
+  struct wchar_iterator *result;
+  iconv_t desc;
 
-static int ebcdic_us_to_ibm1047_table[] = {
-    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, /* 16 */
-   16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 32 */
-   32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 48 */
-   48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 64 */
-   64, -1, -1, -1, -1, -1, -1, -1, -1, -1, 74, 75, 76, 77, 78, 79, /* 80 */
-   80, -1, -1, -1, -1, -1, -1, -1, -1, -1, 90, 91, 92, 93, 94,176, /* 96 */
-   96, 97, -1, -1, -1, -1, -1, -1, -1, -1,106,107,108,109,110,111, /* 112 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1,121,122,123,124,125,126,127, /* 128 */
-   -1,129,130,131,132,133,134,135,136,137, -1, -1, -1, -1, -1, -1, /* 144 */
-   -1,145,146,147,148,149,150,151,152,153, -1, -1, -1, -1, -1, -1, /* 160 */
-   -1,161,162,163,164,165,166,167,168,169, -1, -1, -1, -1, -1, -1, /* 176 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */
-  192,193,194,195,196,197,198,199,200,201, -1, -1, -1, -1, -1, -1, /* 208 */
-  208,209,210,211,212,213,214,215,216,217, -1, -1, -1, -1, -1, -1, /* 224 */
-  224, -1,226,227,228,229,230,231,232,233, -1, -1, -1, -1, -1, -1, /* 240 */
-  240,241,242,243,244,245,246,247,248,249, -1, -1, -1, -1, -1,255  /* 256 */
-};
-
-
-static int ibm1047_to_ascii_table[] = {
-    0,  1,  2,  3, -1,  9, -1,127, -1, -1, -1, 11, 12, 13, 14, 15, /* 16 */
-   16, 17, 18, 19, -1, -1,  8, -1, 24, 25, -1, -1, 28, 29, 30, 31, /* 32 */
-   -1, -1, -1, -1, -1, 10, 23, 27, -1, -1, -1, -1, -1,  5,  6,  7, /* 48 */
-   -1, -1, 22, -1, -1, -1, -1,  4, -1, -1, -1, -1, 20, 21, -1, 26, /* 64 */
-   32, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, 60, 40, 43,124, /* 80 */
-   38, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, 36, 42, 41, 59, 94, /* 96 */
-   45, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, 37, 95, 62, 63, /* 112 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, 96, 58, 35, 64, 39, 61, 34, /* 128 */
-   -1, 97, 98, 99,100,101,102,103,104,105, -1, -1, -1, -1, -1, -1, /* 144 */
-   -1,106,107,108,109,110,111,112,113,114, -1, -1, -1, -1, -1, -1, /* 160 */
-   -1,126,115,116,117,118,119,120,121,122, -1, -1, -1, 91, -1, -1, /* 176 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 93, -1, -1, /* 192 */
-  123, 65, 66, 67, 68, 69, 70, 71, 72, 73, -1, -1, -1, -1, -1, -1, /* 208 */
-  125, 74, 75, 76, 77, 78, 79, 80, 81, 82, -1, -1, -1, -1, -1, -1, /* 224 */
-   92, -1, 83, 84, 85, 86, 87, 88, 89, 90, -1, -1, -1, -1, -1, -1, /* 240 */
-   48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1, -1  /* 256 */
-};
-
+  desc = iconv_open (INTERMEDIATE_ENCODING, charset);
+  if (desc == (iconv_t) -1)
+    perror_with_name (_("Converting character sets"));
 
-static int ibm1047_to_iso_8859_1_table[] = {
-    0,  1,  2,  3,156,  9,134,127,151,141,142, 11, 12, 13, 14, 15, /* 16 */
-   16, 17, 18, 19,157,133,  8,135, 24, 25,146,143, 28, 29, 30, 31, /* 32 */
-  128,129,130,131,132, 10, 23, 27,136,137,138,139,140,  5,  6,  7, /* 48 */
-  144,145, 22,147,148,149,150,  4,152,153,154,155, 20, 21,158, 26, /* 64 */
-   32,160,226,228,224,225,227,229,231,241,162, 46, 60, 40, 43,124, /* 80 */
-   38,233,234,235,232,237,238,239,236,223, 33, 36, 42, 41, 59, 94, /* 96 */
-   45, 47,194,196,192,193,195,197,199,209,166, 44, 37, 95, 62, 63, /* 112 */
-  248,201,202,203,200,205,206,207,204, 96, 58, 35, 64, 39, 61, 34, /* 128 */
-  216, 97, 98, 99,100,101,102,103,104,105,171,187,240,253,254,177, /* 144 */
-  176,106,107,108,109,110,111,112,113,114,170,186,230,184,198,164, /* 160 */
-  181,126,115,116,117,118,119,120,121,122,161,191,208, 91,222,174, /* 176 */
-  172,163,165,183,169,167,182,188,189,190,221,168,175, 93,180,215, /* 192 */
-  123, 65, 66, 67, 68, 69, 70, 71, 72, 73,173,244,246,242,243,245, /* 208 */
-  125, 74, 75, 76, 77, 78, 79, 80, 81, 82,185,251,252,249,250,255, /* 224 */
-   92,247, 83, 84, 85, 86, 87, 88, 89, 90,178,212,214,210,211,213, /* 240 */
-   48, 49, 50, 51, 52, 53, 54, 55, 56, 57,179,219,220,217,218,159  /* 256 */
-};
+  result = XNEW (struct wchar_iterator);
+  result->desc = desc;
+  result->input = input;
+  result->bytes = bytes;
+  result->width = width;
 
+  result->out = XNEW (gdb_wchar_t);
+  result->out_size = 1;
 
-static int ibm1047_to_ebcdic_us_table[] = {
-    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, /* 16 */
-   16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 32 */
-   32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 48 */
-   48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 64 */
-   64, -1, -1, -1, -1, -1, -1, -1, -1, -1, 74, 75, 76, 77, 78, 79, /* 80 */
-   80, -1, -1, -1, -1, -1, -1, -1, -1, -1, 90, 91, 92, 93, 94, -1, /* 96 */
-   96, 97, -1, -1, -1, -1, -1, -1, -1, -1,106,107,108,109,110,111, /* 112 */
-   -1, -1, -1, -1, -1, -1, -1, -1, -1,121,122,123,124,125,126,127, /* 128 */
-   -1,129,130,131,132,133,134,135,136,137, -1, -1, -1, -1, -1, -1, /* 144 */
-   -1,145,146,147,148,149,150,151,152,153, -1, -1, -1, -1, -1, -1, /* 160 */
-   -1,161,162,163,164,165,166,167,168,169, -1, -1, -1, -1, -1, -1, /* 176 */
-   95, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */
-  192,193,194,195,196,197,198,199,200,201, -1, -1, -1, -1, -1, -1, /* 208 */
-  208,209,210,211,212,213,214,215,216,217, -1, -1, -1, -1, -1, -1, /* 224 */
-  224, -1,226,227,228,229,230,231,232,233, -1, -1, -1, -1, -1, -1, /* 240 */
-  240,241,242,243,244,245,246,247,248,249, -1, -1, -1, -1, -1,255  /* 256 */
-};
-
+  return result;
+}
 
-static int
-table_convert_char (void *baton, int from, int *to)
+static void
+do_cleanup_iterator (void *p)
 {
-  int *table = (int *) baton;
+  struct wchar_iterator *iter = p;
 
-  if (0 <= from && from <= 255
-      && table[from] != -1)
-    {
-      *to = table[from];
-      return 1;
-    }
-  else
-    return 0;
+  iconv_close (iter->desc);
+  xfree (iter->out);
+  xfree (iter);
 }
 
-
-static struct translation *
-table_translation (const char *from, const char *to, int *table,
-                   const char *(*c_target_char_has_backslash_escape)
-                   (void *baton, int target_char),
-                   void *c_target_char_has_backslash_escape_baton,
-                   int (*c_parse_backslash) (void *baton,
-                                             int host_char,
-                                             int *target_char),
-                   void *c_parse_backslash_baton)
+struct cleanup *
+make_cleanup_wchar_iterator (struct wchar_iterator *iter)
 {
-  struct translation *t = xmalloc (sizeof (*t));
-
-  memset (t, 0, sizeof (*t));
-  t->from = from;
-  t->to = to;
-  t->c_target_char_has_backslash_escape = c_target_char_has_backslash_escape;
-  t->c_target_char_has_backslash_escape_baton
-    = c_target_char_has_backslash_escape_baton;
-  t->c_parse_backslash = c_parse_backslash;
-  t->c_parse_backslash_baton = c_parse_backslash_baton;
-  t->convert_char = table_convert_char;
-  t->convert_char_baton = (void *) table;
-
-  return t;
+  return make_cleanup (do_cleanup_iterator, iter);
 }
 
-
-static struct translation *
-simple_table_translation (const char *from, const char *to, int *table)
+int
+wchar_iterate (struct wchar_iterator *iter,
+              enum wchar_iterate_result *out_result,
+              gdb_wchar_t **out_chars,
+              const gdb_byte **ptr,
+              size_t *len)
 {
-  return table_translation (from, to, table, 0, 0, 0, 0);
-}
+  size_t out_request;
+
+  /* Try to convert some characters.  At first we try to convert just
+     a single character.  The reason for this is that iconv does not
+     necessarily update its outgoing arguments when it encounters an
+     invalid input sequence -- but we want to reliably report this to
+     our caller so it can emit an escape sequence.  */
+  out_request = 1;
+  while (iter->bytes > 0)
+    {
+      ICONV_CONST char *inptr = (ICONV_CONST char *) iter->input;
+      char *outptr = (char *) &iter->out[0];
+      const gdb_byte *orig_inptr = iter->input;
+      size_t orig_in = iter->bytes;
+      size_t out_avail = out_request * sizeof (gdb_wchar_t);
+      size_t num;
+      size_t r = iconv (iter->desc, &inptr, &iter->bytes, &outptr, &out_avail);
+
+      iter->input = (gdb_byte *) inptr;
+
+      if (r == (size_t) -1)
+       {
+         switch (errno)
+           {
+           case EILSEQ:
+             /* Invalid input sequence.  We still might have
+                converted a character; if so, return it.  */
+             if (out_avail < out_request * sizeof (gdb_wchar_t))
+               break;
+             
+             /* Otherwise skip the first invalid character, and let
+                the caller know about it.  */
+             *out_result = wchar_iterate_invalid;
+             *ptr = iter->input;
+             *len = iter->width;
+             iter->input += iter->width;
+             iter->bytes -= iter->width;
+             return 0;
+
+           case E2BIG:
+             /* We ran out of space.  We still might have converted a
+                character; if so, return it.  Otherwise, grow the
+                buffer and try again.  */
+             if (out_avail < out_request * sizeof (gdb_wchar_t))
+               break;
+
+             ++out_request;
+             if (out_request > iter->out_size)
+               {
+                 iter->out_size = out_request;
+                 iter->out = xrealloc (iter->out,
+                                       out_request * sizeof (gdb_wchar_t));
+               }
+             continue;
+
+           case EINVAL:
+             /* Incomplete input sequence.  Let the caller know, and
+                arrange for future calls to see EOF.  */
+             *out_result = wchar_iterate_incomplete;
+             *ptr = iter->input;
+             *len = iter->bytes;
+             iter->bytes = 0;
+             return 0;
+
+           default:
+             perror_with_name (_("Internal error while "
+                                 "converting character sets"));
+           }
+       }
+
+      /* We converted something.  */
+      num = out_request - out_avail / sizeof (gdb_wchar_t);
+      *out_result = wchar_iterate_ok;
+      *out_chars = iter->out;
+      *ptr = orig_inptr;
+      *len = orig_in - iter->bytes;
+      return num;
+    }
 
+  /* Really done.  */
+  *out_result = wchar_iterate_eof;
+  return -1;
+}
 
 \f
-/* Setting and retrieving the host and target charsets.  */
-
-
-/* The current host and target character sets.  */
-static struct charset *current_host_charset, *current_target_charset;
-
-/* The current functions and batons we should use for the functions in
-   charset.h.  */
+/* The charset.c module initialization function.  */
 
-static const char *(*c_target_char_has_backslash_escape_func)
-     (void *baton, int target_char);
-static void *c_target_char_has_backslash_escape_baton;
+extern initialize_file_ftype _initialize_charset; /* -Wmissing-prototype */
 
-static int (*c_parse_backslash_func) (void *baton,
-                                      int host_char,
-                                      int *target_char);
-static void *c_parse_backslash_baton;
+static VEC (char_ptr) *charsets;
 
-static int (*host_char_to_target_func) (void *baton,
-                                        int host_char,
-                                        int *target_char);
-static void *host_char_to_target_baton;
+#ifdef PHONY_ICONV
 
-static int (*target_char_to_host_func) (void *baton,
-                                        int target_char,
-                                        int *host_char);
-static void *target_char_to_host_baton;
+static void
+find_charset_names (void)
+{
+  VEC_safe_push (char_ptr, charsets, GDB_DEFAULT_HOST_CHARSET);
+  VEC_safe_push (char_ptr, charsets, NULL);
+}
 
+#else /* PHONY_ICONV */
 
-/* Cached iconv conversions, that might be useful to fallback
-   routines.  */
-static struct cached_iconv cached_iconv_host_to_target;
-static struct cached_iconv cached_iconv_target_to_host;
+/* Sometimes, libiconv redefines iconvlist as libiconvlist -- but
+   provides different symbols in the static and dynamic libraries.
+   So, configure may see libiconvlist but not iconvlist.  But, calling
+   iconvlist is the right thing to do and will work.  Hence we do a
+   check here but unconditionally call iconvlist below.  */
+#if defined (HAVE_ICONVLIST) || defined (HAVE_LIBICONVLIST)
 
-\f
-/* Charset structures manipulation functions.  */
+/* A helper function that adds some character sets to the vector of
+   all character sets.  This is a callback function for iconvlist.  */
 
-static struct charset *
-lookup_charset_or_error (const char *name)
+static int
+add_one (unsigned int count, const char *const *names, void *data)
 {
-  struct charset *cs = lookup_charset (name);
+  unsigned int i;
 
-  if (! cs)
-    error ("GDB doesn't know of any character set named `%s'.", name);
+  for (i = 0; i < count; ++i)
+    VEC_safe_push (char_ptr, charsets, xstrdup (names[i]));
 
-  return cs;
+  return 0;
 }
 
 static void
-check_valid_host_charset (struct charset *cs)
+find_charset_names (void)
 {
-  if (! cs->valid_host_charset)
-    error ("GDB can't use `%s' as its host character set.", cs->name);
+  iconvlist (add_one, NULL);
+  VEC_safe_push (char_ptr, charsets, NULL);
 }
 
-/* Set the host and target character sets to HOST and TARGET.  */
-static void
-set_host_and_target_charsets (struct charset *host, struct charset *target)
-{
-  struct translation *h2t, *t2h;
+#else
 
-  /* If they're not both initialized yet, then just do nothing for
-     now.  As soon as we're done running our initialize function,
-     everything will be initialized.  */
-  if (! host || ! target)
-    {
-      current_host_charset = host;
-      current_target_charset = target;
-      return;
-    }
+/* Return non-zero if LINE (output from iconv) should be ignored.
+   Older iconv programs (e.g. 2.2.2) include the human readable
+   introduction even when stdout is not a tty.  Newer versions omit
+   the intro if stdout is not a tty.  */
 
-  h2t = lookup_translation (host->name, target->name);
-  t2h = lookup_translation (target->name, host->name);
-
-  /* If the translations don't provide conversion functions, make sure
-     iconv can back them up.  Do this *before* modifying any state.  */
-  if (host != target)
-    {
-      if (! h2t || ! h2t->convert_char)
-        {
-          if (check_iconv_cache (&cached_iconv_host_to_target, host, target)
-              < 0)
-            error ("GDB can't convert from the `%s' character set to `%s'.",
-                   host->name, target->name);
-        }
-      if (! t2h || ! t2h->convert_char)
-        {
-          if (check_iconv_cache (&cached_iconv_target_to_host, target, host)
-              < 0)
-            error ("GDB can't convert from the `%s' character set to `%s'.",
-                   target->name, host->name);
-        }
-    }
-
-  if (t2h && t2h->c_target_char_has_backslash_escape)
-    {
-      c_target_char_has_backslash_escape_func
-        = t2h->c_target_char_has_backslash_escape;
-      c_target_char_has_backslash_escape_baton
-        = t2h->c_target_char_has_backslash_escape_baton;
-    }
-  else
-    c_target_char_has_backslash_escape_func
-      = default_c_target_char_has_backslash_escape;
-
-  if (h2t && h2t->c_parse_backslash)
-    {
-      c_parse_backslash_func = h2t->c_parse_backslash;
-      c_parse_backslash_baton = h2t->c_parse_backslash_baton;
-    }
-  else
-    c_parse_backslash_func = default_c_parse_backslash;
-
-  if (h2t && h2t->convert_char)
-    {
-      host_char_to_target_func = h2t->convert_char;
-      host_char_to_target_baton = h2t->convert_char_baton;
-    }
-  else if (host == target)
-    host_char_to_target_func = identity_either_char_to_other;
-  else
+static int
+ignore_line_p (const char *line)
+{
+  /* This table is used to filter the output.  If this text appears
+     anywhere in the line, it is ignored (strstr is used).  */
+  static const char * const ignore_lines[] =
     {
-      host_char_to_target_func = iconv_convert;
-      host_char_to_target_baton = &cached_iconv_host_to_target;
-    }
+      "The following",
+      "not necessarily",
+      "the FROM and TO",
+      "listed with several",
+      NULL
+    };
+  int i;
 
-  if (t2h && t2h->convert_char)
-    {
-      target_char_to_host_func = t2h->convert_char;
-      target_char_to_host_baton = t2h->convert_char_baton;
-    }
-  else if (host == target)
-    target_char_to_host_func = identity_either_char_to_other;
-  else
+  for (i = 0; ignore_lines[i] != NULL; ++i)
     {
-      target_char_to_host_func = iconv_convert;
-      target_char_to_host_baton = &cached_iconv_target_to_host;
+      if (strstr (line, ignore_lines[i]) != NULL)
+       return 1;
     }
 
-  current_host_charset = host;
-  current_target_charset = target;
-}
-
-/* Do the real work of setting the host charset.  */
-static void
-set_host_charset (const char *charset)
-{
-  struct charset *cs = lookup_charset_or_error (charset);
-  check_valid_host_charset (cs);
-  set_host_and_target_charsets (cs, current_target_charset);
-}
-
-/* Do the real work of setting the target charset.  */
-static void
-set_target_charset (const char *charset)
-{
-  struct charset *cs = lookup_charset_or_error (charset);
-
-  set_host_and_target_charsets (current_host_charset, cs);
+  return 0;
 }
 
-\f
-/* 'Set charset', 'set host-charset', 'set target-charset', 'show
-   charset' sfunc's.  */
-
-/* This is the sfunc for the 'set charset' command.  */
 static void
-set_charset_sfunc (char *charset, int from_tty, struct cmd_list_element *c)
+find_charset_names (void)
 {
-  struct charset *cs = lookup_charset_or_error (host_charset_name);
-  check_valid_host_charset (cs);
-  /* CAREFUL: set the target charset here as well. */
-  target_charset_name = host_charset_name;
-  set_host_and_target_charsets (cs, cs);
-}
+  struct pex_obj *child;
+  char *args[3];
+  int err, status;
+  int fail = 1;
+  int flags;
+  struct gdb_environ *iconv_env;
+  char *iconv_program;
+
+  /* Older iconvs, e.g. 2.2.2, don't omit the intro text if stdout is
+     not a tty.  We need to recognize it and ignore it.  This text is
+     subject to translation, so force LANGUAGE=C.  */
+  iconv_env = make_environ ();
+  init_environ (iconv_env);
+  set_in_environ (iconv_env, "LANGUAGE", "C");
+  set_in_environ (iconv_env, "LC_ALL", "C");
+
+  child = pex_init (PEX_USE_PIPES, "iconv", NULL);
+
+#ifdef ICONV_BIN
+  {
+    char *iconv_dir = relocate_gdb_directory (ICONV_BIN,
+                                             ICONV_BIN_RELOCATABLE);
+    iconv_program = concat (iconv_dir, SLASH_STRING, "iconv", NULL);
+    xfree (iconv_dir);
+  }
+#else
+  iconv_program = xstrdup ("iconv");
+#endif
+  args[0] = iconv_program;
+  args[1] = "-l";
+  args[2] = NULL;
+  flags = PEX_STDERR_TO_STDOUT;
+#ifndef ICONV_BIN
+  flags |= PEX_SEARCH;
+#endif
+  /* Note that we simply ignore errors here.  */
+  if (!pex_run_in_environment (child, flags,
+                              args[0], args, environ_vector (iconv_env),
+                              NULL, NULL, &err))
+    {
+      FILE *in = pex_read_output (child, 0);
+
+      /* POSIX says that iconv -l uses an unspecified format.  We
+        parse the glibc and libiconv formats; feel free to add others
+        as needed.  */
+
+      while (in != NULL && !feof (in))
+       {
+         /* The size of buf is chosen arbitrarily.  */
+         char buf[1024];
+         char *start, *r;
+         int len;
+
+         r = fgets (buf, sizeof (buf), in);
+         if (!r)
+           break;
+         len = strlen (r);
+         if (len <= 3)
+           continue;
+         if (ignore_line_p (r))
+           continue;
+
+         /* Strip off the newline.  */
+         --len;
+         /* Strip off one or two '/'s.  glibc will print lines like
+            "8859_7//", but also "10646-1:1993/UCS4/".  */
+         if (buf[len - 1] == '/')
+           --len;
+         if (buf[len - 1] == '/')
+           --len;
+         buf[len] = '\0';
+
+         /* libiconv will print multiple entries per line, separated
+            by spaces.  Older iconvs will print multiple entries per
+            line, indented by two spaces, and separated by ", "
+            (i.e. the human readable form).  */
+         start = buf;
+         while (1)
+           {
+             int keep_going;
+             char *p;
+
+             /* Skip leading blanks.  */
+             for (p = start; *p && *p == ' '; ++p)
+               ;
+             start = p;
+             /* Find the next space, comma, or end-of-line.  */
+             for ( ; *p && *p != ' ' && *p != ','; ++p)
+               ;
+             /* Ignore an empty result.  */
+             if (p == start)
+               break;
+             keep_going = *p;
+             *p = '\0';
+             VEC_safe_push (char_ptr, charsets, xstrdup (start));
+             if (!keep_going)
+               break;
+             /* Skip any extra spaces.  */
+             for (start = p + 1; *start && *start == ' '; ++start)
+               ;
+           }
+       }
+
+      if (pex_get_status (child, 1, &status)
+         && WIFEXITED (status) && !WEXITSTATUS (status))
+       fail = 0;
 
-/* 'set host-charset' command sfunc.  We need a wrapper here because
-   the function needs to have a specific signature.  */
-static void
-set_host_charset_sfunc (char *charset, int from_tty,
-                         struct cmd_list_element *c)
-{
-  set_host_charset (host_charset_name);
-}
+    }
 
-/* Wrapper for the 'set target-charset' command.  */
-static void
-set_target_charset_sfunc (char *charset, int from_tty,
-                           struct cmd_list_element *c)
-{
-  set_target_charset (target_charset_name);
-}
+  xfree (iconv_program);
+  pex_free (child);
+  free_environ (iconv_env);
 
-/* sfunc for the 'show charset' command.  */
-static void
-show_charset (char *arg, int from_tty)
-{
-  if (current_host_charset == current_target_charset)
+  if (fail)
     {
-      printf_filtered ("The current host and target character set is `%s'.\n",
-                       host_charset ());
+      /* Some error occurred, so drop the vector.  */
+      free_char_ptr_vec (charsets);
+      charsets = NULL;
     }
   else
-    {
-      printf_filtered ("The current host character set is `%s'.\n",
-                       host_charset ());
-      printf_filtered ("The current target character set is `%s'.\n",
-                       target_charset ());
-    }
+    VEC_safe_push (char_ptr, charsets, NULL);
 }
 
-\f
-/* Accessor functions.  */
+#endif /* HAVE_ICONVLIST || HAVE_LIBICONVLIST */
+#endif /* PHONY_ICONV */
 
-const char *
-host_charset (void)
-{
-  return current_host_charset->name;
-}
+/* The "auto" target charset used by default_auto_charset.  */
+static const char *auto_target_charset_name = GDB_DEFAULT_TARGET_CHARSET;
 
 const char *
-target_charset (void)
+default_auto_charset (void)
 {
-  return current_target_charset->name;
+  return auto_target_charset_name;
 }
 
-
-\f
-/* Public character management functions.  */
-
-
 const char *
-c_target_char_has_backslash_escape (int target_char)
+default_auto_wide_charset (void)
 {
-  return ((*c_target_char_has_backslash_escape_func)
-          (c_target_char_has_backslash_escape_baton, target_char));
+  return GDB_DEFAULT_TARGET_WIDE_CHARSET;
 }
 
 
-int
-c_parse_backslash (int host_char, int *target_char)
-{
-  return (*c_parse_backslash_func) (c_parse_backslash_baton,
-                                    host_char, target_char);
-}
-
-
-int
-host_char_print_literally (int host_char)
-{
-  return ((*current_host_charset->host_char_print_literally)
-          (current_host_charset->host_char_print_literally_baton,
-           host_char));
-}
-
-
-int
-target_char_to_control_char (int target_char, int *target_ctrl_char)
-{
-  return ((*current_target_charset->target_char_to_control_char)
-          (current_target_charset->target_char_to_control_char_baton,
-           target_char, target_ctrl_char));
-}
+#ifdef USE_INTERMEDIATE_ENCODING_FUNCTION
+/* Macro used for UTF or UCS endianness suffix.  */
+#if WORDS_BIGENDIAN
+#define ENDIAN_SUFFIX "BE"
+#else
+#define ENDIAN_SUFFIX "LE"
+#endif
 
+/* The code below serves to generate a compile time error if
+   gdb_wchar_t type is not of size 2 nor 4, despite the fact that
+   macro __STDC_ISO_10646__ is defined.
+   This is better than a gdb_assert call, because GDB cannot handle
+   strings correctly if this size is different.  */
 
-int
-host_char_to_target (int host_char, int *target_char)
-{
-  return ((*host_char_to_target_func)
-          (host_char_to_target_baton, host_char, target_char));
-}
+extern char your_gdb_wchar_t_is_bogus[(sizeof (gdb_wchar_t) == 2
+                                      || sizeof (gdb_wchar_t) == 4)
+                                     ? 1 : -1];
 
+/* intermediate_encoding returns the charset used internally by
+   GDB to convert between target and host encodings. As the test above
+   compiled, sizeof (gdb_wchar_t) is either 2 or 4 bytes.
+   UTF-16/32 is tested first, UCS-2/4 is tested as a second option,
+   otherwise an error is generated.  */
 
-int
-target_char_to_host (int target_char, int *host_char)
+const char *
+intermediate_encoding (void)
 {
-  return ((*target_char_to_host_func)
-          (target_char_to_host_baton, target_char, host_char));
+  iconv_t desc;
+  static const char *stored_result = NULL;
+  char *result;
+
+  if (stored_result)
+    return stored_result;
+  result = xstrprintf ("UTF-%d%s", (int) (sizeof (gdb_wchar_t) * 8),
+                      ENDIAN_SUFFIX);
+  /* Check that the name is supported by iconv_open.  */
+  desc = iconv_open (result, host_charset ());
+  if (desc != (iconv_t) -1)
+    {
+      iconv_close (desc);
+      stored_result = result;
+      return result;
+    }
+  /* Not valid, free the allocated memory.  */
+  xfree (result);
+  /* Second try, with UCS-2 type.  */
+  result = xstrprintf ("UCS-%d%s", (int) sizeof (gdb_wchar_t),
+                      ENDIAN_SUFFIX);
+  /* Check that the name is supported by iconv_open.  */
+  desc = iconv_open (result, host_charset ());
+  if (desc != (iconv_t) -1)
+    {
+      iconv_close (desc);
+      stored_result = result;
+      return result;
+    }
+  /* Not valid, free the allocated memory.  */
+  xfree (result);
+  /* No valid charset found, generate error here.  */
+  error (_("Unable to find a vaild charset for string conversions"));
 }
 
-
-\f
-/* The charset.c module initialization function.  */
-
+#endif /* USE_INTERMEDIATE_ENCODING_FUNCTION */
 
 void
 _initialize_charset (void)
 {
-  struct cmd_list_element *new_cmd;
-
-  /* Register all the character set GDB knows about.
-
-     You should use the same names that iconv does, where possible, to
-     take advantage of the iconv-based default behaviors.
-
-     CAUTION: if you register a character set, you must also register
-     as many translations as are necessary to make that character set
-     interoperate correctly with all the other character sets.  We do
-     provide default behaviors when no translation is available, or
-     when a translation's function pointer for a particular operation
-     is zero.  Hopefully, these defaults will be correct often enough
-     that we won't need to provide too many translations.  */
-  register_charset (simple_charset ("ASCII", 1,
-                                    ascii_print_literally, 0,
-                                    ascii_to_control, 0));
-  register_charset (iso_8859_family_charset ("ISO-8859-1"));
-  register_charset (ebcdic_family_charset ("EBCDIC-US"));
-  register_charset (ebcdic_family_charset ("IBM1047"));
-  register_iconv_charsets ();
+  /* The first element is always "auto".  */
+  VEC_safe_push (char_ptr, charsets, xstrdup ("auto"));
+  find_charset_names ();
 
+  if (VEC_length (char_ptr, charsets) > 1)
+    charset_enum = (const char **) VEC_address (char_ptr, charsets);
+  else
+    charset_enum = default_charset_names;
+
+#ifndef PHONY_ICONV
+#ifdef HAVE_LANGINFO_CODESET
+  /* The result of nl_langinfo may be overwritten later.  This may
+     leak a little memory, if the user later changes the host charset,
+     but that doesn't matter much.  */
+  auto_host_charset_name = xstrdup (nl_langinfo (CODESET));
+  /* Solaris will return `646' here -- but the Solaris iconv then does
+     not accept this.  Darwin (and maybe FreeBSD) may return "" here,
+     which GNU libiconv doesn't like (infinite loop).  */
+  if (!strcmp (auto_host_charset_name, "646") || !*auto_host_charset_name)
+    auto_host_charset_name = "ASCII";
+  auto_target_charset_name = auto_host_charset_name;
+#elif defined (USE_WIN32API)
   {
-    struct { char *from; char *to; int *table; } tlist[] = {
-      { "ASCII",      "ISO-8859-1", ascii_to_iso_8859_1_table },
-      { "ASCII",      "EBCDIC-US",  ascii_to_ebcdic_us_table },
-      { "ASCII",      "IBM1047",    ascii_to_ibm1047_table },
-      { "ISO-8859-1", "ASCII",      iso_8859_1_to_ascii_table },
-      { "ISO-8859-1", "EBCDIC-US",  iso_8859_1_to_ebcdic_us_table },
-      { "ISO-8859-1", "IBM1047",    iso_8859_1_to_ibm1047_table },
-      { "EBCDIC-US",  "ASCII",      ebcdic_us_to_ascii_table },
-      { "EBCDIC-US",  "ISO-8859-1", ebcdic_us_to_iso_8859_1_table },
-      { "EBCDIC-US",  "IBM1047",    ebcdic_us_to_ibm1047_table },
-      { "IBM1047",    "ASCII",      ibm1047_to_ascii_table },
-      { "IBM1047",    "ISO-8859-1", ibm1047_to_iso_8859_1_table },
-      { "IBM1047",    "EBCDIC-US",  ibm1047_to_ebcdic_us_table }
-    };
-
-    int i;
+    /* "CP" + x<=5 digits + paranoia.  */
+    static char w32_host_default_charset[16];
 
-    for (i = 0; i < (sizeof (tlist) / sizeof (tlist[0])); i++)
-      register_translation (simple_table_translation (tlist[i].from,
-                                                      tlist[i].to,
-                                                      tlist[i].table));
+    snprintf (w32_host_default_charset, sizeof w32_host_default_charset,
+             "CP%d", GetACP());
+    auto_host_charset_name = w32_host_default_charset;
+    auto_target_charset_name = auto_host_charset_name;
   }
+#endif
+#endif
 
-  set_host_charset (host_charset_name);
-  set_target_charset (target_charset_name);
-
-  new_cmd = add_set_enum_cmd ("charset",
-                             class_support,
-                             host_charset_enum,
-                             &host_charset_name,
-                              "Set the host and target character sets.\n"
-                              "The `host character set' is the one used by the system GDB is running on.\n"
-                              "The `target character set' is the one used by the program being debugged.\n"
-                              "You may only use supersets of ASCII for your host character set; GDB does\n"
-                              "not support any others.\n"
-                              "To see a list of the character sets GDB supports, type `set charset <TAB>'.",
-                             &setlist);
-
-  /* Note that the sfunc below needs to set target_charset_name, because 
-     the 'set charset' command sets two variables.  */
-  set_cmd_sfunc (new_cmd, set_charset_sfunc);
-  /* Don't use set_from_show - need to print some extra info. */
-  add_cmd ("charset", class_support, show_charset,
-          "Show the host and target character sets.\n"
-          "The `host character set' is the one used by the system GDB is running on.\n"
-          "The `target character set' is the one used by the program being debugged.\n"
-          "You may only use supersets of ASCII for your host character set; GDB does\n"
-          "not support any others.\n"
-          "To see a list of the character sets GDB supports, type `set charset <TAB>'.", 
-          &showlist);
-
-
-  new_cmd = add_set_enum_cmd ("host-charset",
-                             class_support,
-                             host_charset_enum,
-                             &host_charset_name,
-                             "Set the host character set.\n"
-                             "The `host character set' is the one used by the system GDB is running on.\n"
-                             "You may only use supersets of ASCII for your host character set; GDB does\n"
-                             "not support any others.\n"
-                             "To see a list of the character sets GDB supports, type `set host-charset <TAB>'.",
-                             &setlist);
-
-  set_cmd_sfunc (new_cmd, set_host_charset_sfunc);
-
-  add_show_from_set (new_cmd, &showlist);
-
-
-
-  new_cmd = add_set_enum_cmd ("target-charset",
-                             class_support,
-                             target_charset_enum,
-                             &target_charset_name,
-                             "Set the target character set.\n"
-                             "The `target character set' is the one used by the program being debugged.\n"
-                             "GDB translates characters and strings between the host and target\n"
-                             "character sets as needed.\n"
-                             "To see a list of the character sets GDB supports, type `set target-charset'<TAB>",
-                             &setlist);
-
-  set_cmd_sfunc (new_cmd, set_target_charset_sfunc);
-  add_show_from_set (new_cmd, &showlist);
+  add_setshow_enum_cmd ("charset", class_support,
+                       charset_enum, &host_charset_name, _("\
+Set the host and target character sets."), _("\
+Show the host and target character sets."), _("\
+The `host character set' is the one used by the system GDB is running on.\n\
+The `target character set' is the one used by the program being debugged.\n\
+You may only use supersets of ASCII for your host character set; GDB does\n\
+not support any others.\n\
+To see a list of the character sets GDB supports, type `set charset <TAB>'."),
+                       /* Note that the sfunc below needs to set
+                          target_charset_name, because the 'set
+                          charset' command sets two variables.  */
+                       set_charset_sfunc,
+                       show_charset,
+                       &setlist, &showlist);
+
+  add_setshow_enum_cmd ("host-charset", class_support,
+                       charset_enum, &host_charset_name, _("\
+Set the host character set."), _("\
+Show the host character set."), _("\
+The `host character set' is the one used by the system GDB is running on.\n\
+You may only use supersets of ASCII for your host character set; GDB does\n\
+not support any others.\n\
+To see a list of the character sets GDB supports, type `set host-charset <TAB>'."),
+                       set_host_charset_sfunc,
+                       show_host_charset_name,
+                       &setlist, &showlist);
+
+  add_setshow_enum_cmd ("target-charset", class_support,
+                       charset_enum, &target_charset_name, _("\
+Set the target character set."), _("\
+Show the target character set."), _("\
+The `target character set' is the one used by the program being debugged.\n\
+GDB translates characters and strings between the host and target\n\
+character sets as needed.\n\
+To see a list of the character sets GDB supports, type `set target-charset'<TAB>"),
+                       set_target_charset_sfunc,
+                       show_target_charset_name,
+                       &setlist, &showlist);
+
+  add_setshow_enum_cmd ("target-wide-charset", class_support,
+                       charset_enum, &target_wide_charset_name,
+                       _("\
+Set the target wide character set."), _("\
+Show the target wide character set."), _("\
+The `target wide character set' is the one used by the program being debugged.\
+\nIn particular it is the encoding used by `wchar_t'.\n\
+GDB translates characters and strings between the host and target\n\
+character sets as needed.\n\
+To see a list of the character sets GDB supports, type\n\
+`set target-wide-charset'<TAB>"),
+                       set_target_wide_charset_sfunc,
+                       show_target_wide_charset_name,
+                       &setlist, &showlist);
 }