Enable Gold linker for cross-*-binutils build
[platform/upstream/binutils.git] / gdb / charset.c
index 9c35867..bc7bd65 100644 (file)
@@ -1,7 +1,6 @@
 /* Character set conversion support for GDB.
 
-   Copyright (C) 2001, 2003, 2007, 2008, 2009, 2010, 2011
-   Free Software Foundation, Inc.
+   Copyright (C) 2001-2014 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "defs.h"
 #include "charset.h"
 #include "gdbcmd.h"
-#include "gdb_assert.h"
 #include "gdb_obstack.h"
 #include "gdb_wait.h"
 #include "charset-list.h"
 #include "vec.h"
 #include "environ.h"
 #include "arch-utils.h"
-
-#include <stddef.h>
-#include "gdb_string.h"
+#include "gdb_vecs.h"
 #include <ctype.h>
 
 #ifdef USE_WIN32API
 #define EILSEQ ENOENT
 #endif
 
-iconv_t
+static iconv_t
 phony_iconv_open (const char *to, const char *from)
 {
   /* We allow conversions from UTF-32BE, wchar_t, and the host charset.
@@ -124,13 +120,13 @@ phony_iconv_open (const char *to, const char *from)
   return !strcmp (from, "UTF-32BE");
 }
 
-int
+static int
 phony_iconv_close (iconv_t arg)
 {
   return 0;
 }
 
-size_t
+static size_t
 phony_iconv (iconv_t utf_flag, const char **inbuf, size_t *inbytesleft,
             char **outbuf, size_t *outbytesleft)
 {
@@ -324,13 +320,13 @@ validate (struct gdbarch *gdbarch)
 
   desc = iconv_open (target_wide_cset, host_cset);
   if (desc == (iconv_t) -1)
-    error ("Cannot convert between character sets `%s' and `%s'",
+    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'",
+    error (_("Cannot convert between character sets `%s' and `%s'"),
           target_cset, host_cset);
   iconv_close (desc);
 
@@ -474,7 +470,7 @@ convert_between_encodings (const char *from, const char *to,
   iconv_t desc;
   struct cleanup *cleanups;
   size_t inleft;
-  char *inp;
+  ICONV_CONST char *inp;
   unsigned int space_request;
 
   /* Often, the host and target charsets will be the same.  */
@@ -486,11 +482,11 @@ convert_between_encodings (const char *from, const char *to,
 
   desc = iconv_open (to, from);
   if (desc == (iconv_t) -1)
-    perror_with_name ("Converting character sets");
+    perror_with_name (_("Converting character sets"));
   cleanups = make_cleanup (cleanup_iconv, &desc);
 
   inleft = num_bytes;
-  inp = (char *) bytes;
+  inp = (ICONV_CONST char *) bytes;
 
   space_request = num_bytes;
 
@@ -503,10 +499,10 @@ convert_between_encodings (const char *from, const char *to,
       old_size = obstack_object_size (output);
       obstack_blank (output, space_request);
 
-      outp = obstack_base (output) + old_size;
+      outp = (char *) obstack_base (output) + old_size;
       outleft = space_request;
 
-      r = iconv (desc, (ICONV_CONST char **) &inp, &inleft, &outp, &outleft);
+      r = iconv (desc, &inp, &inleft, &outp, &outleft);
 
       /* Now make sure that the object on the obstack only includes
         bytes we have converted.  */
@@ -531,7 +527,7 @@ convert_between_encodings (const char *from, const char *to,
                  {
                    char octal[5];
 
-                   sprintf (octal, "\\%.3o", *inp & 0xff);
+                   xsnprintf (octal, sizeof (octal), "\\%.3o", *inp & 0xff);
                    obstack_grow_str (output, octal);
 
                    ++inp;
@@ -553,8 +549,8 @@ convert_between_encodings (const char *from, const char *to,
              break;
 
            default:
-             perror_with_name ("Internal error while "
-                               "converting character sets");
+             perror_with_name (_("Internal error while "
+                                 "converting character sets"));
            }
        }
     }
@@ -571,7 +567,7 @@ struct wchar_iterator
   iconv_t desc;
 
   /* The input string.  This is updated as convert characters.  */
-  char *input;
+  const gdb_byte *input;
   /* The number of bytes remaining in the input.  */
   size_t bytes;
 
@@ -593,11 +589,11 @@ make_wchar_iterator (const gdb_byte *input, size_t bytes,
 
   desc = iconv_open (INTERMEDIATE_ENCODING, charset);
   if (desc == (iconv_t) -1)
-    perror_with_name ("Converting character sets");
+    perror_with_name (_("Converting character sets"));
 
   result = XNEW (struct wchar_iterator);
   result->desc = desc;
-  result->input = (char *) input;
+  result->input = input;
   result->bytes = bytes;
   result->width = width;
 
@@ -640,14 +636,15 @@ wchar_iterate (struct wchar_iterator *iter,
   out_request = 1;
   while (iter->bytes > 0)
     {
+      ICONV_CONST char *inptr = (ICONV_CONST char *) iter->input;
       char *outptr = (char *) &iter->out[0];
-      char *orig_inptr = iter->input;
+      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,
-                       (ICONV_CONST char **) &iter->input, 
-                       &iter->bytes, &outptr, &out_avail);
+      size_t r = iconv (iter->desc, &inptr, &iter->bytes, &outptr, &out_avail);
+
+      iter->input = (gdb_byte *) inptr;
 
       if (r == (size_t) -1)
        {
@@ -694,8 +691,8 @@ wchar_iterate (struct wchar_iterator *iter,
              return 0;
 
            default:
-             perror_with_name ("Internal error while "
-                               "converting character sets");
+             perror_with_name (_("Internal error while "
+                                 "converting character sets"));
            }
        }
 
@@ -718,8 +715,6 @@ wchar_iterate (struct wchar_iterator *iter,
 
 extern initialize_file_ftype _initialize_charset; /* -Wmissing-prototype */
 
-DEF_VEC_P (char_ptr);
-
 static VEC (char_ptr) *charsets;
 
 #ifdef PHONY_ICONV
@@ -799,7 +794,9 @@ find_charset_names (void)
   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
@@ -811,12 +808,26 @@ find_charset_names (void)
 
   child = pex_init (PEX_USE_PIPES, "iconv", NULL);
 
-  args[0] = "iconv";
+#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, PEX_SEARCH | PEX_STDERR_TO_STDOUT,
-                              "iconv", args, environ_vector (iconv_env),
+  if (!pex_run_in_environment (child, flags,
+                              args[0], args, environ_vector (iconv_env),
                               NULL, NULL, &err))
     {
       FILE *in = pex_read_output (child, 0);
@@ -825,7 +836,7 @@ find_charset_names (void)
         parse the glibc and libiconv formats; feel free to add others
         as needed.  */
 
-      while (!feof (in))
+      while (in != NULL && !feof (in))
        {
          /* The size of buf is chosen arbitrarily.  */
          char buf[1024];
@@ -888,17 +899,15 @@ find_charset_names (void)
 
     }
 
+  xfree (iconv_program);
   pex_free (child);
   free_environ (iconv_env);
 
   if (fail)
     {
       /* Some error occurred, so drop the vector.  */
-      int ix;
-      char *elt;
-      for (ix = 0; VEC_iterate (char_ptr, charsets, ix, elt); ++ix)
-       xfree (elt);
-      VEC_truncate (char_ptr, charsets, 0);
+      free_char_ptr_vec (charsets);
+      charsets = NULL;
     }
   else
     VEC_safe_push (char_ptr, charsets, NULL);
@@ -922,6 +931,71 @@ default_auto_wide_charset (void)
   return GDB_DEFAULT_TARGET_WIDE_CHARSET;
 }
 
+
+#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.  */
+
+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.  */
+
+const char *
+intermediate_encoding (void)
+{
+  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"));
+}
+
+#endif /* USE_INTERMEDIATE_ENCODING_FUNCTION */
+
 void
 _initialize_charset (void)
 {