Fix indentation in print_thread_info_1
[deliverable/binutils-gdb.git] / gdb / charset.c
index 2005a49e00917aff0432075cb0589be60af8e0b7..1af43fffa05859500a366d6fee99ab93b41a22c8 100644 (file)
@@ -1,12 +1,12 @@
 /* Character set conversion support for GDB.
 
-   Copyright 2001, 2003 Free Software Foundation, Inc.
+   Copyright (C) 2001-2020 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 "gdbsupport/gdb_wait.h"
+#include "charset-list.h"
+#include "gdbsupport/environ.h"
+#include "arch-utils.h"
+#include "gdbsupport/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.  */
-
-\f
-/* The character set and translation structures.  */
-
-
-/* A character set GDB knows about.  GDB only supports character sets
-   with stateless encodings, in which every character is one byte
-   long.  */
-struct charset {
-
-  /* A singly-linked list of all known charsets.  */
-  struct charset *next;
-
-  /* The name of the character set.  Comparisons on character set
-     names are case-sensitive.  */
-  const char *name;
-
-  /* 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;
-
-  /* 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;
-
-  int (*target_char_to_control_char) (void *baton,
-                                      int target_char,
-                                      int *target_ctrl_char);
-  void *target_char_to_control_char_baton;
-};
-
-
-/* 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;
-};
-
+     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 global lists of character sets and translations.  */
+#ifdef PHONY_ICONV
 
+/* Provide a phony iconv that does as little as possible.  Also,
+   arrange for there to be a single available character set.  */
 
-#ifndef GDB_DEFAULT_HOST_CHARSET
-#define GDB_DEFAULT_HOST_CHARSET "ISO-8859-1"
+#undef GDB_DEFAULT_HOST_CHARSET
+#ifdef USE_WIN32API
+# define GDB_DEFAULT_HOST_CHARSET "CP1252"
+#else
+# 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;
-
-static const char *host_charset_enum[] = 
+#define GDB_DEFAULT_TARGET_CHARSET GDB_DEFAULT_HOST_CHARSET 
+#define GDB_DEFAULT_TARGET_WIDE_CHARSET "UTF-32"
+#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
+
+/* We allow conversions from UTF-32, wchar_t, and the host charset.
+   We allow conversions to wchar_t and the host charset.
+   Return 1 if we are converting from UTF-32BE, 2 if from UTF32-LE,
+   0 otherwise.  This is used as a flag in calls to iconv.  */
+
+static iconv_t
+phony_iconv_open (const char *to, const char *from)
 {
-  "ASCII",
-  "ISO-8859-1",
-  0
-};
-
-static const char *target_charset_enum[] = 
-{
-  "ASCII",
-  "ISO-8859-1",
-  "EBCDIC-US",
-  "IBM1047",
-  0
-};
-
-/* The global list of all the charsets GDB knows about.  */
-static struct charset *all_charsets;
-
-
-static void
-register_charset (struct charset *cs)
-{
-  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;
-}
-
-
-static struct charset *
-lookup_charset (const char *name)
-{
-  struct charset *cs;
-
-  for (cs = all_charsets; cs; cs = cs->next)
-    if (! strcmp (name, cs->name))
-      return cs;
-
-  return NULL;
-}
+  if (strcmp (to, "wchar_t") && strcmp (to, GDB_DEFAULT_HOST_CHARSET))
+    return -1;
 
+  if (!strcmp (from, "UTF-32BE") || !strcmp (from, "UTF-32"))
+    return 1;
 
-/* The global list of translations.  */
-static struct translation *all_translations;
+  if (!strcmp (from, "UTF-32LE"))
+    return 2;
 
+  if (strcmp (from, "wchar_t") && strcmp (from, GDB_DEFAULT_HOST_CHARSET))
+    return -1;
 
-static void
-register_translation (struct translation *t)
-{
-  t->next = all_translations;
-  all_translations = t;
+  return 0;
 }
 
-
-static struct translation *
-lookup_translation (const char *from, const char *to)
+static int
+phony_iconv_close (iconv_t arg)
 {
-  struct translation *t;
-
-  for (t = all_translations; t; t = t->next)
-    if (! strcmp (from, t->from)
-        && ! strcmp (to, t->to))
-      return t;
-
   return 0;
 }
 
-
-\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 size_t
+phony_iconv (iconv_t utf_flag, const char **inbuf, size_t *inbytesleft,
+            char **outbuf, size_t *outbytesleft)
 {
-  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;
+  if (utf_flag)
+    {
+      enum bfd_endian endian
+       = utf_flag == 1 ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE;
+      while (*inbytesleft >= 4)
+       {
+         unsigned long c
+           = extract_unsigned_integer ((const gdb_byte *)*inbuf, 4, endian);
+
+         if (c >= 256)
+           {
+             errno = EILSEQ;
+             return -1;
+           }
+         if (*outbytesleft < 1)
+           {
+             errno = E2BIG;
+             return -1;
+           }
+         **outbuf = c & 0xff;
+         ++*outbuf;
+         --*outbytesleft;
+
+         *inbuf += 4;
+         *inbytesleft -= 4;
+       }
+      if (*inbytesleft)
+       {
+         /* Partial sequence on input.  */
+         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;
+      if (*inbytesleft)
+       {
+         errno = E2BIG;
+         return -1;
+       }
+    }
 
-  return cs;
+  /* The number of non-reversible conversions -- but they were all
+     reversible.  */
+  return 0;
 }
 
+#else /* PHONY_ICONV */
 
-\f
-/* ASCII functions.  */
+/* On systems that don't have EILSEQ, GNU iconv's iconv.h defines it
+   to ENOENT, while gnulib defines it to a different value.  Always
+   map ENOENT to gnulib's EILSEQ, leaving callers agnostic.  */
 
-static int
-ascii_print_literally (void *baton, int c)
+static size_t
+gdb_iconv (iconv_t utf_flag, ICONV_CONST char **inbuf, size_t *inbytesleft,
+          char **outbuf, size_t *outbytesleft)
 {
-  c &= 0xff;
+  size_t ret;
 
-  return (0x20 <= c && c <= 0x7e);
+  ret = iconv (utf_flag, inbuf, inbytesleft, outbuf, outbytesleft);
+  if (errno == ENOENT)
+    errno = EILSEQ;
+  return ret;
 }
 
+#undef iconv
+#define iconv gdb_iconv
 
-static int
-ascii_to_control (void *baton, int c, int *ctrl_char)
-{
-  *ctrl_char = (c & 037);
-  return 1;
-}
+#endif /* PHONY_ICONV */
 
 \f
-/* ISO-8859 family functions.  */
-
-
-static int
-iso_8859_print_literally (void *baton, int c)
-{
-  c &= 0xff;
-
-  return ((0x20 <= c && c <= 0x7e) /* ascii printables */
-          || (! sevenbit_strings && 0xA0 <= c)); /* iso 8859 printables */
-}
+/* The global lists of character sets and translations.  */
 
 
-static int
-iso_8859_to_control (void *baton, int c, int *ctrl_char)
-{
-  *ctrl_char = (c & 0200) | (c & 037);
-  return 1;
-}
+#ifndef GDB_DEFAULT_TARGET_CHARSET
+#define GDB_DEFAULT_TARGET_CHARSET "ISO-8859-1"
+#endif
 
+#ifndef GDB_DEFAULT_TARGET_WIDE_CHARSET
+#define GDB_DEFAULT_TARGET_WIDE_CHARSET "UTF-32"
+#endif
 
-/* Construct an ISO-8859-like character set.  */
-static struct charset *
-iso_8859_family_charset (const char *name)
+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)
 {
-  return simple_charset (name, 1,
-                         iso_8859_print_literally, 0,
-                         iso_8859_to_control, 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);
 }
 
-
-\f
-/* EBCDIC family functions.  */
-
-
-static int
-ebcdic_print_literally (void *baton, int c)
+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)
 {
-  c &= 0xff;
-
-  return (64 <= c && c <= 254);
+  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 int
-ebcdic_to_control (void *baton, int c, int *ctrl_char)
+static const char *target_wide_charset_name = "auto";
+static void
+show_target_wide_charset_name (struct ui_file *file, 
+                              int from_tty,
+                              struct cmd_list_element *c, 
+                              const char *value)
 {
-  /* There are no control character equivalents in EBCDIC.  Use
-     numeric escapes.  */
-  return 0;
+  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);
 }
 
-
-/* Construct an EBCDIC-like character set.  */
-static struct charset *
-ebcdic_family_charset (const char *name)
+static const char *default_charset_names[] =
 {
-  return simple_charset (name, 0,
-                         ebcdic_print_literally, 0,
-                         ebcdic_to_control, 0);
-}
-                
-
+  DEFAULT_CHARSET_NAMES
+  0
+};
 
+static const char **charset_enum;
 
 \f
-/* Fallback functions using iconv.  */
-
-#if defined(HAVE_ICONV)
+/* 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;
 
-struct cached_iconv {
-  struct charset *from, *to;
-  iconv_t i;
-};
+/* 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.  */
 
-/* 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)
+static void
+set_be_le_names (struct gdbarch *gdbarch)
 {
-  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)
+  if (be_le_arch == gdbarch)
+    return;
+  be_le_arch = gdbarch;
+
+#ifdef PHONY_ICONV
+  /* Match the wide charset names recognized by phony_iconv_open.  */
+  target_wide_charset_le_name = "UTF-32LE";
+  target_wide_charset_be_name = "UTF-32BE";
+#else
+  int i, len;
+  const char *target_wide;
+
+  target_wide_charset_le_name = NULL;
+  target_wide_charset_be_name = NULL;
+
+  target_wide = target_wide_charset_name;
+  if (!strcmp (target_wide, "auto"))
+    target_wide = gdbarch_auto_wide_charset (gdbarch);
+
+  len = strlen (target_wide);
+  for (i = 0; charset_enum[i]; ++i)
     {
-      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 (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];
+       }
     }
-
-  /* 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;
+# endif  /* PHONY_ICONV */
 }
 
+/* 'Set charset', 'set host-charset', 'set target-charset', 'set
+   target-wide-charset', 'set charset' sfunc's.  */
 
-/* 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)
+static void
+validate (struct gdbarch *gdbarch)
 {
-  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)
-    {
-      /* 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 (__FILE__, __LINE__,
-                     "Error converting character `%d' from `%s' to `%s' "
-                      "character set: %s",
-                      from_char, ci->from->name, ci->to->name,
-                      safe_strerror (errno));
-    }
-
-  /* If the pointers weren't advanced across the input, that also
-     suggests something was wrong.  */
-  gdb_assert (from_left == 0 && to_left == 0);
-
-  *to_char = (unsigned char) to;
-  return 1;
+  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;
 }
 
-
+/* This is the sfunc for the 'set charset' command.  */
 static void
-register_iconv_charsets (void)
+set_charset_sfunc (const char *charset, int from_tty, 
+                  struct cmd_list_element *c)
 {
-  /* 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.  */
+  /* CAREFUL: set the target charset here as well.  */
+  target_charset_name = host_charset_name;
+  validate (get_current_arch ());
 }
 
-#endif /* defined (HAVE_ICONV) */
-
-\f
-/* Fallback routines for systems without iconv.  */
-
-#if ! defined (HAVE_ICONV) 
-struct cached_iconv { char nothing; };
-
-static int
-check_iconv_cache (struct cached_iconv *ci,
-                   struct charset *from,
-                   struct charset *to)
+/* '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 (const char *charset, int from_tty,
+                       struct cmd_list_element *c)
 {
-  errno = EINVAL;
-  return -1;
+  validate (get_current_arch ());
 }
 
-static int
-cached_iconv_convert (struct cached_iconv *ci, int from_char, int *to_char)
+/* Wrapper for the 'set target-charset' command.  */
+static void
+set_target_charset_sfunc (const char *charset, int from_tty,
+                         struct cmd_list_element *c)
 {
-  /* This function should never be called.  */
-  gdb_assert (0);
+  validate (get_current_arch ());
 }
 
+/* Wrapper for the 'set target-wide-charset' command.  */
 static void
-register_iconv_charsets (void)
+set_target_wide_charset_sfunc (const char *charset, int from_tty,
+                              struct cmd_list_element *c)
 {
+  validate (get_current_arch ());
 }
 
-#endif /* ! defined(HAVE_ICONV) */
-
-\f
-/* Default trivial conversion functions.  */
-
-static int
-identity_either_char_to_other (void *baton, int either_char, int *other_char)
+/* 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)
 {
-  *other_char = either_char;
-  return 1;
+  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
-/* Default non-trivial conversion functions.  */
-
-
-static char backslashable[] = "abfnrtv";
-static char *backslashed[] = {"a", "b", "f", "n", "r", "t", "v", "0"};
-static char represented[] = "\a\b\f\n\r\t\v";
-
+/* Accessor functions.  */
 
-/* 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)
+const char *
+host_charset (void)
 {
-  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;
+  if (!strcmp (host_charset_name, "auto"))
+    return auto_host_charset_name;
+  return host_charset_name;
 }
 
-
-/* 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)
+const char *
+target_charset (struct gdbarch *gdbarch)
 {
-  const char *ix;
+  if (!strcmp (target_charset_name, "auto"))
+    return gdbarch_auto_charset (gdbarch);
+  return target_charset_name;
+}
 
-  ix = strchr (backslashable, host_char);
+const char *
+target_wide_charset (struct gdbarch *gdbarch)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
 
-  if (! ix)
-    return 0;
+  set_be_le_names (gdbarch);
+  if (byte_order == BFD_ENDIAN_BIG)
+    {
+      if (target_wide_charset_be_name)
+       return target_wide_charset_be_name;
+    }
   else
-    return host_char_to_target (represented[ix - backslashable],
-                                target_char);
-}
+    {
+      if (target_wide_charset_le_name)
+       return target_wide_charset_le_name;
+    }
 
+  if (!strcmp (target_wide_charset_name, "auto"))
+    return gdbarch_auto_wide_charset (gdbarch);
 
-/* 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);
+  return target_wide_charset_name;
 }
 
-
 \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 */
-};
+/* Host character set management.  For the time being, we assume that
+   the host character set is some superset of ASCII.  */
 
+char
+host_letter_to_control_character (char c)
+{
+  if (c == '?')
+    return 0177;
+  return c & 0237;
+}
 
-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 */
-};
+/* Convert a host character, C, to its hex value.  C must already have
+   been validated using isxdigit.  */
 
+int
+host_hex_value (char c)
+{
+  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';
+}
 
-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 */
-};
+\f
+/* Public character management functions.  */
 
+class iconv_wrapper
+{
+public:
 
-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 */
-};
+  iconv_wrapper (const char *to, const char *from)
+  {
+    m_desc = iconv_open (to, from);
+    if (m_desc == (iconv_t) -1)
+      perror_with_name (_("Converting character sets"));
+  }
 
+  ~iconv_wrapper ()
+  {
+    iconv_close (m_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 */
-};
+  size_t convert (ICONV_CONST char **inp, size_t *inleft, char **outp,
+                 size_t *outleft)
+  {
+    return iconv (m_desc, inp, inleft, outp, outleft);
+  }
 
+private:
 
-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 */
+  iconv_t m_desc;
 };
 
+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)
+{
+  size_t inleft;
+  ICONV_CONST char *inp;
+  unsigned int space_request;
 
-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 */
-};
-
+  /* Often, the host and target charsets will be the same.  */
+  if (!strcmp (from, to))
+    {
+      obstack_grow (output, bytes, num_bytes);
+      return;
+    }
 
-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 */
-};
+  iconv_wrapper desc (to, from);
 
+  inleft = num_bytes;
+  inp = (ICONV_CONST char *) bytes;
 
-static int
-table_convert_char (void *baton, int from, int *to)
-{
-  int *table = (int *) baton;
+  space_request = num_bytes;
 
-  if (0 <= from && from <= 255
-      && table[from] != -1)
+  while (inleft > 0)
     {
-      *to = table[from];
-      return 1;
+      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 = desc.convert (&inp, &inleft, &outp, &outleft);
+
+      /* Now make sure that the object on the obstack only includes
+        bytes we have converted.  */
+      obstack_blank_fast (output, -(ssize_t) 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"));
+           }
+       }
     }
-  else
-    return 0;
 }
 
+\f
 
-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)
+/* Create a new iterator.  */
+wchar_iterator::wchar_iterator (const gdb_byte *input, size_t bytes, 
+                               const char *charset, size_t width)
+: m_input (input),
+  m_bytes (bytes),
+  m_width (width),
+  m_out (1)
 {
-  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;
+  m_desc = iconv_open (INTERMEDIATE_ENCODING, charset);
+  if (m_desc == (iconv_t) -1)
+    perror_with_name (_("Converting character sets"));
 }
 
-
-static struct translation *
-simple_table_translation (const char *from, const char *to, int *table)
+wchar_iterator::~wchar_iterator ()
 {
-  return table_translation (from, to, table, 0, 0, 0, 0);
+  if (m_desc != (iconv_t) -1)
+    iconv_close (m_desc);
 }
 
+int
+wchar_iterator::iterate (enum wchar_iterate_result *out_result,
+                        gdb_wchar_t **out_chars,
+                        const gdb_byte **ptr,
+                        size_t *len)
+{
+  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 (m_bytes > 0)
+    {
+      ICONV_CONST char *inptr = (ICONV_CONST char *) m_input;
+      char *outptr = (char *) m_out.data ();
+      const gdb_byte *orig_inptr = m_input;
+      size_t orig_in = m_bytes;
+      size_t out_avail = out_request * sizeof (gdb_wchar_t);
+      size_t num;
+      size_t r = iconv (m_desc, &inptr, &m_bytes, &outptr, &out_avail);
+
+      m_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 = m_input;
+             *len = m_width;
+             m_input += m_width;
+             m_bytes -= m_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 > m_out.size ())
+               m_out.resize (out_request);
+             continue;
+
+           case EINVAL:
+             /* Incomplete input sequence.  Let the caller know, and
+                arrange for future calls to see EOF.  */
+             *out_result = wchar_iterate_incomplete;
+             *ptr = m_input;
+             *len = m_bytes;
+             m_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 = m_out.data ();
+      *ptr = orig_inptr;
+      *len = orig_in - m_bytes;
+      return num;
+    }
 
-\f
-/* Setting and retrieving the host and target charsets.  */
+  /* Really done.  */
+  *out_result = wchar_iterate_eof;
+  return -1;
+}
 
+struct charset_vector
+{
+  ~charset_vector ()
+  {
+    clear ();
+  }
 
-/* The current host and target character sets.  */
-static struct charset *current_host_charset, *current_target_charset;
+  void clear ()
+  {
+    for (char *c : charsets)
+      xfree (c);
 
-/* The current functions and batons we should use for the functions in
-   charset.h.  */
+    charsets.clear ();
+  }
 
-static const char *(*c_target_char_has_backslash_escape_func)
-     (void *baton, int target_char);
-static void *c_target_char_has_backslash_escape_baton;
+  std::vector<char *> charsets;
+};
 
-static int (*c_parse_backslash_func) (void *baton,
-                                      int host_char,
-                                      int *target_char);
-static void *c_parse_backslash_baton;
+static charset_vector 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)
+{
+  charsets.charsets.push_back (xstrdup (GDB_DEFAULT_HOST_CHARSET));
+  charsets.charsets.push_back (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);
-
-  return cs;
-}
+  for (i = 0; i < count; ++i)
+    charsets.charsets.push_back (xstrdup (names[i]));
 
-static void
-check_valid_host_charset (struct charset *cs)
-{
-  if (! cs->valid_host_charset)
-    error ("GDB can't use `%s' as its host character set.", cs->name);
+  return 0;
 }
 
-/* Set the host and target character sets to HOST and TARGET.  */
 static void
-set_host_and_target_charsets (struct charset *host, struct charset *target)
+find_charset_names (void)
 {
-  struct translation *h2t, *t2h;
+  iconvlist (add_one, NULL);
 
-  /* 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;
-    }
+  charsets.charsets.push_back (NULL);
+}
 
-  h2t = lookup_translation (host->name, target->name);
-  t2h = lookup_translation (target->name, host->name);
+#else
 
-  /* 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);
-        }
-    }
+/* 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.  */
 
-  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;
+  const char *args[3];
+  int err, status;
+  int fail = 1;
+  int flags;
+  gdb_environ iconv_env = gdb_environ::from_host_environ ();
+  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.set ("LANGUAGE", "C");
+  iconv_env.set ("LC_ALL", "C");
+
+  child = pex_init (PEX_USE_PIPES, "iconv", NULL);
+
+#ifdef ICONV_BIN
+  {
+    std::string iconv_dir = relocate_gdb_directory (ICONV_BIN,
+                                                   ICONV_BIN_RELOCATABLE);
+    iconv_program = concat (iconv_dir.c_str(), SLASH_STRING, "iconv", NULL);
+  }
+#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], const_cast<char **> (args),
+                              iconv_env.envp (),
+                              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';
+             charsets.charsets.push_back (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);
 
-/* 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.  */
+      charsets.clear ();
     }
   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 ());
-    }
+    charsets.charsets.push_back (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)
-{
-  return ((*c_target_char_has_backslash_escape_func)
-          (c_target_char_has_backslash_escape_baton, target_char));
-}
-
-
-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)
+default_auto_wide_charset (void)
 {
-  return ((*current_host_charset->host_char_print_literally)
-          (current_host_charset->host_char_print_literally_baton,
-           host_char));
+  return GDB_DEFAULT_TARGET_WIDE_CHARSET;
 }
 
 
-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
 
+/* 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));
-}
+gdb_static_assert (sizeof (gdb_wchar_t) == 2 || sizeof (gdb_wchar_t) == 4);
 
+/* 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.  */
-
-extern initialize_file_ftype _initialize_charset; /* -Wmissing-prototype */
+#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".  */
+  charsets.charsets.push_back (xstrdup ("auto"));
+  find_charset_names ();
 
+  if (charsets.charsets.size () > 1)
+    charset_enum = (const char **) charsets.charsets.data ();
+  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);
 }
This page took 0.047252 seconds and 4 git commands to generate.