/* Character set conversion support for GDB.
- Copyright (C) 2001-2014 Free Software Foundation, Inc.
+ Copyright (C) 2001-2017 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 "environ.h"
#include "arch-utils.h"
#include "gdb_vecs.h"
-
-#include <stddef.h>
-#include <string.h>
#include <ctype.h>
#ifdef USE_WIN32API
arrange for there to be a single available character set. */
#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"
+#ifdef USE_WIN32API
+# define GDB_DEFAULT_HOST_CHARSET "CP1252"
+#else
+# define GDB_DEFAULT_HOST_CHARSET "ISO-8859-1"
+#endif
+#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_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
+/* 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)
{
- /* 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;
- /* 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");
+ if (!strcmp (from, "UTF-32BE") || !strcmp (from, "UTF-32"))
+ return 1;
+
+ if (!strcmp (from, "UTF-32LE"))
+ return 2;
+
+ if (strcmp (from, "wchar_t") && strcmp (from, GDB_DEFAULT_HOST_CHARSET))
+ return -1;
+
+ return 0;
}
static int
{
if (utf_flag)
{
+ enum bfd_endian endian
+ = utf_flag == 1 ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE;
while (*inbytesleft >= 4)
{
- size_t j;
- unsigned long c = 0;
-
- for (j = 0; j < 4; ++j)
- {
- c <<= 8;
- c += (*inbuf)[j] & 0xff;
- }
+ 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;
+ *inbuf += 4;
*inbytesleft -= 4;
}
- if (*inbytesleft < 4)
+ if (*inbytesleft)
{
+ /* Partial sequence on input. */
errno = EINVAL;
return -1;
}
*outbuf += amt;
*inbytesleft -= amt;
*outbytesleft -= amt;
- }
-
- if (*inbytesleft)
- {
- errno = E2BIG;
- return -1;
+ if (*inbytesleft)
+ {
+ errno = E2BIG;
+ return -1;
+ }
}
/* The number of non-reversible conversions -- but they were all
return 0;
}
-#endif
+#else /* PHONY_ICONV */
+
+/* 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 size_t
+gdb_iconv (iconv_t utf_flag, ICONV_CONST char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ size_t ret;
+
+ ret = iconv (utf_flag, inbuf, inbytesleft, outbuf, outbytesleft);
+ if (errno == ENOENT)
+ errno = EILSEQ;
+ return ret;
+}
+
+#undef iconv
+#define iconv gdb_iconv
+
+#endif /* PHONY_ICONV */
\f
/* The global lists of character sets and translations. */
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
target_wide_charset_le_name = NULL;
target_wide_charset_be_name = NULL;
target_wide_charset_le_name = charset_enum[i];
}
}
+# endif /* PHONY_ICONV */
}
/* 'Set charset', 'set host-charset', 'set target-charset', 'set
static void
cleanup_iconv (void *p)
{
- iconv_t *descp = p;
+ iconv_t *descp = (iconv_t *) p;
iconv_close (*descp);
}
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, &inp, &inleft, &outp, &outleft);
/* Now make sure that the object on the obstack only includes
bytes we have converted. */
- obstack_blank (output, - (int) outleft);
+ obstack_blank_fast (output, -outleft);
if (r == (size_t) -1)
{
\f
-/* An iterator that returns host wchar_t's from a target string. */
-struct wchar_iterator
-{
- /* The underlying iconv descriptor. */
- iconv_t desc;
-
- /* 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;
-
- /* 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)
+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 wchar_iterator *result;
- iconv_t desc;
-
- desc = iconv_open (INTERMEDIATE_ENCODING, charset);
- if (desc == (iconv_t) -1)
+ m_desc = iconv_open (INTERMEDIATE_ENCODING, charset);
+ if (m_desc == (iconv_t) -1)
perror_with_name (_("Converting character sets"));
-
- 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;
-
- return result;
-}
-
-static void
-do_cleanup_iterator (void *p)
-{
- struct wchar_iterator *iter = p;
-
- iconv_close (iter->desc);
- xfree (iter->out);
- xfree (iter);
}
-struct cleanup *
-make_cleanup_wchar_iterator (struct wchar_iterator *iter)
+wchar_iterator::~wchar_iterator ()
{
- return make_cleanup (do_cleanup_iterator, iter);
+ if (m_desc != (iconv_t) -1)
+ iconv_close (m_desc);
}
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)
+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;
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)
+ while (m_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;
+ 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 (iter->desc, &inptr, &iter->bytes, &outptr, &out_avail);
+ size_t r = iconv (m_desc, &inptr, &m_bytes, &outptr, &out_avail);
- iter->input = (gdb_byte *) inptr;
+ m_input = (gdb_byte *) inptr;
if (r == (size_t) -1)
{
/* 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;
+ *ptr = m_input;
+ *len = m_width;
+ m_input += m_width;
+ m_bytes -= m_width;
return 0;
case E2BIG:
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));
- }
+ if (out_request > m_out.size ())
+ m_out.reserve (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 = iter->input;
- *len = iter->bytes;
- iter->bytes = 0;
+ *ptr = m_input;
+ *len = m_bytes;
+ m_bytes = 0;
return 0;
default:
/* We converted something. */
num = out_request - out_avail / sizeof (gdb_wchar_t);
*out_result = wchar_iterate_ok;
- *out_chars = iter->out;
+ *out_chars = m_out.data ();
*ptr = orig_inptr;
- *len = orig_in - iter->bytes;
+ *len = orig_in - m_bytes;
return num;
}