diff options
Diffstat (limited to 'gdb/charset.c')
-rw-r--r-- | gdb/charset.c | 1555 |
1 files changed, 542 insertions, 1013 deletions
diff --git a/gdb/charset.c b/gdb/charset.c index 32eb9c3..5efb849 100644 --- a/gdb/charset.c +++ b/gdb/charset.c @@ -21,27 +21,31 @@ #include "charset.h" #include "gdbcmd.h" #include "gdb_assert.h" +#include "gdb_obstack.h" +#include "charset-list.h" +#include "vec.h" #include <stddef.h> #include "gdb_string.h" #include <ctype.h> -#ifdef HAVE_ICONV -#include <iconv.h> -#endif - /* 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 @@ -57,118 +61,141 @@ characters the user enters in expressions (mostly host->target conversions), - and so on. - - Now, many of these operations are specific to a particular - host/target character set pair. If GDB supports N character sets, - there are N^2 possible pairs. This means that, the larger GDB's - repertoire of character sets gets, the more expensive it gets to add - new character sets. - - To make sure that GDB can do the right thing for every possible - pairing of host and target character set, while still allowing - GDB's repertoire to scale, we use a two-tiered approach: - - - We maintain a global table of "translations" --- groups of - functions specific to a particular pair of character sets. - - - However, a translation can be incomplete: some functions can be - omitted. Where there is not a translation to specify exactly - what function to use, we provide reasonable defaults. The - default behaviors try to use the "iconv" library functions, which - support a wide range of character sets. However, even if iconv - is not available, there are fallbacks to support trivial - translations: when the host and target character sets are the - same. */ + and so on. + + To avoid excessive code duplication and maintenance efforts, + GDB simply requires a capable iconv function. Users on platforms + without a suitable iconv can use the GNU iconv library. */ -/* The character set and translation structures. */ - +#ifdef PHONY_ICONV -/* A character set GDB knows about. GDB only supports character sets - with stateless encodings, in which every character is one byte - long. */ -struct charset { +/* Provide a phony iconv that does as little as possible. Also, + arrange for there to be a single available character set. */ - /* A singly-linked list of all known charsets. */ - struct charset *next; +#undef GDB_DEFAULT_HOST_CHARSET +#define GDB_DEFAULT_HOST_CHARSET "ISO-8859-1" +#define GDB_DEFAULT_TARGET_CHARSET "ISO-8859-1" +#define GDB_DEFAULT_TARGET_WIDE_CHARSET "ISO-8859-1" +#undef DEFAULT_CHARSET_NAMES +#define DEFAULT_CHARSET_NAMES GDB_DEFAULT_HOST_CHARSET , + +#undef iconv_t +#define iconv_t int +#undef iconv_open +#undef iconv +#undef iconv_close + +iconv_t +iconv_open (const char *to, const char *from) +{ + /* We allow conversions from UCS-4BE, wchar_t, and the host charset. + We allow conversions to wchar_t and the host charset. */ + if (strcmp (from, "UCS-4BE") && strcmp (from, "wchar_t") + && strcmp (from, GDB_DEFAULT_HOST_CHARSET)) + return -1; + if (strcmp (to, "wchar_t") && strcmp (to, GDB_DEFAULT_HOST_CHARSET)) + return -1; - /* The name of the character set. Comparisons on character set - names are case-sensitive. */ - const char *name; + /* Return 1 if we are converting from UCS-4BE, 0 otherwise. This is + used as a flag in calls to iconv. */ + return !strcmp (from, "UCS-4BE"); +} - /* 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; +int +iconv_close (iconv_t arg) +{ + return 0; +} - /* Pointers to charset-specific functions that depend only on a - single character set, and data pointers to pass to them. */ - int (*host_char_print_literally) (void *baton, - int host_char); - void *host_char_print_literally_baton; +size_t +iconv (iconv_t ucs_flag, char **inbuf, size_t *inbytesleft, + char **outbuf, size_t *outbytesleft) +{ + if (ucs_flag) + { + while (*inbytesleft >= 4) + { + size_t j; + unsigned long c = 0; + + for (j = 0; j < 4; ++j) + { + c <<= 8; + c += (*inbuf)[j] & 0xff; + } + + if (c >= 256) + { + errno = EILSEQ; + return -1; + } + **outbuf = c & 0xff; + ++*outbuf; + --*outbytesleft; + + ++*inbuf; + *inbytesleft -= 4; + } + if (*inbytesleft < 4) + { + errno = EINVAL; + return -1; + } + } + else + { + /* In all other cases we simply copy input bytes to the + output. */ + size_t amt = *inbytesleft; + if (amt > *outbytesleft) + amt = *outbytesleft; + memcpy (*outbuf, *inbuf, amt); + *inbuf += amt; + *outbuf += amt; + *inbytesleft -= amt; + *outbytesleft -= amt; + } - int (*target_char_to_control_char) (void *baton, - int target_char, - int *target_ctrl_char); - void *target_char_to_control_char_baton; -}; + if (*inbytesleft) + { + errno = E2BIG; + return -1; + } + /* The number of non-reversible conversions -- but they were all + reversible. */ + return 0; +} -/* A translation from one character set to another. */ -struct translation { - - /* A singly-linked list of all known translations. */ - struct translation *next; - - /* This structure describes functions going from the FROM character - set to the TO character set. Comparisons on character set names - are case-sensitive. */ - const char *from, *to; - - /* Pointers to translation-specific functions, and data pointers to - pass to them. These pointers can be zero, indicating that GDB - should fall back on the default behavior. We hope the default - behavior will be correct for many from/to pairs, reducing the - number of translations that need to be registered explicitly. */ - - /* TARGET_CHAR is in the `from' charset. - Returns a string in the `to' charset. */ - const char *(*c_target_char_has_backslash_escape) (void *baton, - int target_char); - void *c_target_char_has_backslash_escape_baton; - - /* HOST_CHAR is in the `from' charset. - TARGET_CHAR points to a char in the `to' charset. */ - int (*c_parse_backslash) (void *baton, int host_char, int *target_char); - void *c_parse_backslash_baton; - - /* This is used for the host_char_to_target and target_char_to_host - functions. */ - int (*convert_char) (void *baton, int from, int *to); - void *convert_char_baton; -}; +#endif /* The global lists of character sets and translations. */ -#ifndef GDB_DEFAULT_HOST_CHARSET -#define GDB_DEFAULT_HOST_CHARSET "ISO-8859-1" -#endif - #ifndef GDB_DEFAULT_TARGET_CHARSET #define GDB_DEFAULT_TARGET_CHARSET "ISO-8859-1" #endif -static const char *host_charset_name = GDB_DEFAULT_HOST_CHARSET; +#ifndef GDB_DEFAULT_TARGET_WIDE_CHARSET +#define GDB_DEFAULT_TARGET_WIDE_CHARSET "UCS-4" +#endif + +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) { - fprintf_filtered (file, _("The host character set is \"%s\".\n"), value); + if (!strcmp (value, "auto")) + fprintf_filtered (file, + _("The host character set is \"auto; currently %s\".\n"), + auto_host_charset_name); + else + fprintf_filtered (file, _("The host character set is \"%s\".\n"), value); } static const char *target_charset_name = GDB_DEFAULT_TARGET_CHARSET; @@ -180,1060 +207,547 @@ show_target_charset_name (struct ui_file *file, int from_tty, value); } - -static const char *host_charset_enum[] = +static const char *target_wide_charset_name = GDB_DEFAULT_TARGET_WIDE_CHARSET; +static void +show_target_wide_charset_name (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) { - "ASCII", - "ISO-8859-1", - 0 -}; + fprintf_filtered (file, _("The target wide character set is \"%s\".\n"), + value); +} -static const char *target_charset_enum[] = +static const char *default_charset_names[] = { - "ASCII", - "ISO-8859-1", - "EBCDIC-US", - "IBM1047", + DEFAULT_CHARSET_NAMES 0 }; -/* The global list of all the charsets GDB knows about. */ -static struct charset *all_charsets; +static const char **charset_enum; + +/* 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; -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; -} - +/* A helper function for validate which sets the target wide big- and + little-endian character set names, if possible. */ -static struct charset * -lookup_charset (const char *name) +static void +set_be_le_names (void) { - struct charset *cs; + int i, len; - for (cs = all_charsets; cs; cs = cs->next) - if (! strcmp (name, cs->name)) - return cs; + target_wide_charset_le_name = NULL; + target_wide_charset_be_name = NULL; - return NULL; + len = strlen (target_wide_charset_name); + for (i = 0; charset_enum[i]; ++i) + { + if (strncmp (target_wide_charset_name, 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]; + } + } } - -/* The global list of translations. */ -static struct translation *all_translations; - +/* 'Set charset', 'set host-charset', 'set target-charset', 'set + target-wide-charset', 'set charset' sfunc's. */ static void -register_translation (struct translation *t) -{ - t->next = all_translations; - all_translations = t; -} - - -static struct translation * -lookup_translation (const char *from, const char *to) +validate (void) { - struct translation *t; + iconv_t desc; + const char *host_cset = host_charset (); - for (t = all_translations; t; t = t->next) - if (! strcmp (from, t->from) - && ! strcmp (to, t->to)) - return t; - - return 0; -} + desc = iconv_open (target_wide_charset_name, host_cset); + if (desc == (iconv_t) -1) + error ("Cannot convert between character sets `%s' and `%s'", + target_wide_charset_name, host_cset); + iconv_close (desc); + desc = iconv_open (target_charset_name, host_cset); + if (desc == (iconv_t) -1) + error ("Cannot convert between character sets `%s' and `%s'", + target_charset_name, host_cset); + iconv_close (desc); - -/* 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) -{ - struct charset *cs = xmalloc (sizeof (*cs)); - - memset (cs, 0, sizeof (*cs)); - cs->name = name; - cs->valid_host_charset = valid_host_charset; - cs->host_char_print_literally = host_char_print_literally; - cs->host_char_print_literally_baton = host_char_print_literally_baton; - cs->target_char_to_control_char = target_char_to_control_char; - cs->target_char_to_control_char_baton = target_char_to_control_char_baton; - - return cs; + set_be_le_names (); } - - -/* ASCII functions. */ - -static int -ascii_print_literally (void *baton, int c) +/* This is the sfunc for the 'set charset' command. */ +static void +set_charset_sfunc (char *charset, int from_tty, struct cmd_list_element *c) { - c &= 0xff; - - return (0x20 <= c && c <= 0x7e); + /* CAREFUL: set the target charset here as well. */ + target_charset_name = host_charset_name; + validate (); } - -static int -ascii_to_control (void *baton, int c, int *ctrl_char) +/* 'set host-charset' command sfunc. We need a wrapper here because + the function needs to have a specific signature. */ +static void +set_host_charset_sfunc (char *charset, int from_tty, + struct cmd_list_element *c) { - *ctrl_char = (c & 037); - return 1; + validate (); } - -/* ISO-8859 family functions. */ - - -static int -iso_8859_print_literally (void *baton, int c) +/* Wrapper for the 'set target-charset' command. */ +static void +set_target_charset_sfunc (char *charset, int from_tty, + struct cmd_list_element *c) { - c &= 0xff; - - return ((0x20 <= c && c <= 0x7e) /* ascii printables */ - || (! sevenbit_strings && 0xA0 <= c)); /* iso 8859 printables */ + validate (); } - -static int -iso_8859_to_control (void *baton, int c, int *ctrl_char) +/* Wrapper for the 'set target-wide-charset' command. */ +static void +set_target_wide_charset_sfunc (char *charset, int from_tty, + struct cmd_list_element *c) { - *ctrl_char = (c & 0200) | (c & 037); - return 1; + validate (); } - -/* Construct an ISO-8859-like character set. */ -static struct charset * -iso_8859_family_charset (const char *name) +/* sfunc for the 'show charset' command. */ +static void +show_charset (struct ui_file *file, int from_tty, struct cmd_list_element *c, + const char *name) { - return simple_charset (name, 1, - iso_8859_print_literally, 0, - iso_8859_to_control, 0); + show_host_charset_name (file, from_tty, c, host_charset_name); + show_target_charset_name (file, from_tty, c, target_charset_name); + show_target_wide_charset_name (file, from_tty, c, target_wide_charset_name); } - -/* EBCDIC family functions. */ - - -static int -ebcdic_print_literally (void *baton, int c) -{ - c &= 0xff; - - return (64 <= c && c <= 254); -} - +/* Accessor functions. */ -static int -ebcdic_to_control (void *baton, int c, int *ctrl_char) +const char * +host_charset (void) { - /* There are no control character equivalents in EBCDIC. Use - numeric escapes. */ - return 0; + if (!strcmp (host_charset_name, "auto")) + return auto_host_charset_name; + return host_charset_name; } - -/* Construct an EBCDIC-like character set. */ -static struct charset * -ebcdic_family_charset (const char *name) +const char * +target_charset (void) { - return simple_charset (name, 0, - ebcdic_print_literally, 0, - ebcdic_to_control, 0); + return target_charset_name; } - - - - - -/* Fallback functions using iconv. */ - -#if defined(HAVE_ICONV) - -struct cached_iconv { - struct charset *from, *to; - iconv_t i; -}; - -/* 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) +const char * +target_wide_charset (void) { - 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 (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG) { - i = ci->i; - ci->i = (iconv_t) 0; - - if (iconv_close (i) == -1) - error (_("Error closing `iconv' descriptor for " - "`%s'-to-`%s' character conversion: %s"), - ci->from->name, ci->to->name, safe_strerror (errno)); + if (target_wide_charset_be_name) + return target_wide_charset_be_name; } - - /* Open a new iconv descriptor for the required conversion. */ - i = iconv_open (to->name, from->name); - if (i == (iconv_t) -1) - return -1; - - ci->i = i; - ci->from = from; - ci->to = to; - - return 0; -} - - -/* Convert FROM_CHAR using the cached iconv conversion *CI. Return - non-zero if the conversion was successful, zero otherwise. */ -static int -cached_iconv_convert (struct cached_iconv *ci, int from_char, int *to_char) -{ - char from; - ICONV_CONST char *from_ptr = &from; - char to, *to_ptr = &to; - size_t from_left = sizeof (from), to_left = sizeof (to); - - gdb_assert (ci->i != (iconv_t) 0); - - from = from_char; - if (iconv (ci->i, &from_ptr, &from_left, &to_ptr, &to_left) - == (size_t) -1) + else { - /* These all suggest that the input or output character sets - have multi-byte encodings of some characters, which means - it's unsuitable for use as a GDB character set. We should - never have selected it. */ - gdb_assert (errno != E2BIG && errno != EINVAL); - - /* This suggests a bug in the code managing *CI. */ - gdb_assert (errno != EBADF); - - /* This seems to mean that there is no equivalent character in - the `to' character set. */ - if (errno == EILSEQ) - return 0; - - /* Anything else is mysterious. */ - internal_error (__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 (target_wide_charset_le_name) + return target_wide_charset_le_name; } - /* If the pointers weren't advanced across the input, that also - suggests something was wrong. */ - gdb_assert (from_left == 0 && to_left == 0); - - *to_char = (unsigned char) to; - return 1; + return target_wide_charset_name; } - -static void -register_iconv_charsets (void) -{ - /* Here we should check whether various character sets were - recognized by the local iconv implementation. - - The first implementation registered a bunch of character sets - recognized by iconv, but then we discovered that iconv on Solaris - and iconv on GNU/Linux had no character sets in common. So we - replaced them with the hard-coded tables that appear later in the - file. */ -} - -#endif /* defined (HAVE_ICONV) */ - -/* Fallback routines for systems without iconv. */ +/* Host character set management. For the time being, we assume that + the host character set is some superset of ASCII. */ -#if ! defined (HAVE_ICONV) -struct cached_iconv { char nothing; }; - -static int -check_iconv_cache (struct cached_iconv *ci, - struct charset *from, - struct charset *to) -{ - errno = EINVAL; - return -1; -} - -static int -cached_iconv_convert (struct cached_iconv *ci, int from_char, int *to_char) -{ - /* This function should never be called. */ - gdb_assert (0); -} - -static void -register_iconv_charsets (void) +char +host_letter_to_control_character (char c) { + if (c == '?') + return 0177; + return c & 0237; } -#endif /* ! defined(HAVE_ICONV) */ +/* Convert a host character, C, to its hex value. C must already have + been validated using isxdigit. */ - -/* Default trivial conversion functions. */ - -static int -identity_either_char_to_other (void *baton, int either_char, int *other_char) +int +host_hex_value (char c) { - *other_char = either_char; - return 1; + if (isdigit (c)) + return c - '0'; + if (c >= 'a' && c <= 'f') + return 10 + c - 'a'; + gdb_assert (c >= 'A' && c <= 'F'); + return 10 + c - 'A'; } - -/* 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"; - - -/* 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) -{ - 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; -} - - -/* 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 *ix; - - ix = strchr (backslashable, host_char); - - if (! ix) - return 0; - else - return host_char_to_target (represented[ix - backslashable], - target_char); -} +/* Public character management functions. */ +/* A cleanup function which is run to close an iconv descriptor. */ -/* Convert using a cached iconv descriptor. */ -static int -iconv_convert (void *baton, int from_char, int *to_char) +static void +cleanup_iconv (void *p) { - struct cached_iconv *ci = baton; - return cached_iconv_convert (ci, from_char, to_char); + iconv_t *descp = p; + iconv_close (*descp); } +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) +{ + iconv_t desc; + struct cleanup *cleanups; + size_t inleft; + char *inp; + unsigned int space_request; + + /* Often, the host and target charsets will be the same. */ + if (!strcmp (from, to)) + { + obstack_grow (output, bytes, num_bytes); + return; + } - -/* Conversion tables. */ - - -/* I'd much rather fall back on iconv whenever possible. But the - character set names you use with iconv aren't standardized at all, - a lot of platforms have really meager character set coverage, etc. - I wanted to have at least something we could use to exercise the - test suite on all platforms. - - In the long run, we should have a configure-time process explore - somehow which character sets the host platform supports, and some - arrangement that allows GDB users to use platform-indepedent names - for character sets. */ - - -/* We generated these tables using iconv on a GNU/Linux machine. */ - - -static int ascii_to_iso_8859_1_table[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 16 */ - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 32 */ - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 48 */ - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 64 */ - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 80 */ - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 96 */ - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, /* 112 */ - 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, /* 128 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 256 */ -}; - - -static int ascii_to_ebcdic_us_table[] = { - 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15, /* 16 */ - 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, /* 32 */ - 64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97, /* 48 */ - 240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111, /* 64 */ - 124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, /* 80 */ - 215,216,217,226,227,228,229,230,231,232,233, -1,224, -1, -1,109, /* 96 */ - 121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, /* 112 */ - 151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161, 7, /* 128 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 256 */ -}; - - -static int ascii_to_ibm1047_table[] = { - 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15, /* 16 */ - 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, /* 32 */ - 64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97, /* 48 */ - 240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111, /* 64 */ - 124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, /* 80 */ - 215,216,217,226,227,228,229,230,231,232,233,173,224,189, 95,109, /* 96 */ - 121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, /* 112 */ - 151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161, 7, /* 128 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 256 */ -}; - - -static int iso_8859_1_to_ascii_table[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 16 */ - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 32 */ - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 48 */ - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 64 */ - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 80 */ - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 96 */ - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, /* 112 */ - 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, /* 128 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 256 */ -}; - - -static int iso_8859_1_to_ebcdic_us_table[] = { - 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15, /* 16 */ - 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, /* 32 */ - 64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97, /* 48 */ - 240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111, /* 64 */ - 124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, /* 80 */ - 215,216,217,226,227,228,229,230,231,232,233, -1,224, -1, -1,109, /* 96 */ - 121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, /* 112 */ - 151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161, 7, /* 128 */ - 32, 33, 34, 35, 36, 21, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27, /* 144 */ - 48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59, 4, 20, 62,255, /* 160 */ - -1, -1, 74, -1, -1, -1,106, -1, -1, -1, -1, -1, 95, -1, -1, -1, /* 176 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 256 */ -}; - - -static int iso_8859_1_to_ibm1047_table[] = { - 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15, /* 16 */ - 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, /* 32 */ - 64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97, /* 48 */ - 240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111, /* 64 */ - 124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, /* 80 */ - 215,216,217,226,227,228,229,230,231,232,233,173,224,189, 95,109, /* 96 */ - 121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, /* 112 */ - 151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161, 7, /* 128 */ - 32, 33, 34, 35, 36, 21, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27, /* 144 */ - 48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59, 4, 20, 62,255, /* 160 */ - 65,170, 74,177,159,178,106,181,187,180,154,138,176,202,175,188, /* 176 */ - 144,143,234,250,190,160,182,179,157,218,155,139,183,184,185,171, /* 192 */ - 100,101, 98,102, 99,103,158,104,116,113,114,115,120,117,118,119, /* 208 */ - 172,105,237,238,235,239,236,191,128,253,254,251,252,186,174, 89, /* 224 */ - 68, 69, 66, 70, 67, 71,156, 72, 84, 81, 82, 83, 88, 85, 86, 87, /* 240 */ - 140, 73,205,206,203,207,204,225,112,221,222,219,220,141,142,223 /* 256 */ -}; - - -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 */ -}; - - -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 */ -}; - - -static int ebcdic_us_to_ibm1047_table[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 16 */ - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 32 */ - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 48 */ - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 64 */ - 64, -1, -1, -1, -1, -1, -1, -1, -1, -1, 74, 75, 76, 77, 78, 79, /* 80 */ - 80, -1, -1, -1, -1, -1, -1, -1, -1, -1, 90, 91, 92, 93, 94,176, /* 96 */ - 96, 97, -1, -1, -1, -1, -1, -1, -1, -1,106,107,108,109,110,111, /* 112 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1,121,122,123,124,125,126,127, /* 128 */ - -1,129,130,131,132,133,134,135,136,137, -1, -1, -1, -1, -1, -1, /* 144 */ - -1,145,146,147,148,149,150,151,152,153, -1, -1, -1, -1, -1, -1, /* 160 */ - -1,161,162,163,164,165,166,167,168,169, -1, -1, -1, -1, -1, -1, /* 176 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ - 192,193,194,195,196,197,198,199,200,201, -1, -1, -1, -1, -1, -1, /* 208 */ - 208,209,210,211,212,213,214,215,216,217, -1, -1, -1, -1, -1, -1, /* 224 */ - 224, -1,226,227,228,229,230,231,232,233, -1, -1, -1, -1, -1, -1, /* 240 */ - 240,241,242,243,244,245,246,247,248,249, -1, -1, -1, -1, -1,255 /* 256 */ -}; - - -static int ibm1047_to_ascii_table[] = { - 0, 1, 2, 3, -1, 9, -1,127, -1, -1, -1, 11, 12, 13, 14, 15, /* 16 */ - 16, 17, 18, 19, -1, -1, 8, -1, 24, 25, -1, -1, 28, 29, 30, 31, /* 32 */ - -1, -1, -1, -1, -1, 10, 23, 27, -1, -1, -1, -1, -1, 5, 6, 7, /* 48 */ - -1, -1, 22, -1, -1, -1, -1, 4, -1, -1, -1, -1, 20, 21, -1, 26, /* 64 */ - 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, 60, 40, 43,124, /* 80 */ - 38, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, 36, 42, 41, 59, 94, /* 96 */ - 45, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, 37, 95, 62, 63, /* 112 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, 96, 58, 35, 64, 39, 61, 34, /* 128 */ - -1, 97, 98, 99,100,101,102,103,104,105, -1, -1, -1, -1, -1, -1, /* 144 */ - -1,106,107,108,109,110,111,112,113,114, -1, -1, -1, -1, -1, -1, /* 160 */ - -1,126,115,116,117,118,119,120,121,122, -1, -1, -1, 91, -1, -1, /* 176 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 93, -1, -1, /* 192 */ - 123, 65, 66, 67, 68, 69, 70, 71, 72, 73, -1, -1, -1, -1, -1, -1, /* 208 */ - 125, 74, 75, 76, 77, 78, 79, 80, 81, 82, -1, -1, -1, -1, -1, -1, /* 224 */ - 92, -1, 83, 84, 85, 86, 87, 88, 89, 90, -1, -1, -1, -1, -1, -1, /* 240 */ - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1, -1 /* 256 */ -}; - - -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 */ -}; - - -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 */ -}; + desc = iconv_open (to, from); + if (desc == (iconv_t) -1) + perror_with_name ("Converting character sets"); + cleanups = make_cleanup (cleanup_iconv, &desc); + inleft = num_bytes; + inp = (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 = obstack_base (output) + old_size; + outleft = space_request; + + r = iconv (desc, &inp, &inleft, &outp, &outleft); + + /* Now make sure that the object on the obstack only includes + bytes we have converted. */ + obstack_blank (output, - (int) outleft); + + if (r == (size_t) -1) + { + switch (errno) + { + case EILSEQ: + { + int i; + + /* Invalid input sequence. */ + if (translit == translit_none) + error (_("Could not convert character to `%s' character set"), + to); + + /* We emit escape sequence for the bytes, skip them, + and try again. */ + for (i = 0; i < width; ++i) + { + char octal[5]; + + sprintf (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; -} - -static struct translation * -table_translation (const char *from, const char *to, int *table, - const char *(*c_target_char_has_backslash_escape) - (void *baton, int target_char), - void *c_target_char_has_backslash_escape_baton, - int (*c_parse_backslash) (void *baton, - int host_char, - int *target_char), - void *c_parse_backslash_baton) -{ - struct 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; + do_cleanups (cleanups); } - -static struct translation * -simple_table_translation (const char *from, const char *to, int *table) -{ - return table_translation (from, to, table, 0, 0, 0, 0); -} - - - -/* Setting and retrieving the host and target charsets. */ - - -/* The current host and target character sets. */ -static struct charset *current_host_charset, *current_target_charset; - -/* The current functions and batons we should use for the functions in - charset.h. */ - -static const char *(*c_target_char_has_backslash_escape_func) - (void *baton, int target_char); -static void *c_target_char_has_backslash_escape_baton; - -static int (*c_parse_backslash_func) (void *baton, - int host_char, - int *target_char); -static void *c_parse_backslash_baton; - -static int (*host_char_to_target_func) (void *baton, - int host_char, - int *target_char); -static void *host_char_to_target_baton; - -static int (*target_char_to_host_func) (void *baton, - int target_char, - int *host_char); -static void *target_char_to_host_baton; - - -/* 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; - -/* Charset structures manipulation functions. */ -static struct charset * -lookup_charset_or_error (const char *name) +/* An iterator that returns host wchar_t's from a target string. */ +struct wchar_iterator { - struct charset *cs = lookup_charset (name); + /* The underlying iconv descriptor. */ + iconv_t desc; - if (! cs) - error (_("GDB doesn't know of any character set named `%s'."), name); + /* The input string. This is updated as convert characters. */ + char *input; + /* The number of bytes remaining in the input. */ + size_t bytes; - return cs; -} + /* The width of an input character. */ + size_t width; -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); -} + /* The output buffer and its size. */ + gdb_wchar_t *out; + size_t out_size; +}; -/* Set the host and target character sets to HOST and TARGET. */ -static void -set_host_and_target_charsets (struct charset *host, struct charset *target) +/* Create a new iterator. */ +struct wchar_iterator * +make_wchar_iterator (const gdb_byte *input, size_t bytes, const char *charset, + size_t width) { - struct translation *h2t, *t2h; - - /* 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; - } - - h2t = lookup_translation (host->name, target->name); - t2h = lookup_translation (target->name, host->name); - - /* If the translations don't provide conversion functions, make sure - iconv can back them up. Do this *before* modifying any state. */ - if (host != target) - { - if (! h2t || ! h2t->convert_char) - { - if (check_iconv_cache (&cached_iconv_host_to_target, host, target) - < 0) - error (_("GDB can't convert from the `%s' character set to `%s'."), - host->name, target->name); - } - if (! t2h || ! t2h->convert_char) - { - if (check_iconv_cache (&cached_iconv_target_to_host, target, host) - < 0) - error (_("GDB can't convert from the `%s' character set to `%s'."), - target->name, host->name); - } - } - - if (t2h && t2h->c_target_char_has_backslash_escape) - { - c_target_char_has_backslash_escape_func - = t2h->c_target_char_has_backslash_escape; - c_target_char_has_backslash_escape_baton - = t2h->c_target_char_has_backslash_escape_baton; - } - else - c_target_char_has_backslash_escape_func - = default_c_target_char_has_backslash_escape; - - if (h2t && h2t->c_parse_backslash) - { - c_parse_backslash_func = h2t->c_parse_backslash; - c_parse_backslash_baton = h2t->c_parse_backslash_baton; - } - else - c_parse_backslash_func = default_c_parse_backslash; - - if (h2t && h2t->convert_char) - { - host_char_to_target_func = h2t->convert_char; - host_char_to_target_baton = h2t->convert_char_baton; - } - else if (host == target) - host_char_to_target_func = identity_either_char_to_other; - else - { - host_char_to_target_func = iconv_convert; - host_char_to_target_baton = &cached_iconv_host_to_target; - } + struct wchar_iterator *result; + iconv_t desc; - 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 - { - target_char_to_host_func = iconv_convert; - target_char_to_host_baton = &cached_iconv_target_to_host; - } + desc = iconv_open ("wchar_t", charset); + if (desc == (iconv_t) -1) + perror_with_name ("Converting character sets"); - current_host_charset = host; - current_target_charset = target; -} + result = XNEW (struct wchar_iterator); + result->desc = desc; + result->input = (char *) input; + result->bytes = bytes; + result->width = width; -/* 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); -} + result->out = XNEW (gdb_wchar_t); + result->out_size = 1; -/* 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 result; } - -/* '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) +do_cleanup_iterator (void *p) { - 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 wchar_iterator *iter = p; -/* '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); + iconv_close (iter->desc); + xfree (iter->out); + xfree (iter); } -/* Wrapper for the 'set target-charset' command. */ -static void -set_target_charset_sfunc (char *charset, int from_tty, - struct cmd_list_element *c) +struct cleanup * +make_cleanup_wchar_iterator (struct wchar_iterator *iter) { - set_target_charset (target_charset_name); + return make_cleanup (do_cleanup_iterator, iter); } -/* 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) -{ - if (current_host_charset == current_target_charset) - fprintf_filtered (file, - _("The current host and target character set is `%s'.\n"), - host_charset ()); - else +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) +{ + size_t out_request; + + /* Try to convert some characters. At first we try to convert just + a single character. The reason for this is that iconv does not + necessarily update its outgoing arguments when it encounters an + invalid input sequence -- but we want to reliably report this to + our caller so it can emit an escape sequence. */ + out_request = 1; + while (iter->bytes > 0) { - fprintf_filtered (file, _("The current host character set is `%s'.\n"), - host_charset ()); - fprintf_filtered (file, _("The current target character set is `%s'.\n"), - target_charset ()); + char *outptr = (char *) &iter->out[0]; + char *orig_inptr = iter->input; + size_t orig_in = iter->bytes; + size_t out_avail = out_request * sizeof (gdb_wchar_t); + size_t num; + gdb_wchar_t result; + + size_t r = iconv (iter->desc, (char **) &iter->input, &iter->bytes, + &outptr, &out_avail); + if (r == (size_t) -1) + { + switch (errno) + { + case EILSEQ: + /* Invalid input sequence. Skip it, and let the caller + know about it. */ + *out_result = wchar_iterate_invalid; + *ptr = iter->input; + *len = iter->width; + iter->input += iter->width; + iter->bytes -= iter->width; + return 0; + + case E2BIG: + /* We ran out of space. We still might have converted a + character; if so, return it. Otherwise, grow the + buffer and try again. */ + if (out_avail < out_request * sizeof (gdb_wchar_t)) + break; + + ++out_request; + if (out_request > iter->out_size) + { + iter->out_size = out_request; + iter->out = xrealloc (iter->out, + out_request * sizeof (gdb_wchar_t)); + } + continue; + + case EINVAL: + /* Incomplete input sequence. Let the caller know, and + arrange for future calls to see EOF. */ + *out_result = wchar_iterate_incomplete; + *ptr = iter->input; + *len = iter->bytes; + iter->bytes = 0; + return 0; + + default: + perror_with_name ("Internal error while converting character sets"); + } + } + + /* We converted something. */ + num = out_request - out_avail / sizeof (gdb_wchar_t); + *out_result = wchar_iterate_ok; + *out_chars = iter->out; + *ptr = orig_inptr; + *len = orig_in - iter->bytes; + return num; } + + /* Really done. */ + *out_result = wchar_iterate_eof; + return -1; } -/* Accessor functions. */ - -const char * -host_charset (void) -{ - return current_host_charset->name; -} +/* The charset.c module initialization function. */ -const char * -target_charset (void) -{ - return current_target_charset->name; -} +extern initialize_file_ftype _initialize_charset; /* -Wmissing-prototype */ +typedef char *char_ptr; +DEF_VEC_P (char_ptr); - -/* Public character management functions. */ +static VEC (char_ptr) *charsets; +#ifdef PHONY_ICONV -const char * -c_target_char_has_backslash_escape (int target_char) +static void +find_charset_names (void) { - return ((*c_target_char_has_backslash_escape_func) - (c_target_char_has_backslash_escape_baton, target_char)); + VEC_safe_push (char_ptr, charsets, GDB_DEFAULT_HOST_CHARSET); + VEC_safe_push (char_ptr, charsets, NULL); } +#else /* PHONY_ICONV */ +#ifdef HAVE_ICONVLIST -int -c_parse_backslash (int host_char, int *target_char) +/* A helper function that adds some character sets to the vector of + all character sets. This is a callback function for iconvlist. */ + +static int +add_one (unsigned int count, const char *const *names, void *data) { - return (*c_parse_backslash_func) (c_parse_backslash_baton, - host_char, target_char); -} + unsigned int i; + for (i = 0; i < count; ++i) + VEC_safe_push (char_ptr, charsets, xstrdup (names[i])); -int -host_char_print_literally (int host_char) -{ - return ((*current_host_charset->host_char_print_literally) - (current_host_charset->host_char_print_literally_baton, - host_char)); + return 0; } - -int -target_char_to_control_char (int target_char, int *target_ctrl_char) +static void +find_charset_names (void) { - return ((*current_target_charset->target_char_to_control_char) - (current_target_charset->target_char_to_control_char_baton, - target_char, target_ctrl_char)); + iconvlist (add_one, NULL); + VEC_safe_push (char_ptr, charsets, NULL); } +#else -int -host_char_to_target (int host_char, int *target_char) +static void +find_charset_names (void) { - return ((*host_char_to_target_func) - (host_char_to_target_baton, host_char, target_char)); -} + FILE *in; + in = popen ("iconv -l", "r"); + /* It is ok to ignore errors; we'll fall back on a default. */ + if (!in) + return; -int -target_char_to_host (int target_char, int *host_char) -{ - return ((*target_char_to_host_func) - (target_char_to_host_baton, target_char, host_char)); -} + /* POSIX says that iconv -l uses an unspecified format. We parse + the glibc format; feel free to add others as needed. */ + while (!feof (in)) + { + /* The size of buf is chosen arbitrarily. A character set name + longer than this would not be very nice. */ + char buf[80]; + int len; + char *r = fgets (buf, sizeof (buf), in); + if (!r) + break; + len = strlen (r); + if (len <= 3) + continue; + if (buf[len - 2] == '/' && buf[len - 3] == '/') + buf[len - 3] = '\0'; + VEC_safe_push (char_ptr, charsets, xstrdup (buf)); + } + pclose (in); - -/* The charset.c module initialization function. */ + VEC_safe_push (char_ptr, charsets, NULL); +} -extern initialize_file_ftype _initialize_charset; /* -Wmissing-prototype */ +#endif /* HAVE_ICONVLIST */ +#endif /* PHONY_ICONV */ 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 (); - - { - 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; - - for (i = 0; i < (sizeof (tlist) / sizeof (tlist[0])); i++) - register_translation (simple_table_translation (tlist[i].from, - tlist[i].to, - tlist[i].table)); - } - - set_host_charset (host_charset_name); - set_target_charset (target_charset_name); + /* The first element is always "auto"; then we skip it for the + commands where it is not allowed. */ + VEC_safe_push (char_ptr, charsets, "auto"); + find_charset_names (); + + if (VEC_length (char_ptr, charsets) > 1) + charset_enum = (const char **) VEC_address (char_ptr, charsets); + else + charset_enum = default_charset_names; + +#ifndef PHONY_ICONV +#ifdef HAVE_LANGINFO_CODESET + auto_host_charset_name = nl_langinfo (CODESET); + target_charset_name = auto_host_charset_name; + + set_be_le_names (); +#endif +#endif add_setshow_enum_cmd ("charset", class_support, - host_charset_enum, &host_charset_name, _("\ + &charset_enum[1], &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\ @@ -1249,7 +763,7 @@ To see a list of the character sets GDB supports, type `set charset <TAB>'."), &setlist, &showlist); add_setshow_enum_cmd ("host-charset", class_support, - host_charset_enum, &host_charset_name, _("\ + 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\ @@ -1261,7 +775,7 @@ To see a list of the character sets GDB supports, type `set host-charset <TAB>'. &setlist, &showlist); add_setshow_enum_cmd ("target-charset", class_support, - target_charset_enum, &target_charset_name, _("\ + &charset_enum[1], &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\ @@ -1271,4 +785,19 @@ 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[1], &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.\n\ +In 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); } |