diff options
Diffstat (limited to 'libX11/src/xlibi18n/lcUTF8.c')
-rw-r--r-- | libX11/src/xlibi18n/lcUTF8.c | 4780 |
1 files changed, 2390 insertions, 2390 deletions
diff --git a/libX11/src/xlibi18n/lcUTF8.c b/libX11/src/xlibi18n/lcUTF8.c index 08906c695..5e47f23bb 100644 --- a/libX11/src/xlibi18n/lcUTF8.c +++ b/libX11/src/xlibi18n/lcUTF8.c @@ -1,2390 +1,2390 @@ -/****************************************************************** - - Copyright 1993 by SunSoft, Inc. - Copyright 1999-2000 by Bruno Haible - -Permission to use, copy, modify, distribute, and sell this software -and its documentation for any purpose is hereby granted without fee, -provided that the above copyright notice appear in all copies and -that both that copyright notice and this permission notice appear -in supporting documentation, and that the names of SunSoft, Inc. and -Bruno Haible not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. SunSoft, Inc. and Bruno Haible make no representations -about the suitability of this software for any purpose. It is -provided "as is" without express or implied warranty. - -SunSoft Inc. AND Bruno Haible DISCLAIM ALL WARRANTIES WITH REGARD -TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS, IN NO EVENT SHALL SunSoft, Inc. OR Bruno Haible BE LIABLE -FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -******************************************************************/ - -/* - * This file contains: - * - * I. Conversion routines CompoundText/CharSet <--> Unicode/UTF-8. - * - * Used for three purposes: - * 1. The UTF-8 locales, see below. - * 2. Unicode aware applications for which the use of 8-bit character - * sets is an anachronism. - * 3. For conversion from keysym to locale encoding. - * - * II. Conversion files for an UTF-8 locale loader. - * Supports: all locales with codeset UTF-8. - * How: Provides converters for UTF-8. - * Platforms: all systems. - * - * The loader itself is located in lcUTF8.c. - */ - -/* - * The conversion from UTF-8 to CompoundText is realized in a very - * conservative way. Recall that CompoundText data is used for inter-client - * communication purposes. We distinguish three classes of clients: - * - Clients which accept only those pieces of CompoundText which belong to - * the character set understood by the current locale. - * (Example: clients which are linked to an older X11 library.) - * - Clients which accept CompoundText with multiple character sets and parse - * it themselves. - * (Example: emacs, xemacs.) - * - Clients which rely entirely on the X{mb,wc}TextPropertyToTextList - * functions for the conversion of CompoundText to their current locale's - * multi-byte/wide-character format. - * For best interoperation, the UTF-8 to CompoundText conversion proceeds as - * follows. For every character, it first tests whether the character is - * representable in the current locale's original (non-UTF-8) character set. - * If not, it goes through the list of predefined character sets for - * CompoundText and tests if the character is representable in that character - * set. If so, it encodes the character using its code within that character - * set. If not, it uses an UTF-8-in-CompoundText encapsulation. Since - * clients of the first and second kind ignore such encapsulated text, - * this encapsulation is kept to a minimum and terminated as early as possible. - * - * In a distant future, when clients of the first and second kind will have - * disappeared, we will be able to stuff UTF-8 data directly in CompoundText - * without first going through the list of predefined character sets. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#include <stdio.h> -#include "Xlibint.h" -#include "XlcPubI.h" -#include "XlcGeneric.h" - -static XlcConv -create_conv( - XLCd lcd, - XlcConvMethods methods) -{ - XlcConv conv; - - conv = (XlcConv) Xmalloc(sizeof(XlcConvRec)); - if (conv == (XlcConv) NULL) - return (XlcConv) NULL; - - conv->methods = methods; - conv->state = NULL; - - return conv; -} - -static void -close_converter( - XlcConv conv) -{ - Xfree((char *) conv); -} - -/* Replacement character for invalid multibyte sequence or wide character. */ -#define BAD_WCHAR ((ucs4_t) 0xfffd) -#define BAD_CHAR '?' - -/***************************************************************************/ -/* Part I: Conversion routines CompoundText/CharSet <--> Unicode/UTF-8. - * - * Note that this code works in any locale. We store Unicode values in - * `ucs4_t' variables, but don't pass them to the user. - * - * This code has to support all character sets that are used for CompoundText, - * nothing more, nothing less. See the table in lcCT.c. - * Since the conversion _to_ CompoundText is likely to need the tables for all - * character sets at once, we don't use dynamic loading (of tables or shared - * libraries through iconv()). Use a fixed set of tables instead. - * - * We use statically computed tables, not dynamically allocated arrays, - * because it's more memory efficient: Different processes using the same - * libX11 shared library share the "text" and read-only "data" sections. - */ - -typedef unsigned int ucs4_t; -#define conv_t XlcConv - -typedef struct _Utf8ConvRec { - const char *name; - XrmQuark xrm_name; - int (* cstowc) (XlcConv, ucs4_t *, unsigned char const *, int); - int (* wctocs) (XlcConv, unsigned char *, ucs4_t, int); -} Utf8ConvRec, *Utf8Conv; - -/* - * int xxx_cstowc (XlcConv conv, ucs4_t *pwc, unsigned char const *s, int n) - * converts the byte sequence starting at s to a wide character. Up to n bytes - * are available at s. n is >= 1. - * Result is number of bytes consumed (if a wide character was read), - * or 0 if invalid, or -1 if n too small. - * - * int xxx_wctocs (XlcConv conv, unsigned char *r, ucs4_t wc, int n) - * converts the wide character wc to the character set xxx, and stores the - * result beginning at r. Up to n bytes may be written at r. n is >= 1. - * Result is number of bytes written, or 0 if invalid, or -1 if n too small. - */ - -/* Return code if invalid. (xxx_mbtowc, xxx_wctomb) */ -#define RET_ILSEQ 0 -/* Return code if only a shift sequence of n bytes was read. (xxx_mbtowc) */ -#define RET_TOOFEW(n) (-1-(n)) -/* Return code if output buffer is too small. (xxx_wctomb, xxx_reset) */ -#define RET_TOOSMALL -1 - -/* - * The tables below are bijective. It would be possible to extend the - * xxx_wctocs tables to do some transliteration (e.g. U+201C,U+201D -> 0x22) - * but *only* with characters not contained in any other table, and *only* - * when the current locale is not an UTF-8 locale. - */ - -#include "lcUniConv/utf8.h" -#include "lcUniConv/ucs2be.h" -#ifdef notused -#include "lcUniConv/ascii.h" -#endif -#include "lcUniConv/iso8859_1.h" -#include "lcUniConv/iso8859_2.h" -#include "lcUniConv/iso8859_3.h" -#include "lcUniConv/iso8859_4.h" -#include "lcUniConv/iso8859_5.h" -#include "lcUniConv/iso8859_6.h" -#include "lcUniConv/iso8859_7.h" -#include "lcUniConv/iso8859_8.h" -#include "lcUniConv/iso8859_9.h" -#include "lcUniConv/iso8859_10.h" -#include "lcUniConv/iso8859_11.h" -#include "lcUniConv/iso8859_13.h" -#include "lcUniConv/iso8859_14.h" -#include "lcUniConv/iso8859_15.h" -#include "lcUniConv/iso8859_16.h" -#include "lcUniConv/iso8859_9e.h" -#include "lcUniConv/jisx0201.h" -#include "lcUniConv/tis620.h" -#include "lcUniConv/koi8_r.h" -#include "lcUniConv/koi8_u.h" -#include "lcUniConv/koi8_c.h" -#include "lcUniConv/armscii_8.h" -#include "lcUniConv/cp1133.h" -#include "lcUniConv/mulelao.h" -#include "lcUniConv/viscii.h" -#include "lcUniConv/tcvn.h" -#include "lcUniConv/georgian_academy.h" -#include "lcUniConv/georgian_ps.h" -#include "lcUniConv/cp1251.h" -#include "lcUniConv/cp1255.h" -#include "lcUniConv/cp1256.h" -#include "lcUniConv/tatar_cyr.h" - -typedef struct { - unsigned short indx; /* index into big table */ - unsigned short used; /* bitmask of used entries */ -} Summary16; - -#include "lcUniConv/gb2312.h" -#include "lcUniConv/jisx0208.h" -#include "lcUniConv/jisx0212.h" -#include "lcUniConv/ksc5601.h" -#include "lcUniConv/big5.h" -#include "lcUniConv/big5_emacs.h" -#include "lcUniConv/big5hkscs.h" -#include "lcUniConv/gbk.h" - -static Utf8ConvRec all_charsets[] = { - /* The ISO10646-1/UTF-8 entry occurs twice, once at the beginning - (for lookup speed), once at the end (as a fallback). */ - { "ISO10646-1", NULLQUARK, - utf8_mbtowc, utf8_wctomb - }, - - { "ISO8859-1", NULLQUARK, - iso8859_1_mbtowc, iso8859_1_wctomb - }, - { "ISO8859-2", NULLQUARK, - iso8859_2_mbtowc, iso8859_2_wctomb - }, - { "ISO8859-3", NULLQUARK, - iso8859_3_mbtowc, iso8859_3_wctomb - }, - { "ISO8859-4", NULLQUARK, - iso8859_4_mbtowc, iso8859_4_wctomb - }, - { "ISO8859-5", NULLQUARK, - iso8859_5_mbtowc, iso8859_5_wctomb - }, - { "ISO8859-6", NULLQUARK, - iso8859_6_mbtowc, iso8859_6_wctomb - }, - { "ISO8859-7", NULLQUARK, - iso8859_7_mbtowc, iso8859_7_wctomb - }, - { "ISO8859-8", NULLQUARK, - iso8859_8_mbtowc, iso8859_8_wctomb - }, - { "ISO8859-9", NULLQUARK, - iso8859_9_mbtowc, iso8859_9_wctomb - }, - { "ISO8859-10", NULLQUARK, - iso8859_10_mbtowc, iso8859_10_wctomb - }, - { "ISO8859-11", NULLQUARK, - iso8859_11_mbtowc, iso8859_11_wctomb - }, - { "ISO8859-13", NULLQUARK, - iso8859_13_mbtowc, iso8859_13_wctomb - }, - { "ISO8859-14", NULLQUARK, - iso8859_14_mbtowc, iso8859_14_wctomb - }, - { "ISO8859-15", NULLQUARK, - iso8859_15_mbtowc, iso8859_15_wctomb - }, - { "ISO8859-16", NULLQUARK, - iso8859_16_mbtowc, iso8859_16_wctomb - }, - { "JISX0201.1976-0", NULLQUARK, - jisx0201_mbtowc, jisx0201_wctomb - }, - { "TIS620-0", NULLQUARK, - tis620_mbtowc, tis620_wctomb - }, - { "GB2312.1980-0", NULLQUARK, - gb2312_mbtowc, gb2312_wctomb - }, - { "JISX0208.1983-0", NULLQUARK, - jisx0208_mbtowc, jisx0208_wctomb - }, - { "JISX0208.1990-0", NULLQUARK, - jisx0208_mbtowc, jisx0208_wctomb - }, - { "JISX0212.1990-0", NULLQUARK, - jisx0212_mbtowc, jisx0212_wctomb - }, - { "KSC5601.1987-0", NULLQUARK, - ksc5601_mbtowc, ksc5601_wctomb - }, - { "KOI8-R", NULLQUARK, - koi8_r_mbtowc, koi8_r_wctomb - }, - { "KOI8-U", NULLQUARK, - koi8_u_mbtowc, koi8_u_wctomb - }, - { "KOI8-C", NULLQUARK, - koi8_c_mbtowc, koi8_c_wctomb - }, - { "TATAR-CYR", NULLQUARK, - tatar_cyr_mbtowc, tatar_cyr_wctomb - }, - { "ARMSCII-8", NULLQUARK, - armscii_8_mbtowc, armscii_8_wctomb - }, - { "IBM-CP1133", NULLQUARK, - cp1133_mbtowc, cp1133_wctomb - }, - { "MULELAO-1", NULLQUARK, - mulelao_mbtowc, mulelao_wctomb - }, - { "VISCII1.1-1", NULLQUARK, - viscii_mbtowc, viscii_wctomb - }, - { "TCVN-5712", NULLQUARK, - tcvn_mbtowc, tcvn_wctomb - }, - { "GEORGIAN-ACADEMY", NULLQUARK, - georgian_academy_mbtowc, georgian_academy_wctomb - }, - { "GEORGIAN-PS", NULLQUARK, - georgian_ps_mbtowc, georgian_ps_wctomb - }, - { "ISO8859-9E", NULLQUARK, - iso8859_9e_mbtowc, iso8859_9e_wctomb - }, - { "MICROSOFT-CP1251", NULLQUARK, - cp1251_mbtowc, cp1251_wctomb - }, - { "MICROSOFT-CP1255", NULLQUARK, - cp1255_mbtowc, cp1255_wctomb - }, - { "MICROSOFT-CP1256", NULLQUARK, - cp1256_mbtowc, cp1256_wctomb - }, - { "BIG5-0", NULLQUARK, - big5_mbtowc, big5_wctomb - }, - { "BIG5-E0", NULLQUARK, - big5_0_mbtowc, big5_0_wctomb - }, - { "BIG5-E1", NULLQUARK, - big5_1_mbtowc, big5_1_wctomb - }, - { "GBK-0", NULLQUARK, - gbk_mbtowc, gbk_wctomb - }, - { "BIG5HKSCS-0", NULLQUARK, - big5hkscs_mbtowc, big5hkscs_wctomb - }, - - /* The ISO10646-1/UTF-8 entry occurs twice, once at the beginning - (for lookup speed), once at the end (as a fallback). */ - { "ISO10646-1", NULLQUARK, - utf8_mbtowc, utf8_wctomb - }, - - /* Encoding ISO10646-1 for fonts means UCS2-like encoding - so for conversion to FontCharSet we need this record */ - { "ISO10646-1", NULLQUARK, - ucs2be_mbtowc, ucs2be_wctomb - } -}; - -#define charsets_table_size (sizeof(all_charsets)/sizeof(all_charsets[0])) -#define all_charsets_count (charsets_table_size - 1) -#define ucs2_conv_index (charsets_table_size - 1) - -static void -init_all_charsets (void) -{ - Utf8Conv convptr; - int i; - - for (convptr = all_charsets, i = charsets_table_size; i > 0; convptr++, i--) - convptr->xrm_name = XrmStringToQuark(convptr->name); -} - -#define lazy_init_all_charsets() \ - do { \ - if (all_charsets[0].xrm_name == NULLQUARK) \ - init_all_charsets(); \ - } while (0) - -/* from XlcNCharSet to XlcNUtf8String */ - -static int -cstoutf8( - XlcConv conv, - XPointer *from, - int *from_left, - XPointer *to, - int *to_left, - XPointer *args, - int num_args) -{ - XlcCharSet charset; - const char *name; - Utf8Conv convptr; - int i; - unsigned char const *src; - unsigned char const *srcend; - unsigned char *dst; - unsigned char *dstend; - int unconv_num; - - if (from == NULL || *from == NULL) - return 0; - - if (num_args < 1) - return -1; - - charset = (XlcCharSet) args[0]; - name = charset->encoding_name; - /* not charset->name because the latter has a ":GL"/":GR" suffix */ - - for (convptr = all_charsets, i = all_charsets_count-1; i > 0; convptr++, i--) - if (!strcmp(convptr->name, name)) - break; - if (i == 0) - return -1; - - src = (unsigned char const *) *from; - srcend = src + *from_left; - dst = (unsigned char *) *to; - dstend = dst + *to_left; - unconv_num = 0; - - while (src < srcend) { - ucs4_t wc; - int consumed; - int count; - - consumed = convptr->cstowc(conv, &wc, src, srcend-src); - if (consumed == RET_ILSEQ) - return -1; - if (consumed == RET_TOOFEW(0)) - break; - - count = utf8_wctomb(NULL, dst, wc, dstend-dst); - if (count == RET_TOOSMALL) - break; - if (count == RET_ILSEQ) { - count = utf8_wctomb(NULL, dst, BAD_WCHAR, dstend-dst); - if (count == RET_TOOSMALL) - break; - unconv_num++; - } - src += consumed; - dst += count; - } - - *from = (XPointer) src; - *from_left = srcend - src; - *to = (XPointer) dst; - *to_left = dstend - dst; - - return unconv_num; -} - -static XlcConvMethodsRec methods_cstoutf8 = { - close_converter, - cstoutf8, - NULL -}; - -static XlcConv -open_cstoutf8( - XLCd from_lcd, - const char *from_type, - XLCd to_lcd, - const char *to_type) -{ - lazy_init_all_charsets(); - return create_conv(from_lcd, &methods_cstoutf8); -} - -/* from XlcNUtf8String to XlcNCharSet */ - -static XlcConv -create_tocs_conv( - XLCd lcd, - XlcConvMethods methods) -{ - XlcConv conv; - CodeSet *codeset_list; - int codeset_num; - int charset_num; - int i, j, k; - Utf8Conv *preferred; - - lazy_init_all_charsets(); - - codeset_list = XLC_GENERIC(lcd, codeset_list); - codeset_num = XLC_GENERIC(lcd, codeset_num); - - charset_num = 0; - for (i = 0; i < codeset_num; i++) - charset_num += codeset_list[i]->num_charsets; - if (charset_num > all_charsets_count-1) - charset_num = all_charsets_count-1; - - conv = (XlcConv) Xmalloc(sizeof(XlcConvRec) - + (charset_num + 1) * sizeof(Utf8Conv)); - if (conv == (XlcConv) NULL) - return (XlcConv) NULL; - preferred = (Utf8Conv *) ((char *) conv + sizeof(XlcConvRec)); - - /* Loop through all codesets mentioned in the locale. */ - charset_num = 0; - for (i = 0; i < codeset_num; i++) { - XlcCharSet *charsets = codeset_list[i]->charset_list; - int num_charsets = codeset_list[i]->num_charsets; - for (j = 0; j < num_charsets; j++) { - const char *name = charsets[j]->encoding_name; - /* If it wasn't already encountered... */ - for (k = charset_num-1; k >= 0; k--) - if (!strcmp(preferred[k]->name, name)) - break; - if (k < 0) { - /* Look it up in all_charsets[]. */ - for (k = 0; k < all_charsets_count-1; k++) - if (!strcmp(all_charsets[k].name, name)) { - /* Add it to the preferred set. */ - preferred[charset_num++] = &all_charsets[k]; - break; - } - } - } - } - preferred[charset_num] = (Utf8Conv) NULL; - - conv->methods = methods; - conv->state = (XPointer) preferred; - - return conv; -} - -static void -close_tocs_converter( - XlcConv conv) -{ - /* conv->state is allocated together with conv, free both at once. */ - Xfree((char *) conv); -} - -/* - * Converts a Unicode character to an appropriate character set. The NULL - * terminated array of preferred character sets is passed as first argument. - * If successful, *charsetp is set to the character set that was used, and - * *sidep is set to the character set side (XlcGL or XlcGR). - */ -static int -charset_wctocs( - Utf8Conv *preferred, - Utf8Conv *charsetp, - XlcSide *sidep, - XlcConv conv, - unsigned char *r, - ucs4_t wc, - int n) -{ - int count; - Utf8Conv convptr; - int i; - - for (; *preferred != (Utf8Conv) NULL; preferred++) { - convptr = *preferred; - count = convptr->wctocs(conv, r, wc, n); - if (count == RET_TOOSMALL) - return RET_TOOSMALL; - if (count != RET_ILSEQ) { - *charsetp = convptr; - *sidep = (*r < 0x80 ? XlcGL : XlcGR); - return count; - } - } - for (convptr = all_charsets+1, i = all_charsets_count-1; i > 0; convptr++, i--) { - count = convptr->wctocs(conv, r, wc, n); - if (count == RET_TOOSMALL) - return RET_TOOSMALL; - if (count != RET_ILSEQ) { - *charsetp = convptr; - *sidep = (*r < 0x80 ? XlcGL : XlcGR); - return count; - } - } - return RET_ILSEQ; -} - -static int -utf8tocs( - XlcConv conv, - XPointer *from, - int *from_left, - XPointer *to, - int *to_left, - XPointer *args, - int num_args) -{ - Utf8Conv *preferred_charsets; - XlcCharSet last_charset = NULL; - unsigned char const *src; - unsigned char const *srcend; - unsigned char *dst; - unsigned char *dstend; - int unconv_num; - - if (from == NULL || *from == NULL) - return 0; - - preferred_charsets = (Utf8Conv *) conv->state; - src = (unsigned char const *) *from; - srcend = src + *from_left; - dst = (unsigned char *) *to; - dstend = dst + *to_left; - unconv_num = 0; - - while (src < srcend && dst < dstend) { - Utf8Conv chosen_charset = NULL; - XlcSide chosen_side = XlcNONE; - ucs4_t wc; - int consumed; - int count; - - consumed = utf8_mbtowc(NULL, &wc, src, srcend-src); - if (consumed == RET_TOOFEW(0)) - break; - if (consumed == RET_ILSEQ) { - src++; - unconv_num++; - continue; - } - - count = charset_wctocs(preferred_charsets, &chosen_charset, &chosen_side, conv, dst, wc, dstend-dst); - if (count == RET_TOOSMALL) - break; - if (count == RET_ILSEQ) { - src += consumed; - unconv_num++; - continue; - } - - if (last_charset == NULL) { - last_charset = - _XlcGetCharSetWithSide(chosen_charset->name, chosen_side); - if (last_charset == NULL) { - src += consumed; - unconv_num++; - continue; - } - } else { - if (!(last_charset->xrm_encoding_name == chosen_charset->xrm_name - && (last_charset->side == XlcGLGR - || last_charset->side == chosen_side))) - break; - } - src += consumed; - dst += count; - } - - if (last_charset == NULL) - return -1; - - *from = (XPointer) src; - *from_left = srcend - src; - *to = (XPointer) dst; - *to_left = dstend - dst; - - if (num_args >= 1) - *((XlcCharSet *)args[0]) = last_charset; - - return unconv_num; -} - -static XlcConvMethodsRec methods_utf8tocs = { - close_tocs_converter, - utf8tocs, - NULL -}; - -static XlcConv -open_utf8tocs( - XLCd from_lcd, - const char *from_type, - XLCd to_lcd, - const char *to_type) -{ - return create_tocs_conv(from_lcd, &methods_utf8tocs); -} - -/* from XlcNUtf8String to XlcNChar */ - -static int -utf8tocs1( - XlcConv conv, - XPointer *from, - int *from_left, - XPointer *to, - int *to_left, - XPointer *args, - int num_args) -{ - Utf8Conv *preferred_charsets; - XlcCharSet last_charset = NULL; - unsigned char const *src; - unsigned char const *srcend; - unsigned char *dst; - unsigned char *dstend; - int unconv_num; - - if (from == NULL || *from == NULL) - return 0; - - preferred_charsets = (Utf8Conv *) conv->state; - src = (unsigned char const *) *from; - srcend = src + *from_left; - dst = (unsigned char *) *to; - dstend = dst + *to_left; - unconv_num = 0; - - while (src < srcend && dst < dstend) { - Utf8Conv chosen_charset = NULL; - XlcSide chosen_side = XlcNONE; - ucs4_t wc; - int consumed; - int count; - - consumed = utf8_mbtowc(NULL, &wc, src, srcend-src); - if (consumed == RET_TOOFEW(0)) - break; - if (consumed == RET_ILSEQ) { - src++; - unconv_num++; - continue; - } - - count = charset_wctocs(preferred_charsets, &chosen_charset, &chosen_side, conv, dst, wc, dstend-dst); - if (count == RET_TOOSMALL) - break; - if (count == RET_ILSEQ) { - src += consumed; - unconv_num++; - continue; - } - - if (last_charset == NULL) { - last_charset = - _XlcGetCharSetWithSide(chosen_charset->name, chosen_side); - if (last_charset == NULL) { - src += consumed; - unconv_num++; - continue; - } - } else { - if (!(last_charset->xrm_encoding_name == chosen_charset->xrm_name - && (last_charset->side == XlcGLGR - || last_charset->side == chosen_side))) - break; - } - src += consumed; - dst += count; - break; - } - - if (last_charset == NULL) - return -1; - - *from = (XPointer) src; - *from_left = srcend - src; - *to = (XPointer) dst; - *to_left = dstend - dst; - - if (num_args >= 1) - *((XlcCharSet *)args[0]) = last_charset; - - return unconv_num; -} - -static XlcConvMethodsRec methods_utf8tocs1 = { - close_tocs_converter, - utf8tocs1, - NULL -}; - -static XlcConv -open_utf8tocs1( - XLCd from_lcd, - const char *from_type, - XLCd to_lcd, - const char *to_type) -{ - return create_tocs_conv(from_lcd, &methods_utf8tocs1); -} - -/* from XlcNUtf8String to XlcNString */ - -static int -utf8tostr( - XlcConv conv, - XPointer *from, - int *from_left, - XPointer *to, - int *to_left, - XPointer *args, - int num_args) -{ - unsigned char const *src; - unsigned char const *srcend; - unsigned char *dst; - unsigned char *dstend; - int unconv_num; - - if (from == NULL || *from == NULL) - return 0; - - src = (unsigned char const *) *from; - srcend = src + *from_left; - dst = (unsigned char *) *to; - dstend = dst + *to_left; - unconv_num = 0; - - while (src < srcend) { - unsigned char c; - ucs4_t wc; - int consumed; - - consumed = utf8_mbtowc(NULL, &wc, src, srcend-src); - if (consumed == RET_TOOFEW(0)) - break; - if (dst == dstend) - break; - if (consumed == RET_ILSEQ) { - consumed = 1; - c = BAD_CHAR; - unconv_num++; - } else { - if ((wc & ~(ucs4_t)0xff) != 0) { - c = BAD_CHAR; - unconv_num++; - } else - c = (unsigned char) wc; - } - *dst++ = c; - src += consumed; - } - - *from = (XPointer) src; - *from_left = srcend - src; - *to = (XPointer) dst; - *to_left = dstend - dst; - - return unconv_num; -} - -static XlcConvMethodsRec methods_utf8tostr = { - close_converter, - utf8tostr, - NULL -}; - -static XlcConv -open_utf8tostr( - XLCd from_lcd, - const char *from_type, - XLCd to_lcd, - const char *to_type) -{ - return create_conv(from_lcd, &methods_utf8tostr); -} - -/* from XlcNString to XlcNUtf8String */ - -static int -strtoutf8( - XlcConv conv, - XPointer *from, - int *from_left, - XPointer *to, - int *to_left, - XPointer *args, - int num_args) -{ - unsigned char const *src; - unsigned char const *srcend; - unsigned char *dst; - unsigned char *dstend; - - if (from == NULL || *from == NULL) - return 0; - - src = (unsigned char const *) *from; - srcend = src + *from_left; - dst = (unsigned char *) *to; - dstend = dst + *to_left; - - while (src < srcend) { - int count = utf8_wctomb(NULL, dst, *src, dstend-dst); - if (count == RET_TOOSMALL) - break; - dst += count; - src++; - } - - *from = (XPointer) src; - *from_left = srcend - src; - *to = (XPointer) dst; - *to_left = dstend - dst; - - return 0; -} - -static XlcConvMethodsRec methods_strtoutf8 = { - close_converter, - strtoutf8, - NULL -}; - -static XlcConv -open_strtoutf8( - XLCd from_lcd, - const char *from_type, - XLCd to_lcd, - const char *to_type) -{ - return create_conv(from_lcd, &methods_strtoutf8); -} - -/* Support for the input methods. */ - -XPointer -_Utf8GetConvByName( - const char *name) -{ - XrmQuark xrm_name; - Utf8Conv convptr; - int i; - - if (name == NULL) - return (XPointer) NULL; - - lazy_init_all_charsets(); - xrm_name = XrmStringToQuark(name); - - for (convptr = all_charsets, i = all_charsets_count-1; i > 0; convptr++, i--) - if (convptr->xrm_name == xrm_name) - return (XPointer) convptr->wctocs; - return (XPointer) NULL; -} - -/* from XlcNUcsChar to XlcNChar, needed for input methods */ - -static XlcConv -create_ucstocs_conv( - XLCd lcd, - XlcConvMethods methods) -{ - - if (XLC_PUBLIC_PART(lcd)->codeset - && _XlcCompareISOLatin1(XLC_PUBLIC_PART(lcd)->codeset, "UTF-8") == 0) { - XlcConv conv; - Utf8Conv *preferred; - - lazy_init_all_charsets(); - - conv = (XlcConv) Xmalloc(sizeof(XlcConvRec) + 2 * sizeof(Utf8Conv)); - if (conv == (XlcConv) NULL) - return (XlcConv) NULL; - preferred = (Utf8Conv *) ((char *) conv + sizeof(XlcConvRec)); - - preferred[0] = &all_charsets[0]; /* ISO10646 */ - preferred[1] = (Utf8Conv) NULL; - - conv->methods = methods; - conv->state = (XPointer) preferred; - - return conv; - } else { - return create_tocs_conv(lcd, methods); - } -} - -static int -charset_wctocs_exactly( - Utf8Conv *preferred, - Utf8Conv *charsetp, - XlcSide *sidep, - XlcConv conv, - unsigned char *r, - ucs4_t wc, - int n) -{ - int count; - Utf8Conv convptr; - - for (; *preferred != (Utf8Conv) NULL; preferred++) { - convptr = *preferred; - count = convptr->wctocs(conv, r, wc, n); - if (count == RET_TOOSMALL) - return RET_TOOSMALL; - if (count != RET_ILSEQ) { - *charsetp = convptr; - *sidep = (*r < 0x80 ? XlcGL : XlcGR); - return count; - } - } - return RET_ILSEQ; -} - -static int -ucstocs1( - XlcConv conv, - XPointer *from, - int *from_left, - XPointer *to, - int *to_left, - XPointer *args, - int num_args) -{ - ucs4_t const *src = (ucs4_t const *) *from; - unsigned char *dst = (unsigned char *) *to; - int unconv_num = 0; - Utf8Conv *preferred_charsets = (Utf8Conv *) conv->state; - Utf8Conv chosen_charset = NULL; - XlcSide chosen_side = XlcNONE; - XlcCharSet charset = NULL; - int count; - - if (from == NULL || *from == NULL) - return 0; - - count = charset_wctocs_exactly(preferred_charsets, &chosen_charset, - &chosen_side, conv, dst, *src, *to_left); - if (count < 1) { - unconv_num++; - count = 0; - } else { - charset = _XlcGetCharSetWithSide(chosen_charset->name, chosen_side); - } - if (charset == NULL) - return -1; - - *from = (XPointer) ++src; - (*from_left)--; - *to = (XPointer) dst; - *to_left -= count; - - if (num_args >= 1) - *((XlcCharSet *)args[0]) = charset; - - return unconv_num; -} - -static XlcConvMethodsRec methods_ucstocs1 = { - close_tocs_converter, - ucstocs1, - NULL -}; - -static XlcConv -open_ucstocs1( - XLCd from_lcd, - const char *from_type, - XLCd to_lcd, - const char *to_type) -{ - return create_ucstocs_conv(from_lcd, &methods_ucstocs1); -} - -/* from XlcNUcsChar to XlcNUtf8String, needed for input methods */ - -static int -ucstoutf8( - XlcConv conv, - XPointer *from, - int *from_left, - XPointer *to, - int *to_left, - XPointer *args, - int num_args) -{ - const ucs4_t *src; - const ucs4_t *srcend; - unsigned char *dst; - unsigned char *dstend; - int unconv_num; - - if (from == NULL || *from == NULL) - return 0; - - src = (const ucs4_t *) *from; - srcend = src + *from_left; - dst = (unsigned char *) *to; - dstend = dst + *to_left; - unconv_num = 0; - - while (src < srcend) { - int count = utf8_wctomb(NULL, dst, *src, dstend-dst); - if (count == RET_TOOSMALL) - break; - if (count == RET_ILSEQ) - unconv_num++; - src++; - dst += count; - } - - *from = (XPointer) src; - *from_left = srcend - src; - *to = (XPointer) dst; - *to_left = dstend - dst; - - return unconv_num; -} - -static XlcConvMethodsRec methods_ucstoutf8 = { - close_converter, - ucstoutf8, - NULL -}; - -static XlcConv -open_ucstoutf8( - XLCd from_lcd, - const char *from_type, - XLCd to_lcd, - const char *to_type) -{ - return create_conv(from_lcd, &methods_ucstoutf8); -} - -/* Registers UTF-8 converters for a non-UTF-8 locale. */ -void -_XlcAddUtf8Converters( - XLCd lcd) -{ - _XlcSetConverter(lcd, XlcNCharSet, lcd, XlcNUtf8String, open_cstoutf8); - _XlcSetConverter(lcd, XlcNUtf8String, lcd, XlcNCharSet, open_utf8tocs); - _XlcSetConverter(lcd, XlcNUtf8String, lcd, XlcNChar, open_utf8tocs1); - _XlcSetConverter(lcd, XlcNString, lcd, XlcNUtf8String, open_strtoutf8); - _XlcSetConverter(lcd, XlcNUtf8String, lcd, XlcNString, open_utf8tostr); - _XlcSetConverter(lcd, XlcNUcsChar, lcd, XlcNChar, open_ucstocs1); - _XlcSetConverter(lcd, XlcNUcsChar, lcd, XlcNUtf8String, open_ucstoutf8); -} - -/***************************************************************************/ -/* Part II: UTF-8 locale loader conversion files - * - * Here we can assume that "multi-byte" is UTF-8 and that `wchar_t' is Unicode. - */ - -/* from XlcNMultiByte to XlcNWideChar */ - -static int -utf8towcs( - XlcConv conv, - XPointer *from, - int *from_left, - XPointer *to, - int *to_left, - XPointer *args, - int num_args) -{ - unsigned char const *src; - unsigned char const *srcend; - wchar_t *dst; - wchar_t *dstend; - int unconv_num; - - if (from == NULL || *from == NULL) - return 0; - - src = (unsigned char const *) *from; - srcend = src + *from_left; - dst = (wchar_t *) *to; - dstend = dst + *to_left; - unconv_num = 0; - - while (src < srcend && dst < dstend) { - ucs4_t wc; - int consumed = utf8_mbtowc(NULL, &wc, src, srcend-src); - if (consumed == RET_TOOFEW(0)) - break; - if (consumed == RET_ILSEQ) { - src++; - *dst = BAD_WCHAR; - unconv_num++; - } else { - src += consumed; - *dst = wc; - } - dst++; - } - - *from = (XPointer) src; - *from_left = srcend - src; - *to = (XPointer) dst; - *to_left = dstend - dst; - - return unconv_num; -} - -static XlcConvMethodsRec methods_utf8towcs = { - close_converter, - utf8towcs, - NULL -}; - -static XlcConv -open_utf8towcs( - XLCd from_lcd, - const char *from_type, - XLCd to_lcd, - const char *to_type) -{ - return create_conv(from_lcd, &methods_utf8towcs); -} - -/* from XlcNWideChar to XlcNMultiByte */ - -static int -wcstoutf8( - XlcConv conv, - XPointer *from, - int *from_left, - XPointer *to, - int *to_left, - XPointer *args, - int num_args) -{ - wchar_t const *src; - wchar_t const *srcend; - unsigned char *dst; - unsigned char *dstend; - int unconv_num; - - if (from == NULL || *from == NULL) - return 0; - - src = (wchar_t const *) *from; - srcend = src + *from_left; - dst = (unsigned char *) *to; - dstend = dst + *to_left; - unconv_num = 0; - - while (src < srcend) { - int count = utf8_wctomb(NULL, dst, *src, dstend-dst); - if (count == RET_TOOSMALL) - break; - if (count == RET_ILSEQ) { - count = utf8_wctomb(NULL, dst, BAD_WCHAR, dstend-dst); - if (count == RET_TOOSMALL) - break; - unconv_num++; - } - dst += count; - src++; - } - - *from = (XPointer) src; - *from_left = srcend - src; - *to = (XPointer) dst; - *to_left = dstend - dst; - - return unconv_num; -} - -static XlcConvMethodsRec methods_wcstoutf8 = { - close_converter, - wcstoutf8, - NULL -}; - -static XlcConv -open_wcstoutf8( - XLCd from_lcd, - const char *from_type, - XLCd to_lcd, - const char *to_type) -{ - return create_conv(from_lcd, &methods_wcstoutf8); -} - -/* from XlcNString to XlcNWideChar */ - -static int -our_strtowcs( - XlcConv conv, - XPointer *from, - int *from_left, - XPointer *to, - int *to_left, - XPointer *args, - int num_args) -{ - unsigned char const *src; - unsigned char const *srcend; - wchar_t *dst; - wchar_t *dstend; - - if (from == NULL || *from == NULL) - return 0; - - src = (unsigned char const *) *from; - srcend = src + *from_left; - dst = (wchar_t *) *to; - dstend = dst + *to_left; - - while (src < srcend && dst < dstend) - *dst++ = (wchar_t) *src++; - - *from = (XPointer) src; - *from_left = srcend - src; - *to = (XPointer) dst; - *to_left = dstend - dst; - - return 0; -} - -static XlcConvMethodsRec methods_strtowcs = { - close_converter, - our_strtowcs, - NULL -}; - -static XlcConv -open_strtowcs( - XLCd from_lcd, - const char *from_type, - XLCd to_lcd, - const char *to_type) -{ - return create_conv(from_lcd, &methods_strtowcs); -} - -/* from XlcNWideChar to XlcNString */ - -static int -our_wcstostr( - XlcConv conv, - XPointer *from, - int *from_left, - XPointer *to, - int *to_left, - XPointer *args, - int num_args) -{ - wchar_t const *src; - wchar_t const *srcend; - unsigned char *dst; - unsigned char *dstend; - int unconv_num; - - if (from == NULL || *from == NULL) - return 0; - - src = (wchar_t const *) *from; - srcend = src + *from_left; - dst = (unsigned char *) *to; - dstend = dst + *to_left; - unconv_num = 0; - - while (src < srcend && dst < dstend) { - unsigned int wc = *src++; - if (wc < 0x80) - *dst = wc; - else { - *dst = BAD_CHAR; - unconv_num++; - } - dst++; - } - - *from = (XPointer) src; - *from_left = srcend - src; - *to = (XPointer) dst; - *to_left = dstend - dst; - - return unconv_num; -} - -static XlcConvMethodsRec methods_wcstostr = { - close_converter, - our_wcstostr, - NULL -}; - -static XlcConv -open_wcstostr( - XLCd from_lcd, - const char *from_type, - XLCd to_lcd, - const char *to_type) -{ - return create_conv(from_lcd, &methods_wcstostr); -} - -/* from XlcNCharSet to XlcNWideChar */ - -static int -cstowcs( - XlcConv conv, - XPointer *from, - int *from_left, - XPointer *to, - int *to_left, - XPointer *args, - int num_args) -{ - XlcCharSet charset; - const char *name; - Utf8Conv convptr; - int i; - unsigned char const *src; - unsigned char const *srcend; - wchar_t *dst; - wchar_t *dstend; - int unconv_num; - - if (from == NULL || *from == NULL) - return 0; - - if (num_args < 1) - return -1; - - charset = (XlcCharSet) args[0]; - name = charset->encoding_name; - /* not charset->name because the latter has a ":GL"/":GR" suffix */ - - for (convptr = all_charsets, i = all_charsets_count-1; i > 0; convptr++, i--) - if (!strcmp(convptr->name, name)) - break; - if (i == 0) - return -1; - - src = (unsigned char const *) *from; - srcend = src + *from_left; - dst = (wchar_t *) *to; - dstend = dst + *to_left; - unconv_num = 0; - - while (src < srcend && dst < dstend) { - unsigned int wc; - int consumed; - - consumed = convptr->cstowc(conv, &wc, src, srcend-src); - if (consumed == RET_ILSEQ) - return -1; - if (consumed == RET_TOOFEW(0)) - break; - - *dst++ = wc; - src += consumed; - } - - *from = (XPointer) src; - *from_left = srcend - src; - *to = (XPointer) dst; - *to_left = dstend - dst; - - return unconv_num; -} - -static XlcConvMethodsRec methods_cstowcs = { - close_converter, - cstowcs, - NULL -}; - -static XlcConv -open_cstowcs( - XLCd from_lcd, - const char *from_type, - XLCd to_lcd, - const char *to_type) -{ - lazy_init_all_charsets(); - return create_conv(from_lcd, &methods_cstowcs); -} - -/* from XlcNWideChar to XlcNCharSet */ - -static int -wcstocs( - XlcConv conv, - XPointer *from, - int *from_left, - XPointer *to, - int *to_left, - XPointer *args, - int num_args) -{ - Utf8Conv *preferred_charsets; - XlcCharSet last_charset = NULL; - wchar_t const *src; - wchar_t const *srcend; - unsigned char *dst; - unsigned char *dstend; - int unconv_num; - - if (from == NULL || *from == NULL) - return 0; - - preferred_charsets = (Utf8Conv *) conv->state; - src = (wchar_t const *) *from; - srcend = src + *from_left; - dst = (unsigned char *) *to; - dstend = dst + *to_left; - unconv_num = 0; - - while (src < srcend && dst < dstend) { - Utf8Conv chosen_charset = NULL; - XlcSide chosen_side = XlcNONE; - wchar_t wc = *src; - int count; - - count = charset_wctocs(preferred_charsets, &chosen_charset, &chosen_side, conv, dst, wc, dstend-dst); - if (count == RET_TOOSMALL) - break; - if (count == RET_ILSEQ) { - src++; - unconv_num++; - continue; - } - - if (last_charset == NULL) { - last_charset = - _XlcGetCharSetWithSide(chosen_charset->name, chosen_side); - if (last_charset == NULL) { - src++; - unconv_num++; - continue; - } - } else { - if (!(last_charset->xrm_encoding_name == chosen_charset->xrm_name - && (last_charset->side == XlcGLGR - || last_charset->side == chosen_side))) - break; - } - src++; - dst += count; - } - - if (last_charset == NULL) - return -1; - - *from = (XPointer) src; - *from_left = srcend - src; - *to = (XPointer) dst; - *to_left = dstend - dst; - - if (num_args >= 1) - *((XlcCharSet *)args[0]) = last_charset; - - return unconv_num; -} - -static XlcConvMethodsRec methods_wcstocs = { - close_tocs_converter, - wcstocs, - NULL -}; - -static XlcConv -open_wcstocs( - XLCd from_lcd, - const char *from_type, - XLCd to_lcd, - const char *to_type) -{ - return create_tocs_conv(from_lcd, &methods_wcstocs); -} - -/* from XlcNWideChar to XlcNChar */ - -static int -wcstocs1( - XlcConv conv, - XPointer *from, - int *from_left, - XPointer *to, - int *to_left, - XPointer *args, - int num_args) -{ - Utf8Conv *preferred_charsets; - XlcCharSet last_charset = NULL; - wchar_t const *src; - wchar_t const *srcend; - unsigned char *dst; - unsigned char *dstend; - int unconv_num; - - if (from == NULL || *from == NULL) - return 0; - - preferred_charsets = (Utf8Conv *) conv->state; - src = (wchar_t const *) *from; - srcend = src + *from_left; - dst = (unsigned char *) *to; - dstend = dst + *to_left; - unconv_num = 0; - - while (src < srcend && dst < dstend) { - Utf8Conv chosen_charset = NULL; - XlcSide chosen_side = XlcNONE; - wchar_t wc = *src; - int count; - - count = charset_wctocs(preferred_charsets, &chosen_charset, &chosen_side, conv, dst, wc, dstend-dst); - if (count == RET_TOOSMALL) - break; - if (count == RET_ILSEQ) { - src++; - unconv_num++; - continue; - } - - if (last_charset == NULL) { - last_charset = - _XlcGetCharSetWithSide(chosen_charset->name, chosen_side); - if (last_charset == NULL) { - src++; - unconv_num++; - continue; - } - } else { - if (!(last_charset->xrm_encoding_name == chosen_charset->xrm_name - && (last_charset->side == XlcGLGR - || last_charset->side == chosen_side))) - break; - } - src++; - dst += count; - break; - } - - if (last_charset == NULL) - return -1; - - *from = (XPointer) src; - *from_left = srcend - src; - *to = (XPointer) dst; - *to_left = dstend - dst; - - if (num_args >= 1) - *((XlcCharSet *)args[0]) = last_charset; - - return unconv_num; -} - -static XlcConvMethodsRec methods_wcstocs1 = { - close_tocs_converter, - wcstocs1, - NULL -}; - -static XlcConv -open_wcstocs1( - XLCd from_lcd, - const char *from_type, - XLCd to_lcd, - const char *to_type) -{ - return create_tocs_conv(from_lcd, &methods_wcstocs1); -} - -/* trivial, no conversion */ - -static int -identity( - XlcConv conv, - XPointer *from, - int *from_left, - XPointer *to, - int *to_left, - XPointer *args, - int num_args) -{ - unsigned char const *src; - unsigned char const *srcend; - unsigned char *dst; - unsigned char *dstend; - - if (from == NULL || *from == NULL) - return 0; - - src = (unsigned char const *) *from; - srcend = src + *from_left; - dst = (unsigned char *) *to; - dstend = dst + *to_left; - - while (src < srcend && dst < dstend) - *dst++ = *src++; - - *from = (XPointer) src; - *from_left = srcend - src; - *to = (XPointer) dst; - *to_left = dstend - dst; - - return 0; -} - -static XlcConvMethodsRec methods_identity = { - close_converter, - identity, - NULL -}; - -static XlcConv -open_identity( - XLCd from_lcd, - const char *from_type, - XLCd to_lcd, - const char *to_type) -{ - return create_conv(from_lcd, &methods_identity); -} - -/* from MultiByte/WideChar to FontCharSet. */ -/* They really use converters to CharSet - * but with different create_conv procedure. */ - -static XlcConv -create_tofontcs_conv( - XLCd lcd, - XlcConvMethods methods) -{ - XlcConv conv; - int i, num, k, count; - char **value, buf[20]; - Utf8Conv *preferred; - - lazy_init_all_charsets(); - - for (i = 0, num = 0;; i++) { - sprintf(buf, "fs%d.charset.name", i); - _XlcGetResource(lcd, "XLC_FONTSET", buf, &value, &count); - if (count < 1) { - sprintf(buf, "fs%d.charset", i); - _XlcGetResource(lcd, "XLC_FONTSET", buf, &value, &count); - if (count < 1) - break; - } - num += count; - } - - conv = (XlcConv) Xmalloc(sizeof(XlcConvRec) + (num + 1) * sizeof(Utf8Conv)); - if (conv == (XlcConv) NULL) - return (XlcConv) NULL; - preferred = (Utf8Conv *) ((char *) conv + sizeof(XlcConvRec)); - - /* Loop through all fontsets mentioned in the locale. */ - for (i = 0, num = 0;; i++) { - sprintf(buf, "fs%d.charset.name", i); - _XlcGetResource(lcd, "XLC_FONTSET", buf, &value, &count); - if (count < 1) { - sprintf(buf, "fs%d.charset", i); - _XlcGetResource(lcd, "XLC_FONTSET", buf, &value, &count); - if (count < 1) - break; - } - while (count-- > 0) { - XlcCharSet charset = _XlcGetCharSet(*value++); - const char *name; - - if (charset == (XlcCharSet) NULL) - continue; - - name = charset->encoding_name; - /* If it wasn't already encountered... */ - for (k = num - 1; k >= 0; k--) - if (!strcmp(preferred[k]->name, name)) - break; - if (k < 0) { - /* For fonts "ISO10646-1" means ucs2, not utf8.*/ - if (!strcmp("ISO10646-1", name)) { - preferred[num++] = &all_charsets[ucs2_conv_index]; - continue; - } - /* Look it up in all_charsets[]. */ - for (k = 0; k < all_charsets_count-1; k++) - if (!strcmp(all_charsets[k].name, name)) { - /* Add it to the preferred set. */ - preferred[num++] = &all_charsets[k]; - break; - } - } - } - } - preferred[num] = (Utf8Conv) NULL; - - conv->methods = methods; - conv->state = (XPointer) preferred; - - return conv; -} - -static XlcConv -open_wcstofcs( - XLCd from_lcd, - const char *from_type, - XLCd to_lcd, - const char *to_type) -{ - return create_tofontcs_conv(from_lcd, &methods_wcstocs); -} - -static XlcConv -open_utf8tofcs( - XLCd from_lcd, - const char *from_type, - XLCd to_lcd, - const char *to_type) -{ - return create_tofontcs_conv(from_lcd, &methods_utf8tocs); -} - -/* ========================== iconv Stuff ================================ */ - -/* from XlcNCharSet to XlcNMultiByte */ - -static int -iconv_cstombs(XlcConv conv, XPointer *from, int *from_left, - XPointer *to, int *to_left, XPointer *args, int num_args) -{ - XlcCharSet charset; - char *name; - Utf8Conv convptr; - int i; - unsigned char const *src; - unsigned char const *srcend; - unsigned char *dst; - unsigned char *dstend; - int unconv_num; - - if (from == NULL || *from == NULL) - return 0; - - if (num_args < 1) - return -1; - - charset = (XlcCharSet) args[0]; - name = charset->encoding_name; - /* not charset->name because the latter has a ":GL"/":GR" suffix */ - - for (convptr = all_charsets, i = all_charsets_count-1; i > 0; convptr++, i--) - if (!strcmp(convptr->name, name)) - break; - if (i == 0) - return -1; - - src = (unsigned char const *) *from; - srcend = src + *from_left; - dst = (unsigned char *) *to; - dstend = dst + *to_left; - unconv_num = 0; - - while (src < srcend) { - ucs4_t wc; - int consumed; - int count; - - consumed = convptr->cstowc(conv, &wc, src, srcend-src); - if (consumed == RET_ILSEQ) - return -1; - if (consumed == RET_TOOFEW(0)) - break; - - /* Use stdc iconv to convert widechar -> multibyte */ - - count = wctomb(dst, wc); - if (count == 0) - break; - if (count == -1) { - count = wctomb(dst, BAD_WCHAR); - if (count == 0) - break; - unconv_num++; - } - src += consumed; - dst += count; - } - - *from = (XPointer) src; - *from_left = srcend - src; - *to = (XPointer) dst; - *to_left = dstend - dst; - - return unconv_num; - -} - -static XlcConvMethodsRec iconv_cstombs_methods = { - close_converter, - iconv_cstombs, - NULL -}; - -static XlcConv -open_iconv_cstombs(XLCd from_lcd, char *from_type, XLCd to_lcd, char *to_type) -{ - lazy_init_all_charsets(); - return create_conv(from_lcd, &iconv_cstombs_methods); -} - -static int -iconv_mbstocs(XlcConv conv, XPointer *from, int *from_left, - XPointer *to, int *to_left, XPointer *args, int num_args) -{ - Utf8Conv *preferred_charsets; - XlcCharSet last_charset = NULL; - unsigned char const *src; - unsigned char const *srcend; - unsigned char *dst; - unsigned char *dstend; - int unconv_num; - - if (from == NULL || *from == NULL) - return 0; - - preferred_charsets = (Utf8Conv *) conv->state; - src = (unsigned char const *) *from; - srcend = src + *from_left; - dst = (unsigned char *) *to; - dstend = dst + *to_left; - unconv_num = 0; - - while (src < srcend && dst < dstend) { - Utf8Conv chosen_charset = NULL; - XlcSide chosen_side = XlcNONE; - wchar_t wc; - int consumed; - int count; - - /* Uses stdc iconv to convert multibyte -> widechar */ - - consumed = mbtowc(&wc, src, srcend-src); - if (consumed == 0) - break; - if (consumed == -1) { - src++; - unconv_num++; - continue; - } - - count = charset_wctocs(preferred_charsets, &chosen_charset, &chosen_side, conv, dst, wc, dstend-dst); - - if (count == RET_TOOSMALL) - break; - if (count == RET_ILSEQ) { - src += consumed; - unconv_num++; - continue; - } - - if (last_charset == NULL) { - last_charset = - _XlcGetCharSetWithSide(chosen_charset->name, chosen_side); - if (last_charset == NULL) { - src += consumed; - unconv_num++; - continue; - } - } else { - if (!(last_charset->xrm_encoding_name == chosen_charset->xrm_name - && (last_charset->side == XlcGLGR - || last_charset->side == chosen_side))) - break; - } - src += consumed; - dst += count; - } - - if (last_charset == NULL) - return -1; - - *from = (XPointer) src; - *from_left = srcend - src; - *to = (XPointer) dst; - *to_left = dstend - dst; - - if (num_args >= 1) - *((XlcCharSet *)args[0]) = last_charset; - - return unconv_num; -} - -static XlcConvMethodsRec iconv_mbstocs_methods = { - close_tocs_converter, - iconv_mbstocs, - NULL -}; - -static XlcConv -open_iconv_mbstocs(XLCd from_lcd, char *from_type, XLCd to_lcd, char *to_type) -{ - return create_tocs_conv(from_lcd, &iconv_mbstocs_methods); -} - -/* from XlcNMultiByte to XlcNChar */ - -static int -iconv_mbtocs(XlcConv conv, XPointer *from, int *from_left, - XPointer *to, int *to_left, XPointer *args, int num_args) -{ - Utf8Conv *preferred_charsets; - XlcCharSet last_charset = NULL; - unsigned char const *src; - unsigned char const *srcend; - unsigned char *dst; - unsigned char *dstend; - int unconv_num; - - if (from == NULL || *from == NULL) - return 0; - - preferred_charsets = (Utf8Conv *) conv->state; - src = (unsigned char const *) *from; - srcend = src + *from_left; - dst = (unsigned char *) *to; - dstend = dst + *to_left; - unconv_num = 0; - - while (src < srcend && dst < dstend) { - Utf8Conv chosen_charset = NULL; - XlcSide chosen_side = XlcNONE; - wchar_t wc; - int consumed; - int count; - - /* Uses stdc iconv to convert multibyte -> widechar */ - - consumed = mbtowc(&wc, src, srcend-src); - if (consumed == 0) - break; - if (consumed == -1) { - src++; - unconv_num++; - continue; - } - - count = charset_wctocs(preferred_charsets, &chosen_charset, &chosen_side, conv, dst, wc, dstend-dst); - if (count == RET_TOOSMALL) - break; - if (count == RET_ILSEQ) { - src += consumed; - unconv_num++; - continue; - } - - if (last_charset == NULL) { - last_charset = - _XlcGetCharSetWithSide(chosen_charset->name, chosen_side); - if (last_charset == NULL) { - src += consumed; - unconv_num++; - continue; - } - } else { - if (!(last_charset->xrm_encoding_name == chosen_charset->xrm_name - && (last_charset->side == XlcGLGR - || last_charset->side == chosen_side))) - break; - } - src += consumed; - dst += count; - } - - if (last_charset == NULL) - return -1; - - *from = (XPointer) src; - *from_left = srcend - src; - *to = (XPointer) dst; - *to_left = dstend - dst; - - if (num_args >= 1) - *((XlcCharSet *)args[0]) = last_charset; - - return unconv_num; -} - -static XlcConvMethodsRec iconv_mbtocs_methods = { - close_tocs_converter, - iconv_mbtocs, - NULL -}; - -static XlcConv -open_iconv_mbtocs(XLCd from_lcd, char *from_type, XLCd to_lcd, char *to_type) -{ - return create_tocs_conv(from_lcd, &iconv_mbtocs_methods ); -} - -/* from XlcNMultiByte to XlcNString */ - -static int -iconv_mbstostr(XlcConv conv, XPointer *from, int *from_left, - XPointer *to, int *to_left, XPointer *args, int num_args) -{ - unsigned char const *src; - unsigned char const *srcend; - unsigned char *dst; - unsigned char *dstend; - int unconv_num; - - if (from == NULL || *from == NULL) - return 0; - - src = (unsigned char const *) *from; - srcend = src + *from_left; - dst = (unsigned char *) *to; - dstend = dst + *to_left; - unconv_num = 0; - - while (src < srcend) { - unsigned char c; - wchar_t wc; - int consumed; - - /* Uses stdc iconv to convert multibyte -> widechar */ - - consumed = mbtowc(&wc, src, srcend-src); - if (consumed == 0) - break; - if (dst == dstend) - break; - if (consumed == -1) { - consumed = 1; - c = BAD_CHAR; - unconv_num++; - } else { - if ((wc & ~(wchar_t)0xff) != 0) { - c = BAD_CHAR; - unconv_num++; - } else - c = (unsigned char) wc; - } - *dst++ = c; - src += consumed; - } - - *from = (XPointer) src; - *from_left = srcend - src; - *to = (XPointer) dst; - *to_left = dstend - dst; - - return unconv_num; -} - -static XlcConvMethodsRec iconv_mbstostr_methods = { - close_converter, - iconv_mbstostr, - NULL -}; - -static XlcConv -open_iconv_mbstostr(XLCd from_lcd, char *from_type, XLCd to_lcd, char *to_type) -{ - return create_conv(from_lcd, &iconv_mbstostr_methods); -} - -/* from XlcNString to XlcNMultiByte */ -static int -iconv_strtombs(XlcConv conv, XPointer *from, int *from_left, - XPointer *to, int *to_left, XPointer *args, int num_args) -{ - unsigned char const *src; - unsigned char const *srcend; - unsigned char *dst; - unsigned char *dstend; - - if (from == NULL || *from == NULL) - return 0; - - src = (unsigned char const *) *from; - srcend = src + *from_left; - dst = (unsigned char *) *to; - dstend = dst + *to_left; - - while (src < srcend) { - int count = wctomb(dst, *src); - if (count < 0) - break; - dst += count; - src++; - } - - *from = (XPointer) src; - *from_left = srcend - src; - *to = (XPointer) dst; - *to_left = dstend - dst; - - return 0; -} - -static XlcConvMethodsRec iconv_strtombs_methods= { - close_converter, - iconv_strtombs, - NULL -}; - -static XlcConv -open_iconv_strtombs(XLCd from_lcd, char *from_type, XLCd to_lcd, char *to_type) -{ - return create_conv(from_lcd, &iconv_strtombs_methods); -} - -/***************************************************************************/ -/* Part II: An iconv locale loader. - * - *Here we can assume that "multi-byte" is iconv and that `wchar_t' is Unicode. - */ - -/* from XlcNMultiByte to XlcNWideChar */ -static int -iconv_mbstowcs(XlcConv conv, XPointer *from, int *from_left, - XPointer *to, int *to_left, XPointer *args, int num_args) -{ - char *src = *((char **) from); - wchar_t *dst = *((wchar_t **) to); - int src_left = *from_left; - int dst_left = *to_left; - int length, unconv_num = 0; - - while (src_left > 0 && dst_left > 0) { - length = mbtowc(dst, src, src_left); - - if (length > 0) { - src += length; - src_left -= length; - if (dst) - dst++; - dst_left--; - } else if (length < 0) { - src++; - src_left--; - unconv_num++; - } else { - /* null ? */ - src++; - src_left--; - if (dst) - *dst++ = L'\0'; - dst_left--; - } - } - - *from = (XPointer) src; - if (dst) - *to = (XPointer) dst; - *from_left = src_left; - *to_left = dst_left; - - return unconv_num; -} - -static XlcConvMethodsRec iconv_mbstowcs_methods = { - close_converter, - iconv_mbstowcs, - NULL -} ; - -static XlcConv -open_iconv_mbstowcs(XLCd from_lcd, char *from_type, XLCd to_lcd, char *to_type) -{ - return create_conv(from_lcd, &iconv_mbstowcs_methods); -} - -static int -iconv_wcstombs(XlcConv conv, XPointer *from, int *from_left, - XPointer *to, int *to_left, XPointer *args, int num_args) -{ - wchar_t *src = *((wchar_t **) from); - char *dst = *((char **) to); - int src_left = *from_left; - int dst_left = *to_left; - int length, unconv_num = 0; - - while (src_left > 0 && dst_left >= MB_CUR_MAX) { - length = wctomb(dst, *src); /* XXX */ - - if (length > 0) { - src++; - src_left--; - if (dst) - dst += length; - dst_left -= length; - } else if (length < 0) { - src++; - src_left--; - unconv_num++; - } - } - - *from = (XPointer) src; - if (dst) - *to = (XPointer) dst; - *from_left = src_left; - *to_left = dst_left; - - return unconv_num; -} - -static XlcConvMethodsRec iconv_wcstombs_methods = { - close_converter, - iconv_wcstombs, - NULL -} ; - -static XlcConv -open_iconv_wcstombs(XLCd from_lcd, char *from_type, XLCd to_lcd, char *to_type) -{ - return create_conv(from_lcd, &iconv_wcstombs_methods); -} - -static XlcConv -open_iconv_mbstofcs( - XLCd from_lcd, - const char *from_type, - XLCd to_lcd, - const char *to_type) -{ - return create_tofontcs_conv(from_lcd, &iconv_mbstocs_methods); -} - -/* Registers UTF-8 converters for a UTF-8 locale. */ - -void -_XlcAddUtf8LocaleConverters( - XLCd lcd) -{ - /* Register elementary converters. */ - - _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNWideChar, open_utf8towcs); - - _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNMultiByte, open_wcstoutf8); - _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNString, open_wcstostr); - - _XlcSetConverter(lcd, XlcNString, lcd, XlcNWideChar, open_strtowcs); - - /* Register converters for XlcNCharSet. This implicitly provides - * converters from and to XlcNCompoundText. */ - - _XlcSetConverter(lcd, XlcNCharSet, lcd, XlcNMultiByte, open_cstoutf8); - _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNCharSet, open_utf8tocs); - _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNChar, open_utf8tocs1); - - _XlcSetConverter(lcd, XlcNCharSet, lcd, XlcNWideChar, open_cstowcs); - _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNCharSet, open_wcstocs); - _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNChar, open_wcstocs1); - - _XlcSetConverter(lcd, XlcNString, lcd, XlcNMultiByte, open_strtoutf8); - _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNString, open_utf8tostr); - _XlcSetConverter(lcd, XlcNUtf8String, lcd, XlcNMultiByte, open_identity); - _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNUtf8String, open_identity); - - /* Register converters for XlcNFontCharSet */ - _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNFontCharSet, open_utf8tofcs); - _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNFontCharSet, open_wcstofcs); -} - -void -_XlcAddGB18030LocaleConverters( - XLCd lcd) -{ - - /* Register elementary converters. */ - _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNWideChar, open_iconv_mbstowcs); - _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNMultiByte, open_iconv_wcstombs); - - /* Register converters for XlcNCharSet. This implicitly provides - * converters from and to XlcNCompoundText. */ - - _XlcSetConverter(lcd, XlcNCharSet, lcd, XlcNMultiByte, open_iconv_cstombs); - _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNCharSet, open_iconv_mbstocs); - _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNChar, open_iconv_mbtocs); - _XlcSetConverter(lcd, XlcNString, lcd, XlcNMultiByte, open_iconv_strtombs); - _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNString, open_iconv_mbstostr); - - /* Register converters for XlcNFontCharSet */ - _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNFontCharSet, open_iconv_mbstofcs); - - _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNString, open_wcstostr); - _XlcSetConverter(lcd, XlcNString, lcd, XlcNWideChar, open_strtowcs); - _XlcSetConverter(lcd, XlcNCharSet, lcd, XlcNWideChar, open_cstowcs); - _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNCharSet, open_wcstocs); - _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNChar, open_wcstocs1); - - /* Register converters for XlcNFontCharSet */ - _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNFontCharSet, open_wcstofcs); -} +/******************************************************************
+
+ Copyright 1993 by SunSoft, Inc.
+ Copyright 1999-2000 by Bruno Haible
+
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the names of SunSoft, Inc. and
+Bruno Haible not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission. SunSoft, Inc. and Bruno Haible make no representations
+about the suitability of this software for any purpose. It is
+provided "as is" without express or implied warranty.
+
+SunSoft Inc. AND Bruno Haible DISCLAIM ALL WARRANTIES WITH REGARD
+TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS, IN NO EVENT SHALL SunSoft, Inc. OR Bruno Haible BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/*
+ * This file contains:
+ *
+ * I. Conversion routines CompoundText/CharSet <--> Unicode/UTF-8.
+ *
+ * Used for three purposes:
+ * 1. The UTF-8 locales, see below.
+ * 2. Unicode aware applications for which the use of 8-bit character
+ * sets is an anachronism.
+ * 3. For conversion from keysym to locale encoding.
+ *
+ * II. Conversion files for an UTF-8 locale loader.
+ * Supports: all locales with codeset UTF-8.
+ * How: Provides converters for UTF-8.
+ * Platforms: all systems.
+ *
+ * The loader itself is located in lcUTF8.c.
+ */
+
+/*
+ * The conversion from UTF-8 to CompoundText is realized in a very
+ * conservative way. Recall that CompoundText data is used for inter-client
+ * communication purposes. We distinguish three classes of clients:
+ * - Clients which accept only those pieces of CompoundText which belong to
+ * the character set understood by the current locale.
+ * (Example: clients which are linked to an older X11 library.)
+ * - Clients which accept CompoundText with multiple character sets and parse
+ * it themselves.
+ * (Example: emacs, xemacs.)
+ * - Clients which rely entirely on the X{mb,wc}TextPropertyToTextList
+ * functions for the conversion of CompoundText to their current locale's
+ * multi-byte/wide-character format.
+ * For best interoperation, the UTF-8 to CompoundText conversion proceeds as
+ * follows. For every character, it first tests whether the character is
+ * representable in the current locale's original (non-UTF-8) character set.
+ * If not, it goes through the list of predefined character sets for
+ * CompoundText and tests if the character is representable in that character
+ * set. If so, it encodes the character using its code within that character
+ * set. If not, it uses an UTF-8-in-CompoundText encapsulation. Since
+ * clients of the first and second kind ignore such encapsulated text,
+ * this encapsulation is kept to a minimum and terminated as early as possible.
+ *
+ * In a distant future, when clients of the first and second kind will have
+ * disappeared, we will be able to stuff UTF-8 data directly in CompoundText
+ * without first going through the list of predefined character sets.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include "Xlibint.h"
+#include "XlcPubI.h"
+#include "XlcGeneric.h"
+
+static XlcConv
+create_conv(
+ XLCd lcd,
+ XlcConvMethods methods)
+{
+ XlcConv conv;
+
+ conv = (XlcConv) Xmalloc(sizeof(XlcConvRec));
+ if (conv == (XlcConv) NULL)
+ return (XlcConv) NULL;
+
+ conv->methods = methods;
+ conv->state = NULL;
+
+ return conv;
+}
+
+static void
+close_converter(
+ XlcConv conv)
+{
+ Xfree((char *) conv);
+}
+
+/* Replacement character for invalid multibyte sequence or wide character. */
+#define BAD_WCHAR ((ucs4_t) 0xfffd)
+#define BAD_CHAR '?'
+
+/***************************************************************************/
+/* Part I: Conversion routines CompoundText/CharSet <--> Unicode/UTF-8.
+ *
+ * Note that this code works in any locale. We store Unicode values in
+ * `ucs4_t' variables, but don't pass them to the user.
+ *
+ * This code has to support all character sets that are used for CompoundText,
+ * nothing more, nothing less. See the table in lcCT.c.
+ * Since the conversion _to_ CompoundText is likely to need the tables for all
+ * character sets at once, we don't use dynamic loading (of tables or shared
+ * libraries through iconv()). Use a fixed set of tables instead.
+ *
+ * We use statically computed tables, not dynamically allocated arrays,
+ * because it's more memory efficient: Different processes using the same
+ * libX11 shared library share the "text" and read-only "data" sections.
+ */
+
+typedef unsigned int ucs4_t;
+#define conv_t XlcConv
+
+typedef struct _Utf8ConvRec {
+ const char *name;
+ XrmQuark xrm_name;
+ int (* cstowc) (XlcConv, ucs4_t *, unsigned char const *, int);
+ int (* wctocs) (XlcConv, unsigned char *, ucs4_t, int);
+} Utf8ConvRec, *Utf8Conv;
+
+/*
+ * int xxx_cstowc (XlcConv conv, ucs4_t *pwc, unsigned char const *s, int n)
+ * converts the byte sequence starting at s to a wide character. Up to n bytes
+ * are available at s. n is >= 1.
+ * Result is number of bytes consumed (if a wide character was read),
+ * or 0 if invalid, or -1 if n too small.
+ *
+ * int xxx_wctocs (XlcConv conv, unsigned char *r, ucs4_t wc, int n)
+ * converts the wide character wc to the character set xxx, and stores the
+ * result beginning at r. Up to n bytes may be written at r. n is >= 1.
+ * Result is number of bytes written, or 0 if invalid, or -1 if n too small.
+ */
+
+/* Return code if invalid. (xxx_mbtowc, xxx_wctomb) */
+#define RET_ILSEQ 0
+/* Return code if only a shift sequence of n bytes was read. (xxx_mbtowc) */
+#define RET_TOOFEW(n) (-1-(n))
+/* Return code if output buffer is too small. (xxx_wctomb, xxx_reset) */
+#define RET_TOOSMALL -1
+
+/*
+ * The tables below are bijective. It would be possible to extend the
+ * xxx_wctocs tables to do some transliteration (e.g. U+201C,U+201D -> 0x22)
+ * but *only* with characters not contained in any other table, and *only*
+ * when the current locale is not an UTF-8 locale.
+ */
+
+#include "lcUniConv/utf8.h"
+#include "lcUniConv/ucs2be.h"
+#ifdef notused
+#include "lcUniConv/ascii.h"
+#endif
+#include "lcUniConv/iso8859_1.h"
+#include "lcUniConv/iso8859_2.h"
+#include "lcUniConv/iso8859_3.h"
+#include "lcUniConv/iso8859_4.h"
+#include "lcUniConv/iso8859_5.h"
+#include "lcUniConv/iso8859_6.h"
+#include "lcUniConv/iso8859_7.h"
+#include "lcUniConv/iso8859_8.h"
+#include "lcUniConv/iso8859_9.h"
+#include "lcUniConv/iso8859_10.h"
+#include "lcUniConv/iso8859_11.h"
+#include "lcUniConv/iso8859_13.h"
+#include "lcUniConv/iso8859_14.h"
+#include "lcUniConv/iso8859_15.h"
+#include "lcUniConv/iso8859_16.h"
+#include "lcUniConv/iso8859_9e.h"
+#include "lcUniConv/jisx0201.h"
+#include "lcUniConv/tis620.h"
+#include "lcUniConv/koi8_r.h"
+#include "lcUniConv/koi8_u.h"
+#include "lcUniConv/koi8_c.h"
+#include "lcUniConv/armscii_8.h"
+#include "lcUniConv/cp1133.h"
+#include "lcUniConv/mulelao.h"
+#include "lcUniConv/viscii.h"
+#include "lcUniConv/tcvn.h"
+#include "lcUniConv/georgian_academy.h"
+#include "lcUniConv/georgian_ps.h"
+#include "lcUniConv/cp1251.h"
+#include "lcUniConv/cp1255.h"
+#include "lcUniConv/cp1256.h"
+#include "lcUniConv/tatar_cyr.h"
+
+typedef struct {
+ unsigned short indx; /* index into big table */
+ unsigned short used; /* bitmask of used entries */
+} Summary16;
+
+#include "lcUniConv/gb2312.h"
+#include "lcUniConv/jisx0208.h"
+#include "lcUniConv/jisx0212.h"
+#include "lcUniConv/ksc5601.h"
+#include "lcUniConv/big5.h"
+#include "lcUniConv/big5_emacs.h"
+#include "lcUniConv/big5hkscs.h"
+#include "lcUniConv/gbk.h"
+
+static Utf8ConvRec all_charsets[] = {
+ /* The ISO10646-1/UTF-8 entry occurs twice, once at the beginning
+ (for lookup speed), once at the end (as a fallback). */
+ { "ISO10646-1", NULLQUARK,
+ utf8_mbtowc, utf8_wctomb
+ },
+
+ { "ISO8859-1", NULLQUARK,
+ iso8859_1_mbtowc, iso8859_1_wctomb
+ },
+ { "ISO8859-2", NULLQUARK,
+ iso8859_2_mbtowc, iso8859_2_wctomb
+ },
+ { "ISO8859-3", NULLQUARK,
+ iso8859_3_mbtowc, iso8859_3_wctomb
+ },
+ { "ISO8859-4", NULLQUARK,
+ iso8859_4_mbtowc, iso8859_4_wctomb
+ },
+ { "ISO8859-5", NULLQUARK,
+ iso8859_5_mbtowc, iso8859_5_wctomb
+ },
+ { "ISO8859-6", NULLQUARK,
+ iso8859_6_mbtowc, iso8859_6_wctomb
+ },
+ { "ISO8859-7", NULLQUARK,
+ iso8859_7_mbtowc, iso8859_7_wctomb
+ },
+ { "ISO8859-8", NULLQUARK,
+ iso8859_8_mbtowc, iso8859_8_wctomb
+ },
+ { "ISO8859-9", NULLQUARK,
+ iso8859_9_mbtowc, iso8859_9_wctomb
+ },
+ { "ISO8859-10", NULLQUARK,
+ iso8859_10_mbtowc, iso8859_10_wctomb
+ },
+ { "ISO8859-11", NULLQUARK,
+ iso8859_11_mbtowc, iso8859_11_wctomb
+ },
+ { "ISO8859-13", NULLQUARK,
+ iso8859_13_mbtowc, iso8859_13_wctomb
+ },
+ { "ISO8859-14", NULLQUARK,
+ iso8859_14_mbtowc, iso8859_14_wctomb
+ },
+ { "ISO8859-15", NULLQUARK,
+ iso8859_15_mbtowc, iso8859_15_wctomb
+ },
+ { "ISO8859-16", NULLQUARK,
+ iso8859_16_mbtowc, iso8859_16_wctomb
+ },
+ { "JISX0201.1976-0", NULLQUARK,
+ jisx0201_mbtowc, jisx0201_wctomb
+ },
+ { "TIS620-0", NULLQUARK,
+ tis620_mbtowc, tis620_wctomb
+ },
+ { "GB2312.1980-0", NULLQUARK,
+ gb2312_mbtowc, gb2312_wctomb
+ },
+ { "JISX0208.1983-0", NULLQUARK,
+ jisx0208_mbtowc, jisx0208_wctomb
+ },
+ { "JISX0208.1990-0", NULLQUARK,
+ jisx0208_mbtowc, jisx0208_wctomb
+ },
+ { "JISX0212.1990-0", NULLQUARK,
+ jisx0212_mbtowc, jisx0212_wctomb
+ },
+ { "KSC5601.1987-0", NULLQUARK,
+ ksc5601_mbtowc, ksc5601_wctomb
+ },
+ { "KOI8-R", NULLQUARK,
+ koi8_r_mbtowc, koi8_r_wctomb
+ },
+ { "KOI8-U", NULLQUARK,
+ koi8_u_mbtowc, koi8_u_wctomb
+ },
+ { "KOI8-C", NULLQUARK,
+ koi8_c_mbtowc, koi8_c_wctomb
+ },
+ { "TATAR-CYR", NULLQUARK,
+ tatar_cyr_mbtowc, tatar_cyr_wctomb
+ },
+ { "ARMSCII-8", NULLQUARK,
+ armscii_8_mbtowc, armscii_8_wctomb
+ },
+ { "IBM-CP1133", NULLQUARK,
+ cp1133_mbtowc, cp1133_wctomb
+ },
+ { "MULELAO-1", NULLQUARK,
+ mulelao_mbtowc, mulelao_wctomb
+ },
+ { "VISCII1.1-1", NULLQUARK,
+ viscii_mbtowc, viscii_wctomb
+ },
+ { "TCVN-5712", NULLQUARK,
+ tcvn_mbtowc, tcvn_wctomb
+ },
+ { "GEORGIAN-ACADEMY", NULLQUARK,
+ georgian_academy_mbtowc, georgian_academy_wctomb
+ },
+ { "GEORGIAN-PS", NULLQUARK,
+ georgian_ps_mbtowc, georgian_ps_wctomb
+ },
+ { "ISO8859-9E", NULLQUARK,
+ iso8859_9e_mbtowc, iso8859_9e_wctomb
+ },
+ { "MICROSOFT-CP1251", NULLQUARK,
+ cp1251_mbtowc, cp1251_wctomb
+ },
+ { "MICROSOFT-CP1255", NULLQUARK,
+ cp1255_mbtowc, cp1255_wctomb
+ },
+ { "MICROSOFT-CP1256", NULLQUARK,
+ cp1256_mbtowc, cp1256_wctomb
+ },
+ { "BIG5-0", NULLQUARK,
+ big5_mbtowc, big5_wctomb
+ },
+ { "BIG5-E0", NULLQUARK,
+ big5_0_mbtowc, big5_0_wctomb
+ },
+ { "BIG5-E1", NULLQUARK,
+ big5_1_mbtowc, big5_1_wctomb
+ },
+ { "GBK-0", NULLQUARK,
+ gbk_mbtowc, gbk_wctomb
+ },
+ { "BIG5HKSCS-0", NULLQUARK,
+ big5hkscs_mbtowc, big5hkscs_wctomb
+ },
+
+ /* The ISO10646-1/UTF-8 entry occurs twice, once at the beginning
+ (for lookup speed), once at the end (as a fallback). */
+ { "ISO10646-1", NULLQUARK,
+ utf8_mbtowc, utf8_wctomb
+ },
+
+ /* Encoding ISO10646-1 for fonts means UCS2-like encoding
+ so for conversion to FontCharSet we need this record */
+ { "ISO10646-1", NULLQUARK,
+ ucs2be_mbtowc, ucs2be_wctomb
+ }
+};
+
+#define charsets_table_size (sizeof(all_charsets)/sizeof(all_charsets[0]))
+#define all_charsets_count (charsets_table_size - 1)
+#define ucs2_conv_index (charsets_table_size - 1)
+
+static void
+init_all_charsets (void)
+{
+ Utf8Conv convptr;
+ int i;
+
+ for (convptr = all_charsets, i = charsets_table_size; i > 0; convptr++, i--)
+ convptr->xrm_name = XrmStringToQuark(convptr->name);
+}
+
+#define lazy_init_all_charsets() \
+ do { \
+ if (all_charsets[0].xrm_name == NULLQUARK) \
+ init_all_charsets(); \
+ } while (0)
+
+/* from XlcNCharSet to XlcNUtf8String */
+
+static int
+cstoutf8(
+ XlcConv conv,
+ XPointer *from,
+ int *from_left,
+ XPointer *to,
+ int *to_left,
+ XPointer *args,
+ int num_args)
+{
+ XlcCharSet charset;
+ const char *name;
+ Utf8Conv convptr;
+ int i;
+ unsigned char const *src;
+ unsigned char const *srcend;
+ unsigned char *dst;
+ unsigned char *dstend;
+ int unconv_num;
+
+ if (from == NULL || *from == NULL)
+ return 0;
+
+ if (num_args < 1)
+ return -1;
+
+ charset = (XlcCharSet) args[0];
+ name = charset->encoding_name;
+ /* not charset->name because the latter has a ":GL"/":GR" suffix */
+
+ for (convptr = all_charsets, i = all_charsets_count-1; i > 0; convptr++, i--)
+ if (!strcmp(convptr->name, name))
+ break;
+ if (i == 0)
+ return -1;
+
+ src = (unsigned char const *) *from;
+ srcend = src + *from_left;
+ dst = (unsigned char *) *to;
+ dstend = dst + *to_left;
+ unconv_num = 0;
+
+ while (src < srcend) {
+ ucs4_t wc;
+ int consumed;
+ int count;
+
+ consumed = convptr->cstowc(conv, &wc, src, srcend-src);
+ if (consumed == RET_ILSEQ)
+ return -1;
+ if (consumed == RET_TOOFEW(0))
+ break;
+
+ count = utf8_wctomb(NULL, dst, wc, dstend-dst);
+ if (count == RET_TOOSMALL)
+ break;
+ if (count == RET_ILSEQ) {
+ count = utf8_wctomb(NULL, dst, BAD_WCHAR, dstend-dst);
+ if (count == RET_TOOSMALL)
+ break;
+ unconv_num++;
+ }
+ src += consumed;
+ dst += count;
+ }
+
+ *from = (XPointer) src;
+ *from_left = srcend - src;
+ *to = (XPointer) dst;
+ *to_left = dstend - dst;
+
+ return unconv_num;
+}
+
+static XlcConvMethodsRec methods_cstoutf8 = {
+ close_converter,
+ cstoutf8,
+ NULL
+};
+
+static XlcConv
+open_cstoutf8(
+ XLCd from_lcd,
+ const char *from_type,
+ XLCd to_lcd,
+ const char *to_type)
+{
+ lazy_init_all_charsets();
+ return create_conv(from_lcd, &methods_cstoutf8);
+}
+
+/* from XlcNUtf8String to XlcNCharSet */
+
+static XlcConv
+create_tocs_conv(
+ XLCd lcd,
+ XlcConvMethods methods)
+{
+ XlcConv conv;
+ CodeSet *codeset_list;
+ int codeset_num;
+ int charset_num;
+ int i, j, k;
+ Utf8Conv *preferred;
+
+ lazy_init_all_charsets();
+
+ codeset_list = XLC_GENERIC(lcd, codeset_list);
+ codeset_num = XLC_GENERIC(lcd, codeset_num);
+
+ charset_num = 0;
+ for (i = 0; i < codeset_num; i++)
+ charset_num += codeset_list[i]->num_charsets;
+ if (charset_num > all_charsets_count-1)
+ charset_num = all_charsets_count-1;
+
+ conv = (XlcConv) Xmalloc(sizeof(XlcConvRec)
+ + (charset_num + 1) * sizeof(Utf8Conv));
+ if (conv == (XlcConv) NULL)
+ return (XlcConv) NULL;
+ preferred = (Utf8Conv *) ((char *) conv + sizeof(XlcConvRec));
+
+ /* Loop through all codesets mentioned in the locale. */
+ charset_num = 0;
+ for (i = 0; i < codeset_num; i++) {
+ XlcCharSet *charsets = codeset_list[i]->charset_list;
+ int num_charsets = codeset_list[i]->num_charsets;
+ for (j = 0; j < num_charsets; j++) {
+ const char *name = charsets[j]->encoding_name;
+ /* If it wasn't already encountered... */
+ for (k = charset_num-1; k >= 0; k--)
+ if (!strcmp(preferred[k]->name, name))
+ break;
+ if (k < 0) {
+ /* Look it up in all_charsets[]. */
+ for (k = 0; k < all_charsets_count-1; k++)
+ if (!strcmp(all_charsets[k].name, name)) {
+ /* Add it to the preferred set. */
+ preferred[charset_num++] = &all_charsets[k];
+ break;
+ }
+ }
+ }
+ }
+ preferred[charset_num] = (Utf8Conv) NULL;
+
+ conv->methods = methods;
+ conv->state = (XPointer) preferred;
+
+ return conv;
+}
+
+static void
+close_tocs_converter(
+ XlcConv conv)
+{
+ /* conv->state is allocated together with conv, free both at once. */
+ Xfree((char *) conv);
+}
+
+/*
+ * Converts a Unicode character to an appropriate character set. The NULL
+ * terminated array of preferred character sets is passed as first argument.
+ * If successful, *charsetp is set to the character set that was used, and
+ * *sidep is set to the character set side (XlcGL or XlcGR).
+ */
+static int
+charset_wctocs(
+ Utf8Conv *preferred,
+ Utf8Conv *charsetp,
+ XlcSide *sidep,
+ XlcConv conv,
+ unsigned char *r,
+ ucs4_t wc,
+ int n)
+{
+ int count;
+ Utf8Conv convptr;
+ int i;
+
+ for (; *preferred != (Utf8Conv) NULL; preferred++) {
+ convptr = *preferred;
+ count = convptr->wctocs(conv, r, wc, n);
+ if (count == RET_TOOSMALL)
+ return RET_TOOSMALL;
+ if (count != RET_ILSEQ) {
+ *charsetp = convptr;
+ *sidep = (*r < 0x80 ? XlcGL : XlcGR);
+ return count;
+ }
+ }
+ for (convptr = all_charsets+1, i = all_charsets_count-1; i > 0; convptr++, i--) {
+ count = convptr->wctocs(conv, r, wc, n);
+ if (count == RET_TOOSMALL)
+ return RET_TOOSMALL;
+ if (count != RET_ILSEQ) {
+ *charsetp = convptr;
+ *sidep = (*r < 0x80 ? XlcGL : XlcGR);
+ return count;
+ }
+ }
+ return RET_ILSEQ;
+}
+
+static int
+utf8tocs(
+ XlcConv conv,
+ XPointer *from,
+ int *from_left,
+ XPointer *to,
+ int *to_left,
+ XPointer *args,
+ int num_args)
+{
+ Utf8Conv *preferred_charsets;
+ XlcCharSet last_charset = NULL;
+ unsigned char const *src;
+ unsigned char const *srcend;
+ unsigned char *dst;
+ unsigned char *dstend;
+ int unconv_num;
+
+ if (from == NULL || *from == NULL)
+ return 0;
+
+ preferred_charsets = (Utf8Conv *) conv->state;
+ src = (unsigned char const *) *from;
+ srcend = src + *from_left;
+ dst = (unsigned char *) *to;
+ dstend = dst + *to_left;
+ unconv_num = 0;
+
+ while (src < srcend && dst < dstend) {
+ Utf8Conv chosen_charset = NULL;
+ XlcSide chosen_side = XlcNONE;
+ ucs4_t wc;
+ int consumed;
+ int count;
+
+ consumed = utf8_mbtowc(NULL, &wc, src, srcend-src);
+ if (consumed == RET_TOOFEW(0))
+ break;
+ if (consumed == RET_ILSEQ) {
+ src++;
+ unconv_num++;
+ continue;
+ }
+
+ count = charset_wctocs(preferred_charsets, &chosen_charset, &chosen_side, conv, dst, wc, dstend-dst);
+ if (count == RET_TOOSMALL)
+ break;
+ if (count == RET_ILSEQ) {
+ src += consumed;
+ unconv_num++;
+ continue;
+ }
+
+ if (last_charset == NULL) {
+ last_charset =
+ _XlcGetCharSetWithSide(chosen_charset->name, chosen_side);
+ if (last_charset == NULL) {
+ src += consumed;
+ unconv_num++;
+ continue;
+ }
+ } else {
+ if (!(last_charset->xrm_encoding_name == chosen_charset->xrm_name
+ && (last_charset->side == XlcGLGR
+ || last_charset->side == chosen_side)))
+ break;
+ }
+ src += consumed;
+ dst += count;
+ }
+
+ if (last_charset == NULL)
+ return -1;
+
+ *from = (XPointer) src;
+ *from_left = srcend - src;
+ *to = (XPointer) dst;
+ *to_left = dstend - dst;
+
+ if (num_args >= 1)
+ *((XlcCharSet *)args[0]) = last_charset;
+
+ return unconv_num;
+}
+
+static XlcConvMethodsRec methods_utf8tocs = {
+ close_tocs_converter,
+ utf8tocs,
+ NULL
+};
+
+static XlcConv
+open_utf8tocs(
+ XLCd from_lcd,
+ const char *from_type,
+ XLCd to_lcd,
+ const char *to_type)
+{
+ return create_tocs_conv(from_lcd, &methods_utf8tocs);
+}
+
+/* from XlcNUtf8String to XlcNChar */
+
+static int
+utf8tocs1(
+ XlcConv conv,
+ XPointer *from,
+ int *from_left,
+ XPointer *to,
+ int *to_left,
+ XPointer *args,
+ int num_args)
+{
+ Utf8Conv *preferred_charsets;
+ XlcCharSet last_charset = NULL;
+ unsigned char const *src;
+ unsigned char const *srcend;
+ unsigned char *dst;
+ unsigned char *dstend;
+ int unconv_num;
+
+ if (from == NULL || *from == NULL)
+ return 0;
+
+ preferred_charsets = (Utf8Conv *) conv->state;
+ src = (unsigned char const *) *from;
+ srcend = src + *from_left;
+ dst = (unsigned char *) *to;
+ dstend = dst + *to_left;
+ unconv_num = 0;
+
+ while (src < srcend && dst < dstend) {
+ Utf8Conv chosen_charset = NULL;
+ XlcSide chosen_side = XlcNONE;
+ ucs4_t wc;
+ int consumed;
+ int count;
+
+ consumed = utf8_mbtowc(NULL, &wc, src, srcend-src);
+ if (consumed == RET_TOOFEW(0))
+ break;
+ if (consumed == RET_ILSEQ) {
+ src++;
+ unconv_num++;
+ continue;
+ }
+
+ count = charset_wctocs(preferred_charsets, &chosen_charset, &chosen_side, conv, dst, wc, dstend-dst);
+ if (count == RET_TOOSMALL)
+ break;
+ if (count == RET_ILSEQ) {
+ src += consumed;
+ unconv_num++;
+ continue;
+ }
+
+ if (last_charset == NULL) {
+ last_charset =
+ _XlcGetCharSetWithSide(chosen_charset->name, chosen_side);
+ if (last_charset == NULL) {
+ src += consumed;
+ unconv_num++;
+ continue;
+ }
+ } else {
+ if (!(last_charset->xrm_encoding_name == chosen_charset->xrm_name
+ && (last_charset->side == XlcGLGR
+ || last_charset->side == chosen_side)))
+ break;
+ }
+ src += consumed;
+ dst += count;
+ break;
+ }
+
+ if (last_charset == NULL)
+ return -1;
+
+ *from = (XPointer) src;
+ *from_left = srcend - src;
+ *to = (XPointer) dst;
+ *to_left = dstend - dst;
+
+ if (num_args >= 1)
+ *((XlcCharSet *)args[0]) = last_charset;
+
+ return unconv_num;
+}
+
+static XlcConvMethodsRec methods_utf8tocs1 = {
+ close_tocs_converter,
+ utf8tocs1,
+ NULL
+};
+
+static XlcConv
+open_utf8tocs1(
+ XLCd from_lcd,
+ const char *from_type,
+ XLCd to_lcd,
+ const char *to_type)
+{
+ return create_tocs_conv(from_lcd, &methods_utf8tocs1);
+}
+
+/* from XlcNUtf8String to XlcNString */
+
+static int
+utf8tostr(
+ XlcConv conv,
+ XPointer *from,
+ int *from_left,
+ XPointer *to,
+ int *to_left,
+ XPointer *args,
+ int num_args)
+{
+ unsigned char const *src;
+ unsigned char const *srcend;
+ unsigned char *dst;
+ unsigned char *dstend;
+ int unconv_num;
+
+ if (from == NULL || *from == NULL)
+ return 0;
+
+ src = (unsigned char const *) *from;
+ srcend = src + *from_left;
+ dst = (unsigned char *) *to;
+ dstend = dst + *to_left;
+ unconv_num = 0;
+
+ while (src < srcend) {
+ unsigned char c;
+ ucs4_t wc;
+ int consumed;
+
+ consumed = utf8_mbtowc(NULL, &wc, src, srcend-src);
+ if (consumed == RET_TOOFEW(0))
+ break;
+ if (dst == dstend)
+ break;
+ if (consumed == RET_ILSEQ) {
+ consumed = 1;
+ c = BAD_CHAR;
+ unconv_num++;
+ } else {
+ if ((wc & ~(ucs4_t)0xff) != 0) {
+ c = BAD_CHAR;
+ unconv_num++;
+ } else
+ c = (unsigned char) wc;
+ }
+ *dst++ = c;
+ src += consumed;
+ }
+
+ *from = (XPointer) src;
+ *from_left = srcend - src;
+ *to = (XPointer) dst;
+ *to_left = dstend - dst;
+
+ return unconv_num;
+}
+
+static XlcConvMethodsRec methods_utf8tostr = {
+ close_converter,
+ utf8tostr,
+ NULL
+};
+
+static XlcConv
+open_utf8tostr(
+ XLCd from_lcd,
+ const char *from_type,
+ XLCd to_lcd,
+ const char *to_type)
+{
+ return create_conv(from_lcd, &methods_utf8tostr);
+}
+
+/* from XlcNString to XlcNUtf8String */
+
+static int
+strtoutf8(
+ XlcConv conv,
+ XPointer *from,
+ int *from_left,
+ XPointer *to,
+ int *to_left,
+ XPointer *args,
+ int num_args)
+{
+ unsigned char const *src;
+ unsigned char const *srcend;
+ unsigned char *dst;
+ unsigned char *dstend;
+
+ if (from == NULL || *from == NULL)
+ return 0;
+
+ src = (unsigned char const *) *from;
+ srcend = src + *from_left;
+ dst = (unsigned char *) *to;
+ dstend = dst + *to_left;
+
+ while (src < srcend) {
+ int count = utf8_wctomb(NULL, dst, *src, dstend-dst);
+ if (count == RET_TOOSMALL)
+ break;
+ dst += count;
+ src++;
+ }
+
+ *from = (XPointer) src;
+ *from_left = srcend - src;
+ *to = (XPointer) dst;
+ *to_left = dstend - dst;
+
+ return 0;
+}
+
+static XlcConvMethodsRec methods_strtoutf8 = {
+ close_converter,
+ strtoutf8,
+ NULL
+};
+
+static XlcConv
+open_strtoutf8(
+ XLCd from_lcd,
+ const char *from_type,
+ XLCd to_lcd,
+ const char *to_type)
+{
+ return create_conv(from_lcd, &methods_strtoutf8);
+}
+
+/* Support for the input methods. */
+
+XPointer
+_Utf8GetConvByName(
+ const char *name)
+{
+ XrmQuark xrm_name;
+ Utf8Conv convptr;
+ int i;
+
+ if (name == NULL)
+ return (XPointer) NULL;
+
+ lazy_init_all_charsets();
+ xrm_name = XrmStringToQuark(name);
+
+ for (convptr = all_charsets, i = all_charsets_count-1; i > 0; convptr++, i--)
+ if (convptr->xrm_name == xrm_name)
+ return (XPointer) convptr->wctocs;
+ return (XPointer) NULL;
+}
+
+/* from XlcNUcsChar to XlcNChar, needed for input methods */
+
+static XlcConv
+create_ucstocs_conv(
+ XLCd lcd,
+ XlcConvMethods methods)
+{
+
+ if (XLC_PUBLIC_PART(lcd)->codeset
+ && _XlcCompareISOLatin1(XLC_PUBLIC_PART(lcd)->codeset, "UTF-8") == 0) {
+ XlcConv conv;
+ Utf8Conv *preferred;
+
+ lazy_init_all_charsets();
+
+ conv = (XlcConv) Xmalloc(sizeof(XlcConvRec) + 2 * sizeof(Utf8Conv));
+ if (conv == (XlcConv) NULL)
+ return (XlcConv) NULL;
+ preferred = (Utf8Conv *) ((char *) conv + sizeof(XlcConvRec));
+
+ preferred[0] = &all_charsets[0]; /* ISO10646 */
+ preferred[1] = (Utf8Conv) NULL;
+
+ conv->methods = methods;
+ conv->state = (XPointer) preferred;
+
+ return conv;
+ } else {
+ return create_tocs_conv(lcd, methods);
+ }
+}
+
+static int
+charset_wctocs_exactly(
+ Utf8Conv *preferred,
+ Utf8Conv *charsetp,
+ XlcSide *sidep,
+ XlcConv conv,
+ unsigned char *r,
+ ucs4_t wc,
+ int n)
+{
+ int count;
+ Utf8Conv convptr;
+
+ for (; *preferred != (Utf8Conv) NULL; preferred++) {
+ convptr = *preferred;
+ count = convptr->wctocs(conv, r, wc, n);
+ if (count == RET_TOOSMALL)
+ return RET_TOOSMALL;
+ if (count != RET_ILSEQ) {
+ *charsetp = convptr;
+ *sidep = (*r < 0x80 ? XlcGL : XlcGR);
+ return count;
+ }
+ }
+ return RET_ILSEQ;
+}
+
+static int
+ucstocs1(
+ XlcConv conv,
+ XPointer *from,
+ int *from_left,
+ XPointer *to,
+ int *to_left,
+ XPointer *args,
+ int num_args)
+{
+ ucs4_t const *src = (ucs4_t const *) *from;
+ unsigned char *dst = (unsigned char *) *to;
+ int unconv_num = 0;
+ Utf8Conv *preferred_charsets = (Utf8Conv *) conv->state;
+ Utf8Conv chosen_charset = NULL;
+ XlcSide chosen_side = XlcNONE;
+ XlcCharSet charset = NULL;
+ int count;
+
+ if (from == NULL || *from == NULL)
+ return 0;
+
+ count = charset_wctocs_exactly(preferred_charsets, &chosen_charset,
+ &chosen_side, conv, dst, *src, *to_left);
+ if (count < 1) {
+ unconv_num++;
+ count = 0;
+ } else {
+ charset = _XlcGetCharSetWithSide(chosen_charset->name, chosen_side);
+ }
+ if (charset == NULL)
+ return -1;
+
+ *from = (XPointer) ++src;
+ (*from_left)--;
+ *to = (XPointer) dst;
+ *to_left -= count;
+
+ if (num_args >= 1)
+ *((XlcCharSet *)args[0]) = charset;
+
+ return unconv_num;
+}
+
+static XlcConvMethodsRec methods_ucstocs1 = {
+ close_tocs_converter,
+ ucstocs1,
+ NULL
+};
+
+static XlcConv
+open_ucstocs1(
+ XLCd from_lcd,
+ const char *from_type,
+ XLCd to_lcd,
+ const char *to_type)
+{
+ return create_ucstocs_conv(from_lcd, &methods_ucstocs1);
+}
+
+/* from XlcNUcsChar to XlcNUtf8String, needed for input methods */
+
+static int
+ucstoutf8(
+ XlcConv conv,
+ XPointer *from,
+ int *from_left,
+ XPointer *to,
+ int *to_left,
+ XPointer *args,
+ int num_args)
+{
+ const ucs4_t *src;
+ const ucs4_t *srcend;
+ unsigned char *dst;
+ unsigned char *dstend;
+ int unconv_num;
+
+ if (from == NULL || *from == NULL)
+ return 0;
+
+ src = (const ucs4_t *) *from;
+ srcend = src + *from_left;
+ dst = (unsigned char *) *to;
+ dstend = dst + *to_left;
+ unconv_num = 0;
+
+ while (src < srcend) {
+ int count = utf8_wctomb(NULL, dst, *src, dstend-dst);
+ if (count == RET_TOOSMALL)
+ break;
+ if (count == RET_ILSEQ)
+ unconv_num++;
+ src++;
+ dst += count;
+ }
+
+ *from = (XPointer) src;
+ *from_left = srcend - src;
+ *to = (XPointer) dst;
+ *to_left = dstend - dst;
+
+ return unconv_num;
+}
+
+static XlcConvMethodsRec methods_ucstoutf8 = {
+ close_converter,
+ ucstoutf8,
+ NULL
+};
+
+static XlcConv
+open_ucstoutf8(
+ XLCd from_lcd,
+ const char *from_type,
+ XLCd to_lcd,
+ const char *to_type)
+{
+ return create_conv(from_lcd, &methods_ucstoutf8);
+}
+
+/* Registers UTF-8 converters for a non-UTF-8 locale. */
+void
+_XlcAddUtf8Converters(
+ XLCd lcd)
+{
+ _XlcSetConverter(lcd, XlcNCharSet, lcd, XlcNUtf8String, open_cstoutf8);
+ _XlcSetConverter(lcd, XlcNUtf8String, lcd, XlcNCharSet, open_utf8tocs);
+ _XlcSetConverter(lcd, XlcNUtf8String, lcd, XlcNChar, open_utf8tocs1);
+ _XlcSetConverter(lcd, XlcNString, lcd, XlcNUtf8String, open_strtoutf8);
+ _XlcSetConverter(lcd, XlcNUtf8String, lcd, XlcNString, open_utf8tostr);
+ _XlcSetConverter(lcd, XlcNUcsChar, lcd, XlcNChar, open_ucstocs1);
+ _XlcSetConverter(lcd, XlcNUcsChar, lcd, XlcNUtf8String, open_ucstoutf8);
+}
+
+/***************************************************************************/
+/* Part II: UTF-8 locale loader conversion files
+ *
+ * Here we can assume that "multi-byte" is UTF-8 and that `wchar_t' is Unicode.
+ */
+
+/* from XlcNMultiByte to XlcNWideChar */
+
+static int
+utf8towcs(
+ XlcConv conv,
+ XPointer *from,
+ int *from_left,
+ XPointer *to,
+ int *to_left,
+ XPointer *args,
+ int num_args)
+{
+ unsigned char const *src;
+ unsigned char const *srcend;
+ wchar_t *dst;
+ wchar_t *dstend;
+ int unconv_num;
+
+ if (from == NULL || *from == NULL)
+ return 0;
+
+ src = (unsigned char const *) *from;
+ srcend = src + *from_left;
+ dst = (wchar_t *) *to;
+ dstend = dst + *to_left;
+ unconv_num = 0;
+
+ while (src < srcend && dst < dstend) {
+ ucs4_t wc;
+ int consumed = utf8_mbtowc(NULL, &wc, src, srcend-src);
+ if (consumed == RET_TOOFEW(0))
+ break;
+ if (consumed == RET_ILSEQ) {
+ src++;
+ *dst = BAD_WCHAR;
+ unconv_num++;
+ } else {
+ src += consumed;
+ *dst = wc;
+ }
+ dst++;
+ }
+
+ *from = (XPointer) src;
+ *from_left = srcend - src;
+ *to = (XPointer) dst;
+ *to_left = dstend - dst;
+
+ return unconv_num;
+}
+
+static XlcConvMethodsRec methods_utf8towcs = {
+ close_converter,
+ utf8towcs,
+ NULL
+};
+
+static XlcConv
+open_utf8towcs(
+ XLCd from_lcd,
+ const char *from_type,
+ XLCd to_lcd,
+ const char *to_type)
+{
+ return create_conv(from_lcd, &methods_utf8towcs);
+}
+
+/* from XlcNWideChar to XlcNMultiByte */
+
+static int
+wcstoutf8(
+ XlcConv conv,
+ XPointer *from,
+ int *from_left,
+ XPointer *to,
+ int *to_left,
+ XPointer *args,
+ int num_args)
+{
+ wchar_t const *src;
+ wchar_t const *srcend;
+ unsigned char *dst;
+ unsigned char *dstend;
+ int unconv_num;
+
+ if (from == NULL || *from == NULL)
+ return 0;
+
+ src = (wchar_t const *) *from;
+ srcend = src + *from_left;
+ dst = (unsigned char *) *to;
+ dstend = dst + *to_left;
+ unconv_num = 0;
+
+ while (src < srcend) {
+ int count = utf8_wctomb(NULL, dst, *src, dstend-dst);
+ if (count == RET_TOOSMALL)
+ break;
+ if (count == RET_ILSEQ) {
+ count = utf8_wctomb(NULL, dst, BAD_WCHAR, dstend-dst);
+ if (count == RET_TOOSMALL)
+ break;
+ unconv_num++;
+ }
+ dst += count;
+ src++;
+ }
+
+ *from = (XPointer) src;
+ *from_left = srcend - src;
+ *to = (XPointer) dst;
+ *to_left = dstend - dst;
+
+ return unconv_num;
+}
+
+static XlcConvMethodsRec methods_wcstoutf8 = {
+ close_converter,
+ wcstoutf8,
+ NULL
+};
+
+static XlcConv
+open_wcstoutf8(
+ XLCd from_lcd,
+ const char *from_type,
+ XLCd to_lcd,
+ const char *to_type)
+{
+ return create_conv(from_lcd, &methods_wcstoutf8);
+}
+
+/* from XlcNString to XlcNWideChar */
+
+static int
+our_strtowcs(
+ XlcConv conv,
+ XPointer *from,
+ int *from_left,
+ XPointer *to,
+ int *to_left,
+ XPointer *args,
+ int num_args)
+{
+ unsigned char const *src;
+ unsigned char const *srcend;
+ wchar_t *dst;
+ wchar_t *dstend;
+
+ if (from == NULL || *from == NULL)
+ return 0;
+
+ src = (unsigned char const *) *from;
+ srcend = src + *from_left;
+ dst = (wchar_t *) *to;
+ dstend = dst + *to_left;
+
+ while (src < srcend && dst < dstend)
+ *dst++ = (wchar_t) *src++;
+
+ *from = (XPointer) src;
+ *from_left = srcend - src;
+ *to = (XPointer) dst;
+ *to_left = dstend - dst;
+
+ return 0;
+}
+
+static XlcConvMethodsRec methods_strtowcs = {
+ close_converter,
+ our_strtowcs,
+ NULL
+};
+
+static XlcConv
+open_strtowcs(
+ XLCd from_lcd,
+ const char *from_type,
+ XLCd to_lcd,
+ const char *to_type)
+{
+ return create_conv(from_lcd, &methods_strtowcs);
+}
+
+/* from XlcNWideChar to XlcNString */
+
+static int
+our_wcstostr(
+ XlcConv conv,
+ XPointer *from,
+ int *from_left,
+ XPointer *to,
+ int *to_left,
+ XPointer *args,
+ int num_args)
+{
+ wchar_t const *src;
+ wchar_t const *srcend;
+ unsigned char *dst;
+ unsigned char *dstend;
+ int unconv_num;
+
+ if (from == NULL || *from == NULL)
+ return 0;
+
+ src = (wchar_t const *) *from;
+ srcend = src + *from_left;
+ dst = (unsigned char *) *to;
+ dstend = dst + *to_left;
+ unconv_num = 0;
+
+ while (src < srcend && dst < dstend) {
+ unsigned int wc = *src++;
+ if (wc < 0x80)
+ *dst = wc;
+ else {
+ *dst = BAD_CHAR;
+ unconv_num++;
+ }
+ dst++;
+ }
+
+ *from = (XPointer) src;
+ *from_left = srcend - src;
+ *to = (XPointer) dst;
+ *to_left = dstend - dst;
+
+ return unconv_num;
+}
+
+static XlcConvMethodsRec methods_wcstostr = {
+ close_converter,
+ our_wcstostr,
+ NULL
+};
+
+static XlcConv
+open_wcstostr(
+ XLCd from_lcd,
+ const char *from_type,
+ XLCd to_lcd,
+ const char *to_type)
+{
+ return create_conv(from_lcd, &methods_wcstostr);
+}
+
+/* from XlcNCharSet to XlcNWideChar */
+
+static int
+cstowcs(
+ XlcConv conv,
+ XPointer *from,
+ int *from_left,
+ XPointer *to,
+ int *to_left,
+ XPointer *args,
+ int num_args)
+{
+ XlcCharSet charset;
+ const char *name;
+ Utf8Conv convptr;
+ int i;
+ unsigned char const *src;
+ unsigned char const *srcend;
+ wchar_t *dst;
+ wchar_t *dstend;
+ int unconv_num;
+
+ if (from == NULL || *from == NULL)
+ return 0;
+
+ if (num_args < 1)
+ return -1;
+
+ charset = (XlcCharSet) args[0];
+ name = charset->encoding_name;
+ /* not charset->name because the latter has a ":GL"/":GR" suffix */
+
+ for (convptr = all_charsets, i = all_charsets_count-1; i > 0; convptr++, i--)
+ if (!strcmp(convptr->name, name))
+ break;
+ if (i == 0)
+ return -1;
+
+ src = (unsigned char const *) *from;
+ srcend = src + *from_left;
+ dst = (wchar_t *) *to;
+ dstend = dst + *to_left;
+ unconv_num = 0;
+
+ while (src < srcend && dst < dstend) {
+ unsigned int wc;
+ int consumed;
+
+ consumed = convptr->cstowc(conv, &wc, src, srcend-src);
+ if (consumed == RET_ILSEQ)
+ return -1;
+ if (consumed == RET_TOOFEW(0))
+ break;
+
+ *dst++ = wc;
+ src += consumed;
+ }
+
+ *from = (XPointer) src;
+ *from_left = srcend - src;
+ *to = (XPointer) dst;
+ *to_left = dstend - dst;
+
+ return unconv_num;
+}
+
+static XlcConvMethodsRec methods_cstowcs = {
+ close_converter,
+ cstowcs,
+ NULL
+};
+
+static XlcConv
+open_cstowcs(
+ XLCd from_lcd,
+ const char *from_type,
+ XLCd to_lcd,
+ const char *to_type)
+{
+ lazy_init_all_charsets();
+ return create_conv(from_lcd, &methods_cstowcs);
+}
+
+/* from XlcNWideChar to XlcNCharSet */
+
+static int
+wcstocs(
+ XlcConv conv,
+ XPointer *from,
+ int *from_left,
+ XPointer *to,
+ int *to_left,
+ XPointer *args,
+ int num_args)
+{
+ Utf8Conv *preferred_charsets;
+ XlcCharSet last_charset = NULL;
+ wchar_t const *src;
+ wchar_t const *srcend;
+ unsigned char *dst;
+ unsigned char *dstend;
+ int unconv_num;
+
+ if (from == NULL || *from == NULL)
+ return 0;
+
+ preferred_charsets = (Utf8Conv *) conv->state;
+ src = (wchar_t const *) *from;
+ srcend = src + *from_left;
+ dst = (unsigned char *) *to;
+ dstend = dst + *to_left;
+ unconv_num = 0;
+
+ while (src < srcend && dst < dstend) {
+ Utf8Conv chosen_charset = NULL;
+ XlcSide chosen_side = XlcNONE;
+ wchar_t wc = *src;
+ int count;
+
+ count = charset_wctocs(preferred_charsets, &chosen_charset, &chosen_side, conv, dst, wc, dstend-dst);
+ if (count == RET_TOOSMALL)
+ break;
+ if (count == RET_ILSEQ) {
+ src++;
+ unconv_num++;
+ continue;
+ }
+
+ if (last_charset == NULL) {
+ last_charset =
+ _XlcGetCharSetWithSide(chosen_charset->name, chosen_side);
+ if (last_charset == NULL) {
+ src++;
+ unconv_num++;
+ continue;
+ }
+ } else {
+ if (!(last_charset->xrm_encoding_name == chosen_charset->xrm_name
+ && (last_charset->side == XlcGLGR
+ || last_charset->side == chosen_side)))
+ break;
+ }
+ src++;
+ dst += count;
+ }
+
+ if (last_charset == NULL)
+ return -1;
+
+ *from = (XPointer) src;
+ *from_left = srcend - src;
+ *to = (XPointer) dst;
+ *to_left = dstend - dst;
+
+ if (num_args >= 1)
+ *((XlcCharSet *)args[0]) = last_charset;
+
+ return unconv_num;
+}
+
+static XlcConvMethodsRec methods_wcstocs = {
+ close_tocs_converter,
+ wcstocs,
+ NULL
+};
+
+static XlcConv
+open_wcstocs(
+ XLCd from_lcd,
+ const char *from_type,
+ XLCd to_lcd,
+ const char *to_type)
+{
+ return create_tocs_conv(from_lcd, &methods_wcstocs);
+}
+
+/* from XlcNWideChar to XlcNChar */
+
+static int
+wcstocs1(
+ XlcConv conv,
+ XPointer *from,
+ int *from_left,
+ XPointer *to,
+ int *to_left,
+ XPointer *args,
+ int num_args)
+{
+ Utf8Conv *preferred_charsets;
+ XlcCharSet last_charset = NULL;
+ wchar_t const *src;
+ wchar_t const *srcend;
+ unsigned char *dst;
+ unsigned char *dstend;
+ int unconv_num;
+
+ if (from == NULL || *from == NULL)
+ return 0;
+
+ preferred_charsets = (Utf8Conv *) conv->state;
+ src = (wchar_t const *) *from;
+ srcend = src + *from_left;
+ dst = (unsigned char *) *to;
+ dstend = dst + *to_left;
+ unconv_num = 0;
+
+ while (src < srcend && dst < dstend) {
+ Utf8Conv chosen_charset = NULL;
+ XlcSide chosen_side = XlcNONE;
+ wchar_t wc = *src;
+ int count;
+
+ count = charset_wctocs(preferred_charsets, &chosen_charset, &chosen_side, conv, dst, wc, dstend-dst);
+ if (count == RET_TOOSMALL)
+ break;
+ if (count == RET_ILSEQ) {
+ src++;
+ unconv_num++;
+ continue;
+ }
+
+ if (last_charset == NULL) {
+ last_charset =
+ _XlcGetCharSetWithSide(chosen_charset->name, chosen_side);
+ if (last_charset == NULL) {
+ src++;
+ unconv_num++;
+ continue;
+ }
+ } else {
+ if (!(last_charset->xrm_encoding_name == chosen_charset->xrm_name
+ && (last_charset->side == XlcGLGR
+ || last_charset->side == chosen_side)))
+ break;
+ }
+ src++;
+ dst += count;
+ break;
+ }
+
+ if (last_charset == NULL)
+ return -1;
+
+ *from = (XPointer) src;
+ *from_left = srcend - src;
+ *to = (XPointer) dst;
+ *to_left = dstend - dst;
+
+ if (num_args >= 1)
+ *((XlcCharSet *)args[0]) = last_charset;
+
+ return unconv_num;
+}
+
+static XlcConvMethodsRec methods_wcstocs1 = {
+ close_tocs_converter,
+ wcstocs1,
+ NULL
+};
+
+static XlcConv
+open_wcstocs1(
+ XLCd from_lcd,
+ const char *from_type,
+ XLCd to_lcd,
+ const char *to_type)
+{
+ return create_tocs_conv(from_lcd, &methods_wcstocs1);
+}
+
+/* trivial, no conversion */
+
+static int
+identity(
+ XlcConv conv,
+ XPointer *from,
+ int *from_left,
+ XPointer *to,
+ int *to_left,
+ XPointer *args,
+ int num_args)
+{
+ unsigned char const *src;
+ unsigned char const *srcend;
+ unsigned char *dst;
+ unsigned char *dstend;
+
+ if (from == NULL || *from == NULL)
+ return 0;
+
+ src = (unsigned char const *) *from;
+ srcend = src + *from_left;
+ dst = (unsigned char *) *to;
+ dstend = dst + *to_left;
+
+ while (src < srcend && dst < dstend)
+ *dst++ = *src++;
+
+ *from = (XPointer) src;
+ *from_left = srcend - src;
+ *to = (XPointer) dst;
+ *to_left = dstend - dst;
+
+ return 0;
+}
+
+static XlcConvMethodsRec methods_identity = {
+ close_converter,
+ identity,
+ NULL
+};
+
+static XlcConv
+open_identity(
+ XLCd from_lcd,
+ const char *from_type,
+ XLCd to_lcd,
+ const char *to_type)
+{
+ return create_conv(from_lcd, &methods_identity);
+}
+
+/* from MultiByte/WideChar to FontCharSet. */
+/* They really use converters to CharSet
+ * but with different create_conv procedure. */
+
+static XlcConv
+create_tofontcs_conv(
+ XLCd lcd,
+ XlcConvMethods methods)
+{
+ XlcConv conv;
+ int i, num, k, count;
+ char **value, buf[20];
+ Utf8Conv *preferred;
+
+ lazy_init_all_charsets();
+
+ for (i = 0, num = 0;; i++) {
+ sprintf(buf, "fs%d.charset.name", i);
+ _XlcGetResource(lcd, "XLC_FONTSET", buf, &value, &count);
+ if (count < 1) {
+ sprintf(buf, "fs%d.charset", i);
+ _XlcGetResource(lcd, "XLC_FONTSET", buf, &value, &count);
+ if (count < 1)
+ break;
+ }
+ num += count;
+ }
+
+ conv = (XlcConv) Xmalloc(sizeof(XlcConvRec) + (num + 1) * sizeof(Utf8Conv));
+ if (conv == (XlcConv) NULL)
+ return (XlcConv) NULL;
+ preferred = (Utf8Conv *) ((char *) conv + sizeof(XlcConvRec));
+
+ /* Loop through all fontsets mentioned in the locale. */
+ for (i = 0, num = 0;; i++) {
+ sprintf(buf, "fs%d.charset.name", i);
+ _XlcGetResource(lcd, "XLC_FONTSET", buf, &value, &count);
+ if (count < 1) {
+ sprintf(buf, "fs%d.charset", i);
+ _XlcGetResource(lcd, "XLC_FONTSET", buf, &value, &count);
+ if (count < 1)
+ break;
+ }
+ while (count-- > 0) {
+ XlcCharSet charset = _XlcGetCharSet(*value++);
+ const char *name;
+
+ if (charset == (XlcCharSet) NULL)
+ continue;
+
+ name = charset->encoding_name;
+ /* If it wasn't already encountered... */
+ for (k = num - 1; k >= 0; k--)
+ if (!strcmp(preferred[k]->name, name))
+ break;
+ if (k < 0) {
+ /* For fonts "ISO10646-1" means ucs2, not utf8.*/
+ if (!strcmp("ISO10646-1", name)) {
+ preferred[num++] = &all_charsets[ucs2_conv_index];
+ continue;
+ }
+ /* Look it up in all_charsets[]. */
+ for (k = 0; k < all_charsets_count-1; k++)
+ if (!strcmp(all_charsets[k].name, name)) {
+ /* Add it to the preferred set. */
+ preferred[num++] = &all_charsets[k];
+ break;
+ }
+ }
+ }
+ }
+ preferred[num] = (Utf8Conv) NULL;
+
+ conv->methods = methods;
+ conv->state = (XPointer) preferred;
+
+ return conv;
+}
+
+static XlcConv
+open_wcstofcs(
+ XLCd from_lcd,
+ const char *from_type,
+ XLCd to_lcd,
+ const char *to_type)
+{
+ return create_tofontcs_conv(from_lcd, &methods_wcstocs);
+}
+
+static XlcConv
+open_utf8tofcs(
+ XLCd from_lcd,
+ const char *from_type,
+ XLCd to_lcd,
+ const char *to_type)
+{
+ return create_tofontcs_conv(from_lcd, &methods_utf8tocs);
+}
+
+/* ========================== iconv Stuff ================================ */
+
+/* from XlcNCharSet to XlcNMultiByte */
+
+static int
+iconv_cstombs(XlcConv conv, XPointer *from, int *from_left,
+ XPointer *to, int *to_left, XPointer *args, int num_args)
+{
+ XlcCharSet charset;
+ char const *name;
+ Utf8Conv convptr;
+ int i;
+ unsigned char const *src;
+ unsigned char const *srcend;
+ unsigned char *dst;
+ unsigned char *dstend;
+ int unconv_num;
+
+ if (from == NULL || *from == NULL)
+ return 0;
+
+ if (num_args < 1)
+ return -1;
+
+ charset = (XlcCharSet) args[0];
+ name = charset->encoding_name;
+ /* not charset->name because the latter has a ":GL"/":GR" suffix */
+
+ for (convptr = all_charsets, i = all_charsets_count-1; i > 0; convptr++, i--)
+ if (!strcmp(convptr->name, name))
+ break;
+ if (i == 0)
+ return -1;
+
+ src = (unsigned char const *) *from;
+ srcend = src + *from_left;
+ dst = (unsigned char *) *to;
+ dstend = dst + *to_left;
+ unconv_num = 0;
+
+ while (src < srcend) {
+ ucs4_t wc;
+ int consumed;
+ int count;
+
+ consumed = convptr->cstowc(conv, &wc, src, srcend-src);
+ if (consumed == RET_ILSEQ)
+ return -1;
+ if (consumed == RET_TOOFEW(0))
+ break;
+
+ /* Use stdc iconv to convert widechar -> multibyte */
+
+ count = wctomb((char *)dst, wc);
+ if (count == 0)
+ break;
+ if (count == -1) {
+ count = wctomb((char *)dst, BAD_WCHAR);
+ if (count == 0)
+ break;
+ unconv_num++;
+ }
+ src += consumed;
+ dst += count;
+ }
+
+ *from = (XPointer) src;
+ *from_left = srcend - src;
+ *to = (XPointer) dst;
+ *to_left = dstend - dst;
+
+ return unconv_num;
+
+}
+
+static XlcConvMethodsRec iconv_cstombs_methods = {
+ close_converter,
+ iconv_cstombs,
+ NULL
+};
+
+static XlcConv
+open_iconv_cstombs(XLCd from_lcd, const char *from_type, XLCd to_lcd, const char *to_type)
+{
+ lazy_init_all_charsets();
+ return create_conv(from_lcd, &iconv_cstombs_methods);
+}
+
+static int
+iconv_mbstocs(XlcConv conv, XPointer *from, int *from_left,
+ XPointer *to, int *to_left, XPointer *args, int num_args)
+{
+ Utf8Conv *preferred_charsets;
+ XlcCharSet last_charset = NULL;
+ unsigned char const *src;
+ unsigned char const *srcend;
+ unsigned char *dst;
+ unsigned char *dstend;
+ int unconv_num;
+
+ if (from == NULL || *from == NULL)
+ return 0;
+
+ preferred_charsets = (Utf8Conv *) conv->state;
+ src = (unsigned char const *) *from;
+ srcend = src + *from_left;
+ dst = (unsigned char *) *to;
+ dstend = dst + *to_left;
+ unconv_num = 0;
+
+ while (src < srcend && dst < dstend) {
+ Utf8Conv chosen_charset = NULL;
+ XlcSide chosen_side = XlcNONE;
+ wchar_t wc;
+ int consumed;
+ int count;
+
+ /* Uses stdc iconv to convert multibyte -> widechar */
+
+ consumed = mbtowc(&wc, (const char *)src, srcend-src);
+ if (consumed == 0)
+ break;
+ if (consumed == -1) {
+ src++;
+ unconv_num++;
+ continue;
+ }
+
+ count = charset_wctocs(preferred_charsets, &chosen_charset, &chosen_side, conv, dst, wc, dstend-dst);
+
+ if (count == RET_TOOSMALL)
+ break;
+ if (count == RET_ILSEQ) {
+ src += consumed;
+ unconv_num++;
+ continue;
+ }
+
+ if (last_charset == NULL) {
+ last_charset =
+ _XlcGetCharSetWithSide(chosen_charset->name, chosen_side);
+ if (last_charset == NULL) {
+ src += consumed;
+ unconv_num++;
+ continue;
+ }
+ } else {
+ if (!(last_charset->xrm_encoding_name == chosen_charset->xrm_name
+ && (last_charset->side == XlcGLGR
+ || last_charset->side == chosen_side)))
+ break;
+ }
+ src += consumed;
+ dst += count;
+ }
+
+ if (last_charset == NULL)
+ return -1;
+
+ *from = (XPointer) src;
+ *from_left = srcend - src;
+ *to = (XPointer) dst;
+ *to_left = dstend - dst;
+
+ if (num_args >= 1)
+ *((XlcCharSet *)args[0]) = last_charset;
+
+ return unconv_num;
+}
+
+static XlcConvMethodsRec iconv_mbstocs_methods = {
+ close_tocs_converter,
+ iconv_mbstocs,
+ NULL
+};
+
+static XlcConv
+open_iconv_mbstocs(XLCd from_lcd, const char *from_type, XLCd to_lcd, const char *to_type)
+{
+ return create_tocs_conv(from_lcd, &iconv_mbstocs_methods);
+}
+
+/* from XlcNMultiByte to XlcNChar */
+
+static int
+iconv_mbtocs(XlcConv conv, XPointer *from, int *from_left,
+ XPointer *to, int *to_left, XPointer *args, int num_args)
+{
+ Utf8Conv *preferred_charsets;
+ XlcCharSet last_charset = NULL;
+ unsigned char const *src;
+ unsigned char const *srcend;
+ unsigned char *dst;
+ unsigned char *dstend;
+ int unconv_num;
+
+ if (from == NULL || *from == NULL)
+ return 0;
+
+ preferred_charsets = (Utf8Conv *) conv->state;
+ src = (unsigned char const *) *from;
+ srcend = src + *from_left;
+ dst = (unsigned char *) *to;
+ dstend = dst + *to_left;
+ unconv_num = 0;
+
+ while (src < srcend && dst < dstend) {
+ Utf8Conv chosen_charset = NULL;
+ XlcSide chosen_side = XlcNONE;
+ wchar_t wc;
+ int consumed;
+ int count;
+
+ /* Uses stdc iconv to convert multibyte -> widechar */
+
+ consumed = mbtowc(&wc, (const char *)src, srcend-src);
+ if (consumed == 0)
+ break;
+ if (consumed == -1) {
+ src++;
+ unconv_num++;
+ continue;
+ }
+
+ count = charset_wctocs(preferred_charsets, &chosen_charset, &chosen_side, conv, dst, wc, dstend-dst);
+ if (count == RET_TOOSMALL)
+ break;
+ if (count == RET_ILSEQ) {
+ src += consumed;
+ unconv_num++;
+ continue;
+ }
+
+ if (last_charset == NULL) {
+ last_charset =
+ _XlcGetCharSetWithSide(chosen_charset->name, chosen_side);
+ if (last_charset == NULL) {
+ src += consumed;
+ unconv_num++;
+ continue;
+ }
+ } else {
+ if (!(last_charset->xrm_encoding_name == chosen_charset->xrm_name
+ && (last_charset->side == XlcGLGR
+ || last_charset->side == chosen_side)))
+ break;
+ }
+ src += consumed;
+ dst += count;
+ }
+
+ if (last_charset == NULL)
+ return -1;
+
+ *from = (XPointer) src;
+ *from_left = srcend - src;
+ *to = (XPointer) dst;
+ *to_left = dstend - dst;
+
+ if (num_args >= 1)
+ *((XlcCharSet *)args[0]) = last_charset;
+
+ return unconv_num;
+}
+
+static XlcConvMethodsRec iconv_mbtocs_methods = {
+ close_tocs_converter,
+ iconv_mbtocs,
+ NULL
+};
+
+static XlcConv
+open_iconv_mbtocs(XLCd from_lcd, const char *from_type, XLCd to_lcd, const char *to_type)
+{
+ return create_tocs_conv(from_lcd, &iconv_mbtocs_methods );
+}
+
+/* from XlcNMultiByte to XlcNString */
+
+static int
+iconv_mbstostr(XlcConv conv, XPointer *from, int *from_left,
+ XPointer *to, int *to_left, XPointer *args, int num_args)
+{
+ unsigned char const *src;
+ unsigned char const *srcend;
+ unsigned char *dst;
+ unsigned char *dstend;
+ int unconv_num;
+
+ if (from == NULL || *from == NULL)
+ return 0;
+
+ src = (unsigned char const *) *from;
+ srcend = src + *from_left;
+ dst = (unsigned char *) *to;
+ dstend = dst + *to_left;
+ unconv_num = 0;
+
+ while (src < srcend) {
+ unsigned char c;
+ wchar_t wc;
+ int consumed;
+
+ /* Uses stdc iconv to convert multibyte -> widechar */
+
+ consumed = mbtowc(&wc, (const char *)src, srcend-src);
+ if (consumed == 0)
+ break;
+ if (dst == dstend)
+ break;
+ if (consumed == -1) {
+ consumed = 1;
+ c = BAD_CHAR;
+ unconv_num++;
+ } else {
+ if ((wc & ~(wchar_t)0xff) != 0) {
+ c = BAD_CHAR;
+ unconv_num++;
+ } else
+ c = (unsigned char) wc;
+ }
+ *dst++ = c;
+ src += consumed;
+ }
+
+ *from = (XPointer) src;
+ *from_left = srcend - src;
+ *to = (XPointer) dst;
+ *to_left = dstend - dst;
+
+ return unconv_num;
+}
+
+static XlcConvMethodsRec iconv_mbstostr_methods = {
+ close_converter,
+ iconv_mbstostr,
+ NULL
+};
+
+static XlcConv
+open_iconv_mbstostr(XLCd from_lcd, const char *from_type, XLCd to_lcd, const char *to_type)
+{
+ return create_conv(from_lcd, &iconv_mbstostr_methods);
+}
+
+/* from XlcNString to XlcNMultiByte */
+static int
+iconv_strtombs(XlcConv conv, XPointer *from, int *from_left,
+ XPointer *to, int *to_left, XPointer *args, int num_args)
+{
+ unsigned char const *src;
+ unsigned char const *srcend;
+ unsigned char *dst;
+ unsigned char *dstend;
+
+ if (from == NULL || *from == NULL)
+ return 0;
+
+ src = (unsigned char const *) *from;
+ srcend = src + *from_left;
+ dst = (unsigned char *) *to;
+ dstend = dst + *to_left;
+
+ while (src < srcend) {
+ int count = wctomb((char *)dst, *src);
+ if (count < 0)
+ break;
+ dst += count;
+ src++;
+ }
+
+ *from = (XPointer) src;
+ *from_left = srcend - src;
+ *to = (XPointer) dst;
+ *to_left = dstend - dst;
+
+ return 0;
+}
+
+static XlcConvMethodsRec iconv_strtombs_methods= {
+ close_converter,
+ iconv_strtombs,
+ NULL
+};
+
+static XlcConv
+open_iconv_strtombs(XLCd from_lcd, const char *from_type, XLCd to_lcd, const char *to_type)
+{
+ return create_conv(from_lcd, &iconv_strtombs_methods);
+}
+
+/***************************************************************************/
+/* Part II: An iconv locale loader.
+ *
+ *Here we can assume that "multi-byte" is iconv and that `wchar_t' is Unicode.
+ */
+
+/* from XlcNMultiByte to XlcNWideChar */
+static int
+iconv_mbstowcs(XlcConv conv, XPointer *from, int *from_left,
+ XPointer *to, int *to_left, XPointer *args, int num_args)
+{
+ char *src = *((char **) from);
+ wchar_t *dst = *((wchar_t **) to);
+ int src_left = *from_left;
+ int dst_left = *to_left;
+ int length, unconv_num = 0;
+
+ while (src_left > 0 && dst_left > 0) {
+ length = mbtowc(dst, src, src_left);
+
+ if (length > 0) {
+ src += length;
+ src_left -= length;
+ if (dst)
+ dst++;
+ dst_left--;
+ } else if (length < 0) {
+ src++;
+ src_left--;
+ unconv_num++;
+ } else {
+ /* null ? */
+ src++;
+ src_left--;
+ if (dst)
+ *dst++ = L'\0';
+ dst_left--;
+ }
+ }
+
+ *from = (XPointer) src;
+ if (dst)
+ *to = (XPointer) dst;
+ *from_left = src_left;
+ *to_left = dst_left;
+
+ return unconv_num;
+}
+
+static XlcConvMethodsRec iconv_mbstowcs_methods = {
+ close_converter,
+ iconv_mbstowcs,
+ NULL
+} ;
+
+static XlcConv
+open_iconv_mbstowcs(XLCd from_lcd, const char *from_type, XLCd to_lcd, const char *to_type)
+{
+ return create_conv(from_lcd, &iconv_mbstowcs_methods);
+}
+
+static int
+iconv_wcstombs(XlcConv conv, XPointer *from, int *from_left,
+ XPointer *to, int *to_left, XPointer *args, int num_args)
+{
+ wchar_t *src = *((wchar_t **) from);
+ char *dst = *((char **) to);
+ int src_left = *from_left;
+ int dst_left = *to_left;
+ int length, unconv_num = 0;
+
+ while (src_left > 0 && dst_left >= MB_CUR_MAX) {
+ length = wctomb(dst, *src); /* XXX */
+
+ if (length > 0) {
+ src++;
+ src_left--;
+ if (dst)
+ dst += length;
+ dst_left -= length;
+ } else if (length < 0) {
+ src++;
+ src_left--;
+ unconv_num++;
+ }
+ }
+
+ *from = (XPointer) src;
+ if (dst)
+ *to = (XPointer) dst;
+ *from_left = src_left;
+ *to_left = dst_left;
+
+ return unconv_num;
+}
+
+static XlcConvMethodsRec iconv_wcstombs_methods = {
+ close_converter,
+ iconv_wcstombs,
+ NULL
+} ;
+
+static XlcConv
+open_iconv_wcstombs(XLCd from_lcd, const char *from_type, XLCd to_lcd, const char *to_type)
+{
+ return create_conv(from_lcd, &iconv_wcstombs_methods);
+}
+
+static XlcConv
+open_iconv_mbstofcs(
+ XLCd from_lcd,
+ const char *from_type,
+ XLCd to_lcd,
+ const char *to_type)
+{
+ return create_tofontcs_conv(from_lcd, &iconv_mbstocs_methods);
+}
+
+/* Registers UTF-8 converters for a UTF-8 locale. */
+
+void
+_XlcAddUtf8LocaleConverters(
+ XLCd lcd)
+{
+ /* Register elementary converters. */
+
+ _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNWideChar, open_utf8towcs);
+
+ _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNMultiByte, open_wcstoutf8);
+ _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNString, open_wcstostr);
+
+ _XlcSetConverter(lcd, XlcNString, lcd, XlcNWideChar, open_strtowcs);
+
+ /* Register converters for XlcNCharSet. This implicitly provides
+ * converters from and to XlcNCompoundText. */
+
+ _XlcSetConverter(lcd, XlcNCharSet, lcd, XlcNMultiByte, open_cstoutf8);
+ _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNCharSet, open_utf8tocs);
+ _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNChar, open_utf8tocs1);
+
+ _XlcSetConverter(lcd, XlcNCharSet, lcd, XlcNWideChar, open_cstowcs);
+ _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNCharSet, open_wcstocs);
+ _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNChar, open_wcstocs1);
+
+ _XlcSetConverter(lcd, XlcNString, lcd, XlcNMultiByte, open_strtoutf8);
+ _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNString, open_utf8tostr);
+ _XlcSetConverter(lcd, XlcNUtf8String, lcd, XlcNMultiByte, open_identity);
+ _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNUtf8String, open_identity);
+
+ /* Register converters for XlcNFontCharSet */
+ _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNFontCharSet, open_utf8tofcs);
+ _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNFontCharSet, open_wcstofcs);
+}
+
+void
+_XlcAddGB18030LocaleConverters(
+ XLCd lcd)
+{
+
+ /* Register elementary converters. */
+ _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNWideChar, open_iconv_mbstowcs);
+ _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNMultiByte, open_iconv_wcstombs);
+
+ /* Register converters for XlcNCharSet. This implicitly provides
+ * converters from and to XlcNCompoundText. */
+
+ _XlcSetConverter(lcd, XlcNCharSet, lcd, XlcNMultiByte, open_iconv_cstombs);
+ _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNCharSet, open_iconv_mbstocs);
+ _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNChar, open_iconv_mbtocs);
+ _XlcSetConverter(lcd, XlcNString, lcd, XlcNMultiByte, open_iconv_strtombs);
+ _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNString, open_iconv_mbstostr);
+
+ /* Register converters for XlcNFontCharSet */
+ _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNFontCharSet, open_iconv_mbstofcs);
+
+ _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNString, open_wcstostr);
+ _XlcSetConverter(lcd, XlcNString, lcd, XlcNWideChar, open_strtowcs);
+ _XlcSetConverter(lcd, XlcNCharSet, lcd, XlcNWideChar, open_cstowcs);
+ _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNCharSet, open_wcstocs);
+ _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNChar, open_wcstocs1);
+
+ /* Register converters for XlcNFontCharSet */
+ _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNFontCharSet, open_wcstofcs);
+}
|