lcUTF8.c revision 61b2299d
11ab64890Smrg/* $TOG:  $ */
21ab64890Smrg/******************************************************************
31ab64890Smrg
41ab64890Smrg              Copyright 1993 by SunSoft, Inc.
51ab64890Smrg              Copyright 1999-2000 by Bruno Haible
61ab64890Smrg
71ab64890SmrgPermission to use, copy, modify, distribute, and sell this software
81ab64890Smrgand its documentation for any purpose is hereby granted without fee,
91ab64890Smrgprovided that the above copyright notice appear in all copies and
101ab64890Smrgthat both that copyright notice and this permission notice appear
111ab64890Smrgin supporting documentation, and that the names of SunSoft, Inc. and
121ab64890SmrgBruno Haible not be used in advertising or publicity pertaining to
131ab64890Smrgdistribution of the software without specific, written prior
141ab64890Smrgpermission.  SunSoft, Inc. and Bruno Haible make no representations
151ab64890Smrgabout the suitability of this software for any purpose.  It is
161ab64890Smrgprovided "as is" without express or implied warranty.
171ab64890Smrg
181ab64890SmrgSunSoft Inc. AND Bruno Haible DISCLAIM ALL WARRANTIES WITH REGARD
191ab64890SmrgTO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
201ab64890SmrgAND FITNESS, IN NO EVENT SHALL SunSoft, Inc. OR Bruno Haible BE LIABLE
211ab64890SmrgFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
221ab64890SmrgWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
231ab64890SmrgACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
241ab64890SmrgOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
251ab64890Smrg
261ab64890Smrg******************************************************************/
271ab64890Smrg/* $XFree86: xc/lib/X11/lcUTF8.c,v 1.15 2002/10/08 23:31:36 dawes Exp $ */
281ab64890Smrg
291ab64890Smrg/*
301ab64890Smrg * This file contains:
311ab64890Smrg *
321ab64890Smrg * I. Conversion routines CompoundText/CharSet <--> Unicode/UTF-8.
331ab64890Smrg *
341ab64890Smrg *    Used for three purposes:
351ab64890Smrg *      1. The UTF-8 locales, see below.
361ab64890Smrg *      2. Unicode aware applications for which the use of 8-bit character
371ab64890Smrg *         sets is an anachronism.
381ab64890Smrg *      3. For conversion from keysym to locale encoding.
391ab64890Smrg *
401ab64890Smrg * II. Conversion files for an UTF-8 locale loader.
411ab64890Smrg *     Supports: all locales with codeset UTF-8.
421ab64890Smrg *     How: Provides converters for UTF-8.
431ab64890Smrg *     Platforms: all systems.
441ab64890Smrg *
451ab64890Smrg * The loader itself is located in lcUTF8.c.
461ab64890Smrg */
471ab64890Smrg
481ab64890Smrg/*
491ab64890Smrg * The conversion from UTF-8 to CompoundText is realized in a very
501ab64890Smrg * conservative way. Recall that CompoundText data is used for inter-client
511ab64890Smrg * communication purposes. We distinguish three classes of clients:
521ab64890Smrg * - Clients which accept only those pieces of CompoundText which belong to
531ab64890Smrg *   the character set understood by the current locale.
541ab64890Smrg *   (Example: clients which are linked to an older X11 library.)
551ab64890Smrg * - Clients which accept CompoundText with multiple character sets and parse
561ab64890Smrg *   it themselves.
571ab64890Smrg *   (Example: emacs, xemacs.)
581ab64890Smrg * - Clients which rely entirely on the X{mb,wc}TextPropertyToTextList
591ab64890Smrg *   functions for the conversion of CompoundText to their current locale's
601ab64890Smrg *   multi-byte/wide-character format.
611ab64890Smrg * For best interoperation, the UTF-8 to CompoundText conversion proceeds as
621ab64890Smrg * follows. For every character, it first tests whether the character is
631ab64890Smrg * representable in the current locale's original (non-UTF-8) character set.
641ab64890Smrg * If not, it goes through the list of predefined character sets for
651ab64890Smrg * CompoundText and tests if the character is representable in that character
661ab64890Smrg * set. If so, it encodes the character using its code within that character
671ab64890Smrg * set. If not, it uses an UTF-8-in-CompoundText encapsulation. Since
681ab64890Smrg * clients of the first and second kind ignore such encapsulated text,
691ab64890Smrg * this encapsulation is kept to a minimum and terminated as early as possible.
701ab64890Smrg *
711ab64890Smrg * In a distant future, when clients of the first and second kind will have
721ab64890Smrg * disappeared, we will be able to stuff UTF-8 data directly in CompoundText
731ab64890Smrg * without first going through the list of predefined character sets.
741ab64890Smrg */
751ab64890Smrg
761ab64890Smrg#ifdef HAVE_CONFIG_H
771ab64890Smrg#include <config.h>
781ab64890Smrg#endif
791ab64890Smrg#include <stdio.h>
801ab64890Smrg#include "Xlibint.h"
811ab64890Smrg#include "XlcPubI.h"
821ab64890Smrg#include "XlcGeneric.h"
831ab64890Smrg
841ab64890Smrgstatic XlcConv
851ab64890Smrgcreate_conv(
861ab64890Smrg    XLCd lcd,
871ab64890Smrg    XlcConvMethods methods)
881ab64890Smrg{
891ab64890Smrg    XlcConv conv;
901ab64890Smrg
911ab64890Smrg    conv = (XlcConv) Xmalloc(sizeof(XlcConvRec));
921ab64890Smrg    if (conv == (XlcConv) NULL)
931ab64890Smrg	return (XlcConv) NULL;
941ab64890Smrg
951ab64890Smrg    conv->methods = methods;
961ab64890Smrg    conv->state = NULL;
971ab64890Smrg
981ab64890Smrg    return conv;
991ab64890Smrg}
1001ab64890Smrg
1011ab64890Smrgstatic void
1021ab64890Smrgclose_converter(
1031ab64890Smrg    XlcConv conv)
1041ab64890Smrg{
1051ab64890Smrg    Xfree((char *) conv);
1061ab64890Smrg}
1071ab64890Smrg
1081ab64890Smrg/* Replacement character for invalid multibyte sequence or wide character. */
1091ab64890Smrg#define BAD_WCHAR ((ucs4_t) 0xfffd)
1101ab64890Smrg#define BAD_CHAR '?'
1111ab64890Smrg
1121ab64890Smrg/***************************************************************************/
1131ab64890Smrg/* Part I: Conversion routines CompoundText/CharSet <--> Unicode/UTF-8.
1141ab64890Smrg *
1151ab64890Smrg * Note that this code works in any locale. We store Unicode values in
1161ab64890Smrg * `ucs4_t' variables, but don't pass them to the user.
1171ab64890Smrg *
1181ab64890Smrg * This code has to support all character sets that are used for CompoundText,
1191ab64890Smrg * nothing more, nothing less. See the table in lcCT.c.
1201ab64890Smrg * Since the conversion _to_ CompoundText is likely to need the tables for all
1211ab64890Smrg * character sets at once, we don't use dynamic loading (of tables or shared
1221ab64890Smrg * libraries through iconv()). Use a fixed set of tables instead.
1231ab64890Smrg *
1241ab64890Smrg * We use statically computed tables, not dynamically allocated arrays,
1251ab64890Smrg * because it's more memory efficient: Different processes using the same
1261ab64890Smrg * libX11 shared library share the "text" and read-only "data" sections.
1271ab64890Smrg */
1281ab64890Smrg
1291ab64890Smrgtypedef unsigned int ucs4_t;
1301ab64890Smrg#define conv_t XlcConv
1311ab64890Smrg
1321ab64890Smrgtypedef struct _Utf8ConvRec {
1331ab64890Smrg    const char *name;
1341ab64890Smrg    XrmQuark xrm_name;
1351ab64890Smrg    int (* cstowc) (XlcConv, ucs4_t *, unsigned char const *, int);
1361ab64890Smrg    int (* wctocs) (XlcConv, unsigned char *, ucs4_t, int);
1371ab64890Smrg} Utf8ConvRec, *Utf8Conv;
1381ab64890Smrg
1391ab64890Smrg/*
1401ab64890Smrg * int xxx_cstowc (XlcConv conv, ucs4_t *pwc, unsigned char const *s, int n)
1411ab64890Smrg * converts the byte sequence starting at s to a wide character. Up to n bytes
1421ab64890Smrg * are available at s. n is >= 1.
1431ab64890Smrg * Result is number of bytes consumed (if a wide character was read),
1441ab64890Smrg * or 0 if invalid, or -1 if n too small.
1451ab64890Smrg *
1461ab64890Smrg * int xxx_wctocs (XlcConv conv, unsigned char *r, ucs4_t wc, int n)
1471ab64890Smrg * converts the wide character wc to the character set xxx, and stores the
1481ab64890Smrg * result beginning at r. Up to n bytes may be written at r. n is >= 1.
1491ab64890Smrg * Result is number of bytes written, or 0 if invalid, or -1 if n too small.
1501ab64890Smrg */
1511ab64890Smrg
1521ab64890Smrg/* Return code if invalid. (xxx_mbtowc, xxx_wctomb) */
1531ab64890Smrg#define RET_ILSEQ      0
1541ab64890Smrg/* Return code if only a shift sequence of n bytes was read. (xxx_mbtowc) */
1551ab64890Smrg#define RET_TOOFEW(n)  (-1-(n))
1561ab64890Smrg/* Return code if output buffer is too small. (xxx_wctomb, xxx_reset) */
1571ab64890Smrg#define RET_TOOSMALL   -1
1581ab64890Smrg
1591ab64890Smrg/*
1601ab64890Smrg * The tables below are bijective. It would be possible to extend the
1611ab64890Smrg * xxx_wctocs tables to do some transliteration (e.g. U+201C,U+201D -> 0x22)
1621ab64890Smrg * but *only* with characters not contained in any other table, and *only*
1631ab64890Smrg * when the current locale is not an UTF-8 locale.
1641ab64890Smrg */
1651ab64890Smrg
1661ab64890Smrg#include "lcUniConv/utf8.h"
1671ab64890Smrg#include "lcUniConv/ucs2be.h"
1681ab64890Smrg#ifdef notused
1691ab64890Smrg#include "lcUniConv/ascii.h"
1701ab64890Smrg#endif
1711ab64890Smrg#include "lcUniConv/iso8859_1.h"
1721ab64890Smrg#include "lcUniConv/iso8859_2.h"
1731ab64890Smrg#include "lcUniConv/iso8859_3.h"
1741ab64890Smrg#include "lcUniConv/iso8859_4.h"
1751ab64890Smrg#include "lcUniConv/iso8859_5.h"
1761ab64890Smrg#include "lcUniConv/iso8859_6.h"
1771ab64890Smrg#include "lcUniConv/iso8859_7.h"
1781ab64890Smrg#include "lcUniConv/iso8859_8.h"
1791ab64890Smrg#include "lcUniConv/iso8859_9.h"
1801ab64890Smrg#include "lcUniConv/iso8859_10.h"
1811ab64890Smrg#include "lcUniConv/iso8859_11.h"
1821ab64890Smrg#include "lcUniConv/iso8859_13.h"
1831ab64890Smrg#include "lcUniConv/iso8859_14.h"
1841ab64890Smrg#include "lcUniConv/iso8859_15.h"
1851ab64890Smrg#include "lcUniConv/iso8859_16.h"
1861ab64890Smrg#include "lcUniConv/iso8859_9e.h"
1871ab64890Smrg#include "lcUniConv/jisx0201.h"
1881ab64890Smrg#include "lcUniConv/tis620.h"
1891ab64890Smrg#include "lcUniConv/koi8_r.h"
1901ab64890Smrg#include "lcUniConv/koi8_u.h"
1911ab64890Smrg#include "lcUniConv/koi8_c.h"
1921ab64890Smrg#include "lcUniConv/armscii_8.h"
1931ab64890Smrg#include "lcUniConv/cp1133.h"
1941ab64890Smrg#include "lcUniConv/mulelao.h"
1951ab64890Smrg#include "lcUniConv/viscii.h"
1961ab64890Smrg#include "lcUniConv/tcvn.h"
1971ab64890Smrg#include "lcUniConv/georgian_academy.h"
1981ab64890Smrg#include "lcUniConv/georgian_ps.h"
1991ab64890Smrg#include "lcUniConv/cp1251.h"
2001ab64890Smrg#include "lcUniConv/cp1255.h"
2011ab64890Smrg#include "lcUniConv/cp1256.h"
2021ab64890Smrg#include "lcUniConv/tatar_cyr.h"
2031ab64890Smrg
2041ab64890Smrgtypedef struct {
2051ab64890Smrg    unsigned short indx; /* index into big table */
2061ab64890Smrg    unsigned short used; /* bitmask of used entries */
2071ab64890Smrg} Summary16;
2081ab64890Smrg
2091ab64890Smrg#include "lcUniConv/gb2312.h"
2101ab64890Smrg#include "lcUniConv/jisx0208.h"
2111ab64890Smrg#include "lcUniConv/jisx0212.h"
2121ab64890Smrg#include "lcUniConv/ksc5601.h"
2131ab64890Smrg#include "lcUniConv/big5.h"
2141ab64890Smrg#include "lcUniConv/big5_emacs.h"
21561b2299dSmrg#include "lcUniConv/big5hkscs.h"
21661b2299dSmrg#include "lcUniConv/gbk.h"
2171ab64890Smrg
2181ab64890Smrgstatic Utf8ConvRec all_charsets[] = {
2191ab64890Smrg    /* The ISO10646-1/UTF-8 entry occurs twice, once at the beginning
2201ab64890Smrg       (for lookup speed), once at the end (as a fallback).  */
2211ab64890Smrg    { "ISO10646-1", NULLQUARK,
2221ab64890Smrg	utf8_mbtowc, utf8_wctomb
2231ab64890Smrg    },
2241ab64890Smrg
2251ab64890Smrg    { "ISO8859-1", NULLQUARK,
2261ab64890Smrg	iso8859_1_mbtowc, iso8859_1_wctomb
2271ab64890Smrg    },
2281ab64890Smrg    { "ISO8859-2", NULLQUARK,
2291ab64890Smrg	iso8859_2_mbtowc, iso8859_2_wctomb
2301ab64890Smrg    },
2311ab64890Smrg    { "ISO8859-3", NULLQUARK,
2321ab64890Smrg	iso8859_3_mbtowc, iso8859_3_wctomb
2331ab64890Smrg    },
2341ab64890Smrg    { "ISO8859-4", NULLQUARK,
2351ab64890Smrg	iso8859_4_mbtowc, iso8859_4_wctomb
2361ab64890Smrg    },
2371ab64890Smrg    { "ISO8859-5", NULLQUARK,
2381ab64890Smrg	iso8859_5_mbtowc, iso8859_5_wctomb
2391ab64890Smrg    },
2401ab64890Smrg    { "ISO8859-6", NULLQUARK,
2411ab64890Smrg	iso8859_6_mbtowc, iso8859_6_wctomb
2421ab64890Smrg    },
2431ab64890Smrg    { "ISO8859-7", NULLQUARK,
2441ab64890Smrg	iso8859_7_mbtowc, iso8859_7_wctomb
2451ab64890Smrg    },
2461ab64890Smrg    { "ISO8859-8", NULLQUARK,
2471ab64890Smrg	iso8859_8_mbtowc, iso8859_8_wctomb
2481ab64890Smrg    },
2491ab64890Smrg    { "ISO8859-9", NULLQUARK,
2501ab64890Smrg	iso8859_9_mbtowc, iso8859_9_wctomb
2511ab64890Smrg    },
2521ab64890Smrg    { "ISO8859-10", NULLQUARK,
2531ab64890Smrg	iso8859_10_mbtowc, iso8859_10_wctomb
2541ab64890Smrg    },
2551ab64890Smrg    { "ISO8859-11", NULLQUARK,
2561ab64890Smrg	iso8859_11_mbtowc, iso8859_11_wctomb
2571ab64890Smrg    },
2581ab64890Smrg    { "ISO8859-13", NULLQUARK,
2591ab64890Smrg	iso8859_13_mbtowc, iso8859_13_wctomb
2601ab64890Smrg    },
2611ab64890Smrg    { "ISO8859-14", NULLQUARK,
2621ab64890Smrg	iso8859_14_mbtowc, iso8859_14_wctomb
2631ab64890Smrg    },
2641ab64890Smrg    { "ISO8859-15", NULLQUARK,
2651ab64890Smrg	iso8859_15_mbtowc, iso8859_15_wctomb
2661ab64890Smrg    },
2671ab64890Smrg    { "ISO8859-16", NULLQUARK,
2681ab64890Smrg	iso8859_16_mbtowc, iso8859_16_wctomb
2691ab64890Smrg    },
2701ab64890Smrg    { "JISX0201.1976-0", NULLQUARK,
2711ab64890Smrg	jisx0201_mbtowc, jisx0201_wctomb
2721ab64890Smrg    },
2731ab64890Smrg    { "TIS620-0", NULLQUARK,
2741ab64890Smrg	tis620_mbtowc, tis620_wctomb
2751ab64890Smrg    },
2761ab64890Smrg    { "GB2312.1980-0", NULLQUARK,
2771ab64890Smrg	gb2312_mbtowc, gb2312_wctomb
2781ab64890Smrg    },
2791ab64890Smrg    { "JISX0208.1983-0", NULLQUARK,
2801ab64890Smrg	jisx0208_mbtowc, jisx0208_wctomb
2811ab64890Smrg    },
2821ab64890Smrg    { "JISX0208.1990-0", NULLQUARK,
2831ab64890Smrg	jisx0208_mbtowc, jisx0208_wctomb
2841ab64890Smrg    },
2851ab64890Smrg    { "JISX0212.1990-0", NULLQUARK,
2861ab64890Smrg	jisx0212_mbtowc, jisx0212_wctomb
2871ab64890Smrg    },
2881ab64890Smrg    { "KSC5601.1987-0", NULLQUARK,
2891ab64890Smrg	ksc5601_mbtowc, ksc5601_wctomb
2901ab64890Smrg    },
2911ab64890Smrg    { "KOI8-R", NULLQUARK,
2921ab64890Smrg	koi8_r_mbtowc, koi8_r_wctomb
2931ab64890Smrg    },
2941ab64890Smrg    { "KOI8-U", NULLQUARK,
2951ab64890Smrg	koi8_u_mbtowc, koi8_u_wctomb
2961ab64890Smrg    },
2971ab64890Smrg    { "KOI8-C", NULLQUARK,
2981ab64890Smrg	koi8_c_mbtowc, koi8_c_wctomb
2991ab64890Smrg    },
3001ab64890Smrg    { "TATAR-CYR", NULLQUARK,
3011ab64890Smrg	tatar_cyr_mbtowc, tatar_cyr_wctomb
3021ab64890Smrg    },
3031ab64890Smrg    { "ARMSCII-8", NULLQUARK,
3041ab64890Smrg	armscii_8_mbtowc, armscii_8_wctomb
3051ab64890Smrg    },
3061ab64890Smrg    { "IBM-CP1133", NULLQUARK,
3071ab64890Smrg	cp1133_mbtowc, cp1133_wctomb
3081ab64890Smrg    },
3091ab64890Smrg    { "MULELAO-1", NULLQUARK,
3101ab64890Smrg	mulelao_mbtowc, mulelao_wctomb
3111ab64890Smrg    },
3121ab64890Smrg    { "VISCII1.1-1", NULLQUARK,
3131ab64890Smrg	viscii_mbtowc, viscii_wctomb
3141ab64890Smrg    },
3151ab64890Smrg    { "TCVN-5712", NULLQUARK,
3161ab64890Smrg	tcvn_mbtowc, tcvn_wctomb
3171ab64890Smrg    },
3181ab64890Smrg    { "GEORGIAN-ACADEMY", NULLQUARK,
3191ab64890Smrg	georgian_academy_mbtowc, georgian_academy_wctomb
3201ab64890Smrg    },
3211ab64890Smrg    { "GEORGIAN-PS", NULLQUARK,
3221ab64890Smrg	georgian_ps_mbtowc, georgian_ps_wctomb
3231ab64890Smrg    },
3241ab64890Smrg    { "ISO8859-9E", NULLQUARK,
3251ab64890Smrg	iso8859_9e_mbtowc, iso8859_9e_wctomb
3261ab64890Smrg    },
3271ab64890Smrg    { "MICROSOFT-CP1251", NULLQUARK,
3281ab64890Smrg	cp1251_mbtowc, cp1251_wctomb
3291ab64890Smrg    },
3301ab64890Smrg    { "MICROSOFT-CP1255", NULLQUARK,
3311ab64890Smrg	cp1255_mbtowc, cp1255_wctomb
3321ab64890Smrg    },
3331ab64890Smrg    { "MICROSOFT-CP1256", NULLQUARK,
3341ab64890Smrg	cp1256_mbtowc, cp1256_wctomb
3351ab64890Smrg    },
3361ab64890Smrg    { "BIG5-0", NULLQUARK,
33761b2299dSmrg	big5_mbtowc, big5_wctomb
33861b2299dSmrg    },
3391ab64890Smrg    { "BIG5-E0", NULLQUARK,
3401ab64890Smrg	big5_0_mbtowc, big5_0_wctomb
3411ab64890Smrg    },
3421ab64890Smrg    { "BIG5-E1", NULLQUARK,
3431ab64890Smrg	big5_1_mbtowc, big5_1_wctomb
3441ab64890Smrg    },
34561b2299dSmrg    { "GBK-0", NULLQUARK,
34661b2299dSmrg	gbk_mbtowc, gbk_wctomb
34761b2299dSmrg    },
34861b2299dSmrg    { "BIG5HKSCS-0", NULLQUARK,
34961b2299dSmrg	big5hkscs_mbtowc, big5hkscs_wctomb
35061b2299dSmrg    },
3511ab64890Smrg
3521ab64890Smrg    /* The ISO10646-1/UTF-8 entry occurs twice, once at the beginning
3531ab64890Smrg       (for lookup speed), once at the end (as a fallback).  */
3541ab64890Smrg    { "ISO10646-1", NULLQUARK,
3551ab64890Smrg	utf8_mbtowc, utf8_wctomb
3561ab64890Smrg    },
3571ab64890Smrg
3581ab64890Smrg    /* Encoding ISO10646-1 for fonts means UCS2-like encoding
3591ab64890Smrg       so for conversion to FontCharSet we need this record */
3601ab64890Smrg    { "ISO10646-1", NULLQUARK,
3611ab64890Smrg	ucs2be_mbtowc, ucs2be_wctomb
3621ab64890Smrg    }
3631ab64890Smrg};
3641ab64890Smrg
3651ab64890Smrg#define charsets_table_size (sizeof(all_charsets)/sizeof(all_charsets[0]))
3661ab64890Smrg#define all_charsets_count  (charsets_table_size - 1)
3671ab64890Smrg#define ucs2_conv_index     (charsets_table_size - 1)
3681ab64890Smrg
3691ab64890Smrgstatic void
3701ab64890Smrginit_all_charsets (void)
3711ab64890Smrg{
3721ab64890Smrg    Utf8Conv convptr;
3731ab64890Smrg    int i;
3741ab64890Smrg
3751ab64890Smrg    for (convptr = all_charsets, i = charsets_table_size; i > 0; convptr++, i--)
3761ab64890Smrg	convptr->xrm_name = XrmStringToQuark(convptr->name);
3771ab64890Smrg}
3781ab64890Smrg
3791ab64890Smrg#define lazy_init_all_charsets()					\
3801ab64890Smrg    do {								\
3811ab64890Smrg	if (all_charsets[0].xrm_name == NULLQUARK)			\
3821ab64890Smrg	    init_all_charsets();					\
3831ab64890Smrg    } while (0)
3841ab64890Smrg
3851ab64890Smrg/* from XlcNCharSet to XlcNUtf8String */
3861ab64890Smrg
3871ab64890Smrgstatic int
3881ab64890Smrgcstoutf8(
3891ab64890Smrg    XlcConv conv,
3901ab64890Smrg    XPointer *from,
3911ab64890Smrg    int *from_left,
3921ab64890Smrg    XPointer *to,
3931ab64890Smrg    int *to_left,
3941ab64890Smrg    XPointer *args,
3951ab64890Smrg    int num_args)
3961ab64890Smrg{
3971ab64890Smrg    XlcCharSet charset;
3981ab64890Smrg    const char *name;
3991ab64890Smrg    Utf8Conv convptr;
4001ab64890Smrg    int i;
4011ab64890Smrg    unsigned char const *src;
4021ab64890Smrg    unsigned char const *srcend;
4031ab64890Smrg    unsigned char *dst;
4041ab64890Smrg    unsigned char *dstend;
4051ab64890Smrg    int unconv_num;
4061ab64890Smrg
4071ab64890Smrg    if (from == NULL || *from == NULL)
4081ab64890Smrg	return 0;
4091ab64890Smrg
4101ab64890Smrg    if (num_args < 1)
4111ab64890Smrg	return -1;
4121ab64890Smrg
4131ab64890Smrg    charset = (XlcCharSet) args[0];
4141ab64890Smrg    name = charset->encoding_name;
4151ab64890Smrg    /* not charset->name because the latter has a ":GL"/":GR" suffix */
4161ab64890Smrg
4171ab64890Smrg    for (convptr = all_charsets, i = all_charsets_count-1; i > 0; convptr++, i--)
4181ab64890Smrg	if (!strcmp(convptr->name, name))
4191ab64890Smrg	    break;
4201ab64890Smrg    if (i == 0)
4211ab64890Smrg	return -1;
4221ab64890Smrg
4231ab64890Smrg    src = (unsigned char const *) *from;
4241ab64890Smrg    srcend = src + *from_left;
4251ab64890Smrg    dst = (unsigned char *) *to;
4261ab64890Smrg    dstend = dst + *to_left;
4271ab64890Smrg    unconv_num = 0;
4281ab64890Smrg
4291ab64890Smrg    while (src < srcend) {
4301ab64890Smrg	ucs4_t wc;
4311ab64890Smrg	int consumed;
4321ab64890Smrg	int count;
4331ab64890Smrg
4341ab64890Smrg	consumed = convptr->cstowc(conv, &wc, src, srcend-src);
4351ab64890Smrg	if (consumed == RET_ILSEQ)
4361ab64890Smrg	    return -1;
4371ab64890Smrg	if (consumed == RET_TOOFEW(0))
4381ab64890Smrg	    break;
4391ab64890Smrg
4401ab64890Smrg	count = utf8_wctomb(NULL, dst, wc, dstend-dst);
4411ab64890Smrg	if (count == RET_TOOSMALL)
4421ab64890Smrg	    break;
4431ab64890Smrg	if (count == RET_ILSEQ) {
4441ab64890Smrg	    count = utf8_wctomb(NULL, dst, BAD_WCHAR, dstend-dst);
4451ab64890Smrg	    if (count == RET_TOOSMALL)
4461ab64890Smrg		break;
4471ab64890Smrg	    unconv_num++;
4481ab64890Smrg	}
4491ab64890Smrg	src += consumed;
4501ab64890Smrg	dst += count;
4511ab64890Smrg    }
4521ab64890Smrg
4531ab64890Smrg    *from = (XPointer) src;
4541ab64890Smrg    *from_left = srcend - src;
4551ab64890Smrg    *to = (XPointer) dst;
4561ab64890Smrg    *to_left = dstend - dst;
4571ab64890Smrg
4581ab64890Smrg    return unconv_num;
4591ab64890Smrg}
4601ab64890Smrg
4611ab64890Smrgstatic XlcConvMethodsRec methods_cstoutf8 = {
4621ab64890Smrg    close_converter,
4631ab64890Smrg    cstoutf8,
4641ab64890Smrg    NULL
4651ab64890Smrg};
4661ab64890Smrg
4671ab64890Smrgstatic XlcConv
4681ab64890Smrgopen_cstoutf8(
4691ab64890Smrg    XLCd from_lcd,
4701ab64890Smrg    const char *from_type,
4711ab64890Smrg    XLCd to_lcd,
4721ab64890Smrg    const char *to_type)
4731ab64890Smrg{
4741ab64890Smrg    lazy_init_all_charsets();
4751ab64890Smrg    return create_conv(from_lcd, &methods_cstoutf8);
4761ab64890Smrg}
4771ab64890Smrg
4781ab64890Smrg/* from XlcNUtf8String to XlcNCharSet */
4791ab64890Smrg
4801ab64890Smrgstatic XlcConv
4811ab64890Smrgcreate_tocs_conv(
4821ab64890Smrg    XLCd lcd,
4831ab64890Smrg    XlcConvMethods methods)
4841ab64890Smrg{
4851ab64890Smrg    XlcConv conv;
4861ab64890Smrg    CodeSet *codeset_list;
4871ab64890Smrg    int codeset_num;
4881ab64890Smrg    int charset_num;
4891ab64890Smrg    int i, j, k;
4901ab64890Smrg    Utf8Conv *preferred;
4911ab64890Smrg
4921ab64890Smrg    lazy_init_all_charsets();
4931ab64890Smrg
4941ab64890Smrg    codeset_list = XLC_GENERIC(lcd, codeset_list);
4951ab64890Smrg    codeset_num = XLC_GENERIC(lcd, codeset_num);
4961ab64890Smrg
4971ab64890Smrg    charset_num = 0;
4981ab64890Smrg    for (i = 0; i < codeset_num; i++)
4991ab64890Smrg	charset_num += codeset_list[i]->num_charsets;
5001ab64890Smrg    if (charset_num > all_charsets_count-1)
5011ab64890Smrg	charset_num = all_charsets_count-1;
5021ab64890Smrg
5031ab64890Smrg    conv = (XlcConv) Xmalloc(sizeof(XlcConvRec)
5041ab64890Smrg			     + (charset_num + 1) * sizeof(Utf8Conv));
5051ab64890Smrg    if (conv == (XlcConv) NULL)
5061ab64890Smrg	return (XlcConv) NULL;
5071ab64890Smrg    preferred = (Utf8Conv *) ((char *) conv + sizeof(XlcConvRec));
5081ab64890Smrg
5091ab64890Smrg    /* Loop through all codesets mentioned in the locale. */
5101ab64890Smrg    charset_num = 0;
5111ab64890Smrg    for (i = 0; i < codeset_num; i++) {
5121ab64890Smrg	XlcCharSet *charsets = codeset_list[i]->charset_list;
5131ab64890Smrg	int num_charsets = codeset_list[i]->num_charsets;
5141ab64890Smrg	for (j = 0; j < num_charsets; j++) {
5151ab64890Smrg	    const char *name = charsets[j]->encoding_name;
5161ab64890Smrg	    /* If it wasn't already encountered... */
5171ab64890Smrg	    for (k = charset_num-1; k >= 0; k--)
5181ab64890Smrg		if (!strcmp(preferred[k]->name, name))
5191ab64890Smrg		    break;
5201ab64890Smrg	    if (k < 0) {
5211ab64890Smrg		/* Look it up in all_charsets[]. */
5221ab64890Smrg		for (k = 0; k < all_charsets_count-1; k++)
5231ab64890Smrg		    if (!strcmp(all_charsets[k].name, name)) {
5241ab64890Smrg			/* Add it to the preferred set. */
5251ab64890Smrg			preferred[charset_num++] = &all_charsets[k];
5261ab64890Smrg			break;
5271ab64890Smrg		    }
5281ab64890Smrg	    }
5291ab64890Smrg	}
5301ab64890Smrg    }
5311ab64890Smrg    preferred[charset_num] = (Utf8Conv) NULL;
5321ab64890Smrg
5331ab64890Smrg    conv->methods = methods;
5341ab64890Smrg    conv->state = (XPointer) preferred;
5351ab64890Smrg
5361ab64890Smrg    return conv;
5371ab64890Smrg}
5381ab64890Smrg
5391ab64890Smrgstatic void
5401ab64890Smrgclose_tocs_converter(
5411ab64890Smrg    XlcConv conv)
5421ab64890Smrg{
5431ab64890Smrg    /* conv->state is allocated together with conv, free both at once.  */
5441ab64890Smrg    Xfree((char *) conv);
5451ab64890Smrg}
5461ab64890Smrg
5471ab64890Smrg/*
5481ab64890Smrg * Converts a Unicode character to an appropriate character set. The NULL
5491ab64890Smrg * terminated array of preferred character sets is passed as first argument.
5501ab64890Smrg * If successful, *charsetp is set to the character set that was used, and
5511ab64890Smrg * *sidep is set to the character set side (XlcGL or XlcGR).
5521ab64890Smrg */
5531ab64890Smrgstatic int
5541ab64890Smrgcharset_wctocs(
5551ab64890Smrg    Utf8Conv *preferred,
5561ab64890Smrg    Utf8Conv *charsetp,
5571ab64890Smrg    XlcSide *sidep,
5581ab64890Smrg    XlcConv conv,
5591ab64890Smrg    unsigned char *r,
5601ab64890Smrg    ucs4_t wc,
5611ab64890Smrg    int n)
5621ab64890Smrg{
5631ab64890Smrg    int count;
5641ab64890Smrg    Utf8Conv convptr;
5651ab64890Smrg    int i;
5661ab64890Smrg
5671ab64890Smrg    for (; *preferred != (Utf8Conv) NULL; preferred++) {
5681ab64890Smrg	convptr = *preferred;
5691ab64890Smrg	count = convptr->wctocs(conv, r, wc, n);
5701ab64890Smrg	if (count == RET_TOOSMALL)
5711ab64890Smrg	    return RET_TOOSMALL;
5721ab64890Smrg	if (count != RET_ILSEQ) {
5731ab64890Smrg	    *charsetp = convptr;
5741ab64890Smrg	    *sidep = (*r < 0x80 ? XlcGL : XlcGR);
5751ab64890Smrg	    return count;
5761ab64890Smrg	}
5771ab64890Smrg    }
5781ab64890Smrg    for (convptr = all_charsets+1, i = all_charsets_count-1; i > 0; convptr++, i--) {
5791ab64890Smrg	count = convptr->wctocs(conv, r, wc, n);
5801ab64890Smrg	if (count == RET_TOOSMALL)
5811ab64890Smrg	    return RET_TOOSMALL;
5821ab64890Smrg	if (count != RET_ILSEQ) {
5831ab64890Smrg	    *charsetp = convptr;
5841ab64890Smrg	    *sidep = (*r < 0x80 ? XlcGL : XlcGR);
5851ab64890Smrg	    return count;
5861ab64890Smrg	}
5871ab64890Smrg    }
5881ab64890Smrg    return RET_ILSEQ;
5891ab64890Smrg}
5901ab64890Smrg
5911ab64890Smrgstatic int
5921ab64890Smrgutf8tocs(
5931ab64890Smrg    XlcConv conv,
5941ab64890Smrg    XPointer *from,
5951ab64890Smrg    int *from_left,
5961ab64890Smrg    XPointer *to,
5971ab64890Smrg    int *to_left,
5981ab64890Smrg    XPointer *args,
5991ab64890Smrg    int num_args)
6001ab64890Smrg{
6011ab64890Smrg    Utf8Conv *preferred_charsets;
6021ab64890Smrg    XlcCharSet last_charset = NULL;
6031ab64890Smrg    unsigned char const *src;
6041ab64890Smrg    unsigned char const *srcend;
6051ab64890Smrg    unsigned char *dst;
6061ab64890Smrg    unsigned char *dstend;
6071ab64890Smrg    int unconv_num;
6081ab64890Smrg
6091ab64890Smrg    if (from == NULL || *from == NULL)
6101ab64890Smrg	return 0;
6111ab64890Smrg
6121ab64890Smrg    preferred_charsets = (Utf8Conv *) conv->state;
6131ab64890Smrg    src = (unsigned char const *) *from;
6141ab64890Smrg    srcend = src + *from_left;
6151ab64890Smrg    dst = (unsigned char *) *to;
6161ab64890Smrg    dstend = dst + *to_left;
6171ab64890Smrg    unconv_num = 0;
6181ab64890Smrg
6191ab64890Smrg    while (src < srcend && dst < dstend) {
6201ab64890Smrg	Utf8Conv chosen_charset = NULL;
6211ab64890Smrg	XlcSide chosen_side = XlcNONE;
6221ab64890Smrg	ucs4_t wc;
6231ab64890Smrg	int consumed;
6241ab64890Smrg	int count;
6251ab64890Smrg
6261ab64890Smrg	consumed = utf8_mbtowc(NULL, &wc, src, srcend-src);
6271ab64890Smrg	if (consumed == RET_TOOFEW(0))
6281ab64890Smrg	    break;
6291ab64890Smrg	if (consumed == RET_ILSEQ) {
6301ab64890Smrg	    src++;
6311ab64890Smrg	    unconv_num++;
6321ab64890Smrg	    continue;
6331ab64890Smrg	}
6341ab64890Smrg
6351ab64890Smrg	count = charset_wctocs(preferred_charsets, &chosen_charset, &chosen_side, conv, dst, wc, dstend-dst);
6361ab64890Smrg	if (count == RET_TOOSMALL)
6371ab64890Smrg	    break;
6381ab64890Smrg	if (count == RET_ILSEQ) {
6391ab64890Smrg	    src += consumed;
6401ab64890Smrg	    unconv_num++;
6411ab64890Smrg	    continue;
6421ab64890Smrg	}
6431ab64890Smrg
6441ab64890Smrg	if (last_charset == NULL) {
6451ab64890Smrg	    last_charset =
6461ab64890Smrg	        _XlcGetCharSetWithSide(chosen_charset->name, chosen_side);
6471ab64890Smrg	    if (last_charset == NULL) {
6481ab64890Smrg		src += consumed;
6491ab64890Smrg		unconv_num++;
6501ab64890Smrg		continue;
6511ab64890Smrg	    }
6521ab64890Smrg	} else {
6531ab64890Smrg	    if (!(last_charset->xrm_encoding_name == chosen_charset->xrm_name
6541ab64890Smrg	          && (last_charset->side == XlcGLGR
6551ab64890Smrg	              || last_charset->side == chosen_side)))
6561ab64890Smrg		break;
6571ab64890Smrg	}
6581ab64890Smrg	src += consumed;
6591ab64890Smrg	dst += count;
6601ab64890Smrg    }
6611ab64890Smrg
6621ab64890Smrg    if (last_charset == NULL)
6631ab64890Smrg	return -1;
6641ab64890Smrg
6651ab64890Smrg    *from = (XPointer) src;
6661ab64890Smrg    *from_left = srcend - src;
6671ab64890Smrg    *to = (XPointer) dst;
6681ab64890Smrg    *to_left = dstend - dst;
6691ab64890Smrg
6701ab64890Smrg    if (num_args >= 1)
6711ab64890Smrg	*((XlcCharSet *)args[0]) = last_charset;
6721ab64890Smrg
6731ab64890Smrg    return unconv_num;
6741ab64890Smrg}
6751ab64890Smrg
6761ab64890Smrgstatic XlcConvMethodsRec methods_utf8tocs = {
6771ab64890Smrg    close_tocs_converter,
6781ab64890Smrg    utf8tocs,
6791ab64890Smrg    NULL
6801ab64890Smrg};
6811ab64890Smrg
6821ab64890Smrgstatic XlcConv
6831ab64890Smrgopen_utf8tocs(
6841ab64890Smrg    XLCd from_lcd,
6851ab64890Smrg    const char *from_type,
6861ab64890Smrg    XLCd to_lcd,
6871ab64890Smrg    const char *to_type)
6881ab64890Smrg{
6891ab64890Smrg    return create_tocs_conv(from_lcd, &methods_utf8tocs);
6901ab64890Smrg}
6911ab64890Smrg
6921ab64890Smrg/* from XlcNUtf8String to XlcNChar */
6931ab64890Smrg
6941ab64890Smrgstatic int
6951ab64890Smrgutf8tocs1(
6961ab64890Smrg    XlcConv conv,
6971ab64890Smrg    XPointer *from,
6981ab64890Smrg    int *from_left,
6991ab64890Smrg    XPointer *to,
7001ab64890Smrg    int *to_left,
7011ab64890Smrg    XPointer *args,
7021ab64890Smrg    int num_args)
7031ab64890Smrg{
7041ab64890Smrg    Utf8Conv *preferred_charsets;
7051ab64890Smrg    XlcCharSet last_charset = NULL;
7061ab64890Smrg    unsigned char const *src;
7071ab64890Smrg    unsigned char const *srcend;
7081ab64890Smrg    unsigned char *dst;
7091ab64890Smrg    unsigned char *dstend;
7101ab64890Smrg    int unconv_num;
7111ab64890Smrg
7121ab64890Smrg    if (from == NULL || *from == NULL)
7131ab64890Smrg	return 0;
7141ab64890Smrg
7151ab64890Smrg    preferred_charsets = (Utf8Conv *) conv->state;
7161ab64890Smrg    src = (unsigned char const *) *from;
7171ab64890Smrg    srcend = src + *from_left;
7181ab64890Smrg    dst = (unsigned char *) *to;
7191ab64890Smrg    dstend = dst + *to_left;
7201ab64890Smrg    unconv_num = 0;
7211ab64890Smrg
7221ab64890Smrg    while (src < srcend && dst < dstend) {
7231ab64890Smrg	Utf8Conv chosen_charset = NULL;
7241ab64890Smrg	XlcSide chosen_side = XlcNONE;
7251ab64890Smrg	ucs4_t wc;
7261ab64890Smrg	int consumed;
7271ab64890Smrg	int count;
7281ab64890Smrg
7291ab64890Smrg	consumed = utf8_mbtowc(NULL, &wc, src, srcend-src);
7301ab64890Smrg	if (consumed == RET_TOOFEW(0))
7311ab64890Smrg	    break;
7321ab64890Smrg	if (consumed == RET_ILSEQ) {
7331ab64890Smrg	    src++;
7341ab64890Smrg	    unconv_num++;
7351ab64890Smrg	    continue;
7361ab64890Smrg	}
7371ab64890Smrg
7381ab64890Smrg	count = charset_wctocs(preferred_charsets, &chosen_charset, &chosen_side, conv, dst, wc, dstend-dst);
7391ab64890Smrg	if (count == RET_TOOSMALL)
7401ab64890Smrg	    break;
7411ab64890Smrg	if (count == RET_ILSEQ) {
7421ab64890Smrg	    src += consumed;
7431ab64890Smrg	    unconv_num++;
7441ab64890Smrg	    continue;
7451ab64890Smrg	}
7461ab64890Smrg
7471ab64890Smrg	if (last_charset == NULL) {
7481ab64890Smrg	    last_charset =
7491ab64890Smrg	        _XlcGetCharSetWithSide(chosen_charset->name, chosen_side);
7501ab64890Smrg	    if (last_charset == NULL) {
7511ab64890Smrg		src += consumed;
7521ab64890Smrg		unconv_num++;
7531ab64890Smrg		continue;
7541ab64890Smrg	    }
7551ab64890Smrg	} else {
7561ab64890Smrg	    if (!(last_charset->xrm_encoding_name == chosen_charset->xrm_name
7571ab64890Smrg	          && (last_charset->side == XlcGLGR
7581ab64890Smrg	              || last_charset->side == chosen_side)))
7591ab64890Smrg		break;
7601ab64890Smrg	}
7611ab64890Smrg	src += consumed;
7621ab64890Smrg	dst += count;
7631ab64890Smrg	break;
7641ab64890Smrg    }
7651ab64890Smrg
7661ab64890Smrg    if (last_charset == NULL)
7671ab64890Smrg	return -1;
7681ab64890Smrg
7691ab64890Smrg    *from = (XPointer) src;
7701ab64890Smrg    *from_left = srcend - src;
7711ab64890Smrg    *to = (XPointer) dst;
7721ab64890Smrg    *to_left = dstend - dst;
7731ab64890Smrg
7741ab64890Smrg    if (num_args >= 1)
7751ab64890Smrg	*((XlcCharSet *)args[0]) = last_charset;
7761ab64890Smrg
7771ab64890Smrg    return unconv_num;
7781ab64890Smrg}
7791ab64890Smrg
7801ab64890Smrgstatic XlcConvMethodsRec methods_utf8tocs1 = {
7811ab64890Smrg    close_tocs_converter,
7821ab64890Smrg    utf8tocs1,
7831ab64890Smrg    NULL
7841ab64890Smrg};
7851ab64890Smrg
7861ab64890Smrgstatic XlcConv
7871ab64890Smrgopen_utf8tocs1(
7881ab64890Smrg    XLCd from_lcd,
7891ab64890Smrg    const char *from_type,
7901ab64890Smrg    XLCd to_lcd,
7911ab64890Smrg    const char *to_type)
7921ab64890Smrg{
7931ab64890Smrg    return create_tocs_conv(from_lcd, &methods_utf8tocs1);
7941ab64890Smrg}
7951ab64890Smrg
7961ab64890Smrg/* from XlcNUtf8String to XlcNString */
7971ab64890Smrg
7981ab64890Smrgstatic int
7991ab64890Smrgutf8tostr(
8001ab64890Smrg    XlcConv conv,
8011ab64890Smrg    XPointer *from,
8021ab64890Smrg    int *from_left,
8031ab64890Smrg    XPointer *to,
8041ab64890Smrg    int *to_left,
8051ab64890Smrg    XPointer *args,
8061ab64890Smrg    int num_args)
8071ab64890Smrg{
8081ab64890Smrg    unsigned char const *src;
8091ab64890Smrg    unsigned char const *srcend;
8101ab64890Smrg    unsigned char *dst;
8111ab64890Smrg    unsigned char *dstend;
8121ab64890Smrg    int unconv_num;
8131ab64890Smrg
8141ab64890Smrg    if (from == NULL || *from == NULL)
8151ab64890Smrg	return 0;
8161ab64890Smrg
8171ab64890Smrg    src = (unsigned char const *) *from;
8181ab64890Smrg    srcend = src + *from_left;
8191ab64890Smrg    dst = (unsigned char *) *to;
8201ab64890Smrg    dstend = dst + *to_left;
8211ab64890Smrg    unconv_num = 0;
8221ab64890Smrg
8231ab64890Smrg    while (src < srcend) {
8241ab64890Smrg	unsigned char c;
8251ab64890Smrg	ucs4_t wc;
8261ab64890Smrg	int consumed;
8271ab64890Smrg
8281ab64890Smrg	consumed = utf8_mbtowc(NULL, &wc, src, srcend-src);
8291ab64890Smrg	if (consumed == RET_TOOFEW(0))
8301ab64890Smrg	    break;
8311ab64890Smrg	if (dst == dstend)
8321ab64890Smrg	    break;
8331ab64890Smrg	if (consumed == RET_ILSEQ) {
8341ab64890Smrg	    consumed = 1;
8351ab64890Smrg	    c = BAD_CHAR;
8361ab64890Smrg	    unconv_num++;
8371ab64890Smrg	} else {
8381ab64890Smrg	    if ((wc & ~(ucs4_t)0xff) != 0) {
8391ab64890Smrg		c = BAD_CHAR;
8401ab64890Smrg		unconv_num++;
8411ab64890Smrg	    } else
8421ab64890Smrg		c = (unsigned char) wc;
8431ab64890Smrg	}
8441ab64890Smrg	*dst++ = c;
8451ab64890Smrg	src += consumed;
8461ab64890Smrg    }
8471ab64890Smrg
8481ab64890Smrg    *from = (XPointer) src;
8491ab64890Smrg    *from_left = srcend - src;
8501ab64890Smrg    *to = (XPointer) dst;
8511ab64890Smrg    *to_left = dstend - dst;
8521ab64890Smrg
8531ab64890Smrg    return unconv_num;
8541ab64890Smrg}
8551ab64890Smrg
8561ab64890Smrgstatic XlcConvMethodsRec methods_utf8tostr = {
8571ab64890Smrg    close_converter,
8581ab64890Smrg    utf8tostr,
8591ab64890Smrg    NULL
8601ab64890Smrg};
8611ab64890Smrg
8621ab64890Smrgstatic XlcConv
8631ab64890Smrgopen_utf8tostr(
8641ab64890Smrg    XLCd from_lcd,
8651ab64890Smrg    const char *from_type,
8661ab64890Smrg    XLCd to_lcd,
8671ab64890Smrg    const char *to_type)
8681ab64890Smrg{
8691ab64890Smrg    return create_conv(from_lcd, &methods_utf8tostr);
8701ab64890Smrg}
8711ab64890Smrg
8721ab64890Smrg/* from XlcNString to XlcNUtf8String */
8731ab64890Smrg
8741ab64890Smrgstatic int
8751ab64890Smrgstrtoutf8(
8761ab64890Smrg    XlcConv conv,
8771ab64890Smrg    XPointer *from,
8781ab64890Smrg    int *from_left,
8791ab64890Smrg    XPointer *to,
8801ab64890Smrg    int *to_left,
8811ab64890Smrg    XPointer *args,
8821ab64890Smrg    int num_args)
8831ab64890Smrg{
8841ab64890Smrg    unsigned char const *src;
8851ab64890Smrg    unsigned char const *srcend;
8861ab64890Smrg    unsigned char *dst;
8871ab64890Smrg    unsigned char *dstend;
8881ab64890Smrg
8891ab64890Smrg    if (from == NULL || *from == NULL)
8901ab64890Smrg	return 0;
8911ab64890Smrg
8921ab64890Smrg    src = (unsigned char const *) *from;
8931ab64890Smrg    srcend = src + *from_left;
8941ab64890Smrg    dst = (unsigned char *) *to;
8951ab64890Smrg    dstend = dst + *to_left;
8961ab64890Smrg
8971ab64890Smrg    while (src < srcend) {
8981ab64890Smrg	int count = utf8_wctomb(NULL, dst, *src, dstend-dst);
8991ab64890Smrg	if (count == RET_TOOSMALL)
9001ab64890Smrg	    break;
9011ab64890Smrg	dst += count;
9021ab64890Smrg	src++;
9031ab64890Smrg    }
9041ab64890Smrg
9051ab64890Smrg    *from = (XPointer) src;
9061ab64890Smrg    *from_left = srcend - src;
9071ab64890Smrg    *to = (XPointer) dst;
9081ab64890Smrg    *to_left = dstend - dst;
9091ab64890Smrg
9101ab64890Smrg    return 0;
9111ab64890Smrg}
9121ab64890Smrg
9131ab64890Smrgstatic XlcConvMethodsRec methods_strtoutf8 = {
9141ab64890Smrg    close_converter,
9151ab64890Smrg    strtoutf8,
9161ab64890Smrg    NULL
9171ab64890Smrg};
9181ab64890Smrg
9191ab64890Smrgstatic XlcConv
9201ab64890Smrgopen_strtoutf8(
9211ab64890Smrg    XLCd from_lcd,
9221ab64890Smrg    const char *from_type,
9231ab64890Smrg    XLCd to_lcd,
9241ab64890Smrg    const char *to_type)
9251ab64890Smrg{
9261ab64890Smrg    return create_conv(from_lcd, &methods_strtoutf8);
9271ab64890Smrg}
9281ab64890Smrg
9291ab64890Smrg/* Support for the input methods. */
9301ab64890Smrg
9311ab64890SmrgXPointer
9321ab64890Smrg_Utf8GetConvByName(
9331ab64890Smrg    const char *name)
9341ab64890Smrg{
9351ab64890Smrg    XrmQuark xrm_name;
9361ab64890Smrg    Utf8Conv convptr;
9371ab64890Smrg    int i;
9381ab64890Smrg
9391ab64890Smrg    if (name == NULL)
9401ab64890Smrg        return (XPointer) NULL;
9411ab64890Smrg
9421ab64890Smrg    lazy_init_all_charsets();
9431ab64890Smrg    xrm_name = XrmStringToQuark(name);
9441ab64890Smrg
9451ab64890Smrg    for (convptr = all_charsets, i = all_charsets_count-1; i > 0; convptr++, i--)
9461ab64890Smrg	if (convptr->xrm_name == xrm_name)
9471ab64890Smrg	    return (XPointer) convptr->wctocs;
9481ab64890Smrg    return (XPointer) NULL;
9491ab64890Smrg}
9501ab64890Smrg
9511ab64890Smrg/* from XlcNUcsChar to XlcNChar, needed for input methods */
9521ab64890Smrg
9531ab64890Smrgstatic XlcConv
9541ab64890Smrgcreate_ucstocs_conv(
9551ab64890Smrg    XLCd lcd,
9561ab64890Smrg    XlcConvMethods methods)
9571ab64890Smrg{
9581ab64890Smrg
9591ab64890Smrg    if (XLC_PUBLIC_PART(lcd)->codeset
9601ab64890Smrg	&& _XlcCompareISOLatin1(XLC_PUBLIC_PART(lcd)->codeset, "UTF-8") == 0) {
9611ab64890Smrg	XlcConv conv;
9621ab64890Smrg	Utf8Conv *preferred;
9631ab64890Smrg
9641ab64890Smrg	lazy_init_all_charsets();
9651ab64890Smrg
9661ab64890Smrg	conv = (XlcConv) Xmalloc(sizeof(XlcConvRec) + 2 * sizeof(Utf8Conv));
9671ab64890Smrg	if (conv == (XlcConv) NULL)
9681ab64890Smrg	    return (XlcConv) NULL;
9691ab64890Smrg	preferred = (Utf8Conv *) ((char *) conv + sizeof(XlcConvRec));
9701ab64890Smrg
9711ab64890Smrg	preferred[0] = &all_charsets[0]; /* ISO10646 */
9721ab64890Smrg	preferred[1] = (Utf8Conv) NULL;
9731ab64890Smrg
9741ab64890Smrg	conv->methods = methods;
9751ab64890Smrg	conv->state = (XPointer) preferred;
9761ab64890Smrg
9771ab64890Smrg	return conv;
9781ab64890Smrg    } else {
9791ab64890Smrg	return create_tocs_conv(lcd, methods);
9801ab64890Smrg    }
9811ab64890Smrg}
9821ab64890Smrg
9831ab64890Smrgstatic int
9841ab64890Smrgcharset_wctocs_exactly(
9851ab64890Smrg    Utf8Conv *preferred,
9861ab64890Smrg    Utf8Conv *charsetp,
9871ab64890Smrg    XlcSide *sidep,
9881ab64890Smrg    XlcConv conv,
9891ab64890Smrg    unsigned char *r,
9901ab64890Smrg    ucs4_t wc,
9911ab64890Smrg    int n)
9921ab64890Smrg{
9931ab64890Smrg    int count;
9941ab64890Smrg    Utf8Conv convptr;
9951ab64890Smrg
9961ab64890Smrg    for (; *preferred != (Utf8Conv) NULL; preferred++) {
9971ab64890Smrg	convptr = *preferred;
9981ab64890Smrg	count = convptr->wctocs(conv, r, wc, n);
9991ab64890Smrg	if (count == RET_TOOSMALL)
10001ab64890Smrg	    return RET_TOOSMALL;
10011ab64890Smrg	if (count != RET_ILSEQ) {
10021ab64890Smrg	    *charsetp = convptr;
10031ab64890Smrg	    *sidep = (*r < 0x80 ? XlcGL : XlcGR);
10041ab64890Smrg	    return count;
10051ab64890Smrg	}
10061ab64890Smrg    }
10071ab64890Smrg    return RET_ILSEQ;
10081ab64890Smrg}
10091ab64890Smrg
10101ab64890Smrgstatic int
10111ab64890Smrgucstocs1(
10121ab64890Smrg    XlcConv conv,
10131ab64890Smrg    XPointer *from,
10141ab64890Smrg    int *from_left,
10151ab64890Smrg    XPointer *to,
10161ab64890Smrg    int *to_left,
10171ab64890Smrg    XPointer *args,
10181ab64890Smrg    int num_args)
10191ab64890Smrg{
10201ab64890Smrg    ucs4_t const *src = (ucs4_t const *) *from;
10211ab64890Smrg    unsigned char *dst = (unsigned char *) *to;
10221ab64890Smrg    int unconv_num = 0;
10231ab64890Smrg    Utf8Conv *preferred_charsets = (Utf8Conv *) conv->state;
10241ab64890Smrg    Utf8Conv chosen_charset = NULL;
10251ab64890Smrg    XlcSide chosen_side = XlcNONE;
10261ab64890Smrg    XlcCharSet charset = NULL;
10271ab64890Smrg    int count;
10281ab64890Smrg
10291ab64890Smrg    if (from == NULL || *from == NULL)
10301ab64890Smrg	return 0;
10311ab64890Smrg
10321ab64890Smrg    count = charset_wctocs_exactly(preferred_charsets, &chosen_charset,
10331ab64890Smrg                                   &chosen_side, conv, dst, *src, *to_left);
10341ab64890Smrg    if (count < 1) {
10351ab64890Smrg        unconv_num++;
10361ab64890Smrg        count = 0;
10371ab64890Smrg    } else {
10381ab64890Smrg        charset = _XlcGetCharSetWithSide(chosen_charset->name, chosen_side);
10391ab64890Smrg    }
10401ab64890Smrg    if (charset == NULL)
10411ab64890Smrg	return -1;
10421ab64890Smrg
10431ab64890Smrg    *from = (XPointer) ++src;
10441ab64890Smrg    (*from_left)--;
10451ab64890Smrg    *to = (XPointer) dst;
10461ab64890Smrg    *to_left -= count;
10471ab64890Smrg
10481ab64890Smrg    if (num_args >= 1)
10491ab64890Smrg	*((XlcCharSet *)args[0]) = charset;
10501ab64890Smrg
10511ab64890Smrg    return unconv_num;
10521ab64890Smrg}
10531ab64890Smrg
10541ab64890Smrgstatic XlcConvMethodsRec methods_ucstocs1 = {
10551ab64890Smrg    close_tocs_converter,
10561ab64890Smrg    ucstocs1,
10571ab64890Smrg    NULL
10581ab64890Smrg};
10591ab64890Smrg
10601ab64890Smrgstatic XlcConv
10611ab64890Smrgopen_ucstocs1(
10621ab64890Smrg    XLCd from_lcd,
10631ab64890Smrg    const char *from_type,
10641ab64890Smrg    XLCd to_lcd,
10651ab64890Smrg    const char *to_type)
10661ab64890Smrg{
10671ab64890Smrg    return create_ucstocs_conv(from_lcd, &methods_ucstocs1);
10681ab64890Smrg}
10691ab64890Smrg
10701ab64890Smrg/* from XlcNUcsChar to XlcNUtf8String, needed for input methods */
10711ab64890Smrg
10721ab64890Smrgstatic int
10731ab64890Smrgucstoutf8(
10741ab64890Smrg    XlcConv conv,
10751ab64890Smrg    XPointer *from,
10761ab64890Smrg    int *from_left,
10771ab64890Smrg    XPointer *to,
10781ab64890Smrg    int *to_left,
10791ab64890Smrg    XPointer *args,
10801ab64890Smrg    int num_args)
10811ab64890Smrg{
10821ab64890Smrg    const ucs4_t *src;
10831ab64890Smrg    const ucs4_t *srcend;
10841ab64890Smrg    unsigned char *dst;
10851ab64890Smrg    unsigned char *dstend;
10861ab64890Smrg    int unconv_num;
10871ab64890Smrg
10881ab64890Smrg    if (from == NULL || *from == NULL)
10891ab64890Smrg	return 0;
10901ab64890Smrg
10911ab64890Smrg    src = (const ucs4_t *) *from;
10921ab64890Smrg    srcend = src + *from_left;
10931ab64890Smrg    dst = (unsigned char *) *to;
10941ab64890Smrg    dstend = dst + *to_left;
10951ab64890Smrg    unconv_num = 0;
10961ab64890Smrg
10971ab64890Smrg    while (src < srcend) {
10981ab64890Smrg	int count = utf8_wctomb(NULL, dst, *src, dstend-dst);
10991ab64890Smrg	if (count == RET_TOOSMALL)
11001ab64890Smrg	    break;
11011ab64890Smrg	if (count == RET_ILSEQ)
11021ab64890Smrg	    unconv_num++;
11031ab64890Smrg	src++;
11041ab64890Smrg	dst += count;
11051ab64890Smrg    }
11061ab64890Smrg
11071ab64890Smrg    *from = (XPointer) src;
11081ab64890Smrg    *from_left = srcend - src;
11091ab64890Smrg    *to = (XPointer) dst;
11101ab64890Smrg    *to_left = dstend - dst;
11111ab64890Smrg
11121ab64890Smrg    return unconv_num;
11131ab64890Smrg}
11141ab64890Smrg
11151ab64890Smrgstatic XlcConvMethodsRec methods_ucstoutf8 = {
11161ab64890Smrg    close_converter,
11171ab64890Smrg    ucstoutf8,
11181ab64890Smrg    NULL
11191ab64890Smrg};
11201ab64890Smrg
11211ab64890Smrgstatic XlcConv
11221ab64890Smrgopen_ucstoutf8(
11231ab64890Smrg    XLCd from_lcd,
11241ab64890Smrg    const char *from_type,
11251ab64890Smrg    XLCd to_lcd,
11261ab64890Smrg    const char *to_type)
11271ab64890Smrg{
11281ab64890Smrg    return create_conv(from_lcd, &methods_ucstoutf8);
11291ab64890Smrg}
11301ab64890Smrg
11311ab64890Smrg/* Registers UTF-8 converters for a non-UTF-8 locale. */
11321ab64890Smrgvoid
11331ab64890Smrg_XlcAddUtf8Converters(
11341ab64890Smrg    XLCd lcd)
11351ab64890Smrg{
11361ab64890Smrg    _XlcSetConverter(lcd, XlcNCharSet, lcd, XlcNUtf8String, open_cstoutf8);
11371ab64890Smrg    _XlcSetConverter(lcd, XlcNUtf8String, lcd, XlcNCharSet, open_utf8tocs);
11381ab64890Smrg    _XlcSetConverter(lcd, XlcNUtf8String, lcd, XlcNChar, open_utf8tocs1);
11391ab64890Smrg    _XlcSetConverter(lcd, XlcNString, lcd, XlcNUtf8String, open_strtoutf8);
11401ab64890Smrg    _XlcSetConverter(lcd, XlcNUtf8String, lcd, XlcNString, open_utf8tostr);
11411ab64890Smrg    _XlcSetConverter(lcd, XlcNUcsChar,    lcd, XlcNChar, open_ucstocs1);
11421ab64890Smrg    _XlcSetConverter(lcd, XlcNUcsChar,    lcd, XlcNUtf8String, open_ucstoutf8);
11431ab64890Smrg}
11441ab64890Smrg
11451ab64890Smrg/***************************************************************************/
11461ab64890Smrg/* Part II: UTF-8 locale loader conversion files
11471ab64890Smrg *
11481ab64890Smrg * Here we can assume that "multi-byte" is UTF-8 and that `wchar_t' is Unicode.
11491ab64890Smrg */
11501ab64890Smrg
11511ab64890Smrg/* from XlcNMultiByte to XlcNWideChar */
11521ab64890Smrg
11531ab64890Smrgstatic int
11541ab64890Smrgutf8towcs(
11551ab64890Smrg    XlcConv conv,
11561ab64890Smrg    XPointer *from,
11571ab64890Smrg    int *from_left,
11581ab64890Smrg    XPointer *to,
11591ab64890Smrg    int *to_left,
11601ab64890Smrg    XPointer *args,
11611ab64890Smrg    int num_args)
11621ab64890Smrg{
11631ab64890Smrg    unsigned char const *src;
11641ab64890Smrg    unsigned char const *srcend;
11651ab64890Smrg    wchar_t *dst;
11661ab64890Smrg    wchar_t *dstend;
11671ab64890Smrg    int unconv_num;
11681ab64890Smrg
11691ab64890Smrg    if (from == NULL || *from == NULL)
11701ab64890Smrg	return 0;
11711ab64890Smrg
11721ab64890Smrg    src = (unsigned char const *) *from;
11731ab64890Smrg    srcend = src + *from_left;
11741ab64890Smrg    dst = (wchar_t *) *to;
11751ab64890Smrg    dstend = dst + *to_left;
11761ab64890Smrg    unconv_num = 0;
11771ab64890Smrg
11781ab64890Smrg    while (src < srcend && dst < dstend) {
11791ab64890Smrg	ucs4_t wc;
11801ab64890Smrg	int consumed = utf8_mbtowc(NULL, &wc, src, srcend-src);
11811ab64890Smrg	if (consumed == RET_TOOFEW(0))
11821ab64890Smrg	    break;
11831ab64890Smrg	if (consumed == RET_ILSEQ) {
11841ab64890Smrg	    src++;
11851ab64890Smrg	    *dst = BAD_WCHAR;
11861ab64890Smrg	    unconv_num++;
11871ab64890Smrg	} else {
11881ab64890Smrg	    src += consumed;
11891ab64890Smrg	    *dst = wc;
11901ab64890Smrg	}
11911ab64890Smrg	dst++;
11921ab64890Smrg    }
11931ab64890Smrg
11941ab64890Smrg    *from = (XPointer) src;
11951ab64890Smrg    *from_left = srcend - src;
11961ab64890Smrg    *to = (XPointer) dst;
11971ab64890Smrg    *to_left = dstend - dst;
11981ab64890Smrg
11991ab64890Smrg    return unconv_num;
12001ab64890Smrg}
12011ab64890Smrg
12021ab64890Smrgstatic XlcConvMethodsRec methods_utf8towcs = {
12031ab64890Smrg    close_converter,
12041ab64890Smrg    utf8towcs,
12051ab64890Smrg    NULL
12061ab64890Smrg};
12071ab64890Smrg
12081ab64890Smrgstatic XlcConv
12091ab64890Smrgopen_utf8towcs(
12101ab64890Smrg    XLCd from_lcd,
12111ab64890Smrg    const char *from_type,
12121ab64890Smrg    XLCd to_lcd,
12131ab64890Smrg    const char *to_type)
12141ab64890Smrg{
12151ab64890Smrg    return create_conv(from_lcd, &methods_utf8towcs);
12161ab64890Smrg}
12171ab64890Smrg
12181ab64890Smrg/* from XlcNWideChar to XlcNMultiByte */
12191ab64890Smrg
12201ab64890Smrgstatic int
12211ab64890Smrgwcstoutf8(
12221ab64890Smrg    XlcConv conv,
12231ab64890Smrg    XPointer *from,
12241ab64890Smrg    int *from_left,
12251ab64890Smrg    XPointer *to,
12261ab64890Smrg    int *to_left,
12271ab64890Smrg    XPointer *args,
12281ab64890Smrg    int num_args)
12291ab64890Smrg{
12301ab64890Smrg    wchar_t const *src;
12311ab64890Smrg    wchar_t const *srcend;
12321ab64890Smrg    unsigned char *dst;
12331ab64890Smrg    unsigned char *dstend;
12341ab64890Smrg    int unconv_num;
12351ab64890Smrg
12361ab64890Smrg    if (from == NULL || *from == NULL)
12371ab64890Smrg	return 0;
12381ab64890Smrg
12391ab64890Smrg    src = (wchar_t const *) *from;
12401ab64890Smrg    srcend = src + *from_left;
12411ab64890Smrg    dst = (unsigned char *) *to;
12421ab64890Smrg    dstend = dst + *to_left;
12431ab64890Smrg    unconv_num = 0;
12441ab64890Smrg
12451ab64890Smrg    while (src < srcend) {
12461ab64890Smrg	int count = utf8_wctomb(NULL, dst, *src, dstend-dst);
12471ab64890Smrg	if (count == RET_TOOSMALL)
12481ab64890Smrg	    break;
12491ab64890Smrg	if (count == RET_ILSEQ) {
12501ab64890Smrg	    count = utf8_wctomb(NULL, dst, BAD_WCHAR, dstend-dst);
12511ab64890Smrg	    if (count == RET_TOOSMALL)
12521ab64890Smrg		break;
12531ab64890Smrg	    unconv_num++;
12541ab64890Smrg	}
12551ab64890Smrg	dst += count;
12561ab64890Smrg	src++;
12571ab64890Smrg    }
12581ab64890Smrg
12591ab64890Smrg    *from = (XPointer) src;
12601ab64890Smrg    *from_left = srcend - src;
12611ab64890Smrg    *to = (XPointer) dst;
12621ab64890Smrg    *to_left = dstend - dst;
12631ab64890Smrg
12641ab64890Smrg    return unconv_num;
12651ab64890Smrg}
12661ab64890Smrg
12671ab64890Smrgstatic XlcConvMethodsRec methods_wcstoutf8 = {
12681ab64890Smrg    close_converter,
12691ab64890Smrg    wcstoutf8,
12701ab64890Smrg    NULL
12711ab64890Smrg};
12721ab64890Smrg
12731ab64890Smrgstatic XlcConv
12741ab64890Smrgopen_wcstoutf8(
12751ab64890Smrg    XLCd from_lcd,
12761ab64890Smrg    const char *from_type,
12771ab64890Smrg    XLCd to_lcd,
12781ab64890Smrg    const char *to_type)
12791ab64890Smrg{
12801ab64890Smrg    return create_conv(from_lcd, &methods_wcstoutf8);
12811ab64890Smrg}
12821ab64890Smrg
12831ab64890Smrg/* from XlcNString to XlcNWideChar */
12841ab64890Smrg
12851ab64890Smrgstatic int
12861ab64890Smrgour_strtowcs(
12871ab64890Smrg    XlcConv conv,
12881ab64890Smrg    XPointer *from,
12891ab64890Smrg    int *from_left,
12901ab64890Smrg    XPointer *to,
12911ab64890Smrg    int *to_left,
12921ab64890Smrg    XPointer *args,
12931ab64890Smrg    int num_args)
12941ab64890Smrg{
12951ab64890Smrg    unsigned char const *src;
12961ab64890Smrg    unsigned char const *srcend;
12971ab64890Smrg    wchar_t *dst;
12981ab64890Smrg    wchar_t *dstend;
12991ab64890Smrg
13001ab64890Smrg    if (from == NULL || *from == NULL)
13011ab64890Smrg	return 0;
13021ab64890Smrg
13031ab64890Smrg    src = (unsigned char const *) *from;
13041ab64890Smrg    srcend = src + *from_left;
13051ab64890Smrg    dst = (wchar_t *) *to;
13061ab64890Smrg    dstend = dst + *to_left;
13071ab64890Smrg
13081ab64890Smrg    while (src < srcend && dst < dstend)
13091ab64890Smrg	*dst++ = (wchar_t) *src++;
13101ab64890Smrg
13111ab64890Smrg    *from = (XPointer) src;
13121ab64890Smrg    *from_left = srcend - src;
13131ab64890Smrg    *to = (XPointer) dst;
13141ab64890Smrg    *to_left = dstend - dst;
13151ab64890Smrg
13161ab64890Smrg    return 0;
13171ab64890Smrg}
13181ab64890Smrg
13191ab64890Smrgstatic XlcConvMethodsRec methods_strtowcs = {
13201ab64890Smrg    close_converter,
13211ab64890Smrg    our_strtowcs,
13221ab64890Smrg    NULL
13231ab64890Smrg};
13241ab64890Smrg
13251ab64890Smrgstatic XlcConv
13261ab64890Smrgopen_strtowcs(
13271ab64890Smrg    XLCd from_lcd,
13281ab64890Smrg    const char *from_type,
13291ab64890Smrg    XLCd to_lcd,
13301ab64890Smrg    const char *to_type)
13311ab64890Smrg{
13321ab64890Smrg    return create_conv(from_lcd, &methods_strtowcs);
13331ab64890Smrg}
13341ab64890Smrg
13351ab64890Smrg/* from XlcNWideChar to XlcNString */
13361ab64890Smrg
13371ab64890Smrgstatic int
13381ab64890Smrgour_wcstostr(
13391ab64890Smrg    XlcConv conv,
13401ab64890Smrg    XPointer *from,
13411ab64890Smrg    int *from_left,
13421ab64890Smrg    XPointer *to,
13431ab64890Smrg    int *to_left,
13441ab64890Smrg    XPointer *args,
13451ab64890Smrg    int num_args)
13461ab64890Smrg{
13471ab64890Smrg    wchar_t const *src;
13481ab64890Smrg    wchar_t const *srcend;
13491ab64890Smrg    unsigned char *dst;
13501ab64890Smrg    unsigned char *dstend;
13511ab64890Smrg    int unconv_num;
13521ab64890Smrg
13531ab64890Smrg    if (from == NULL || *from == NULL)
13541ab64890Smrg	return 0;
13551ab64890Smrg
13561ab64890Smrg    src = (wchar_t const *) *from;
13571ab64890Smrg    srcend = src + *from_left;
13581ab64890Smrg    dst = (unsigned char *) *to;
13591ab64890Smrg    dstend = dst + *to_left;
13601ab64890Smrg    unconv_num = 0;
13611ab64890Smrg
13621ab64890Smrg    while (src < srcend && dst < dstend) {
13631ab64890Smrg	unsigned int wc = *src++;
13641ab64890Smrg	if (wc < 0x80)
13651ab64890Smrg	    *dst = wc;
13661ab64890Smrg	else {
13671ab64890Smrg	    *dst = BAD_CHAR;
13681ab64890Smrg	    unconv_num++;
13691ab64890Smrg	}
13701ab64890Smrg	dst++;
13711ab64890Smrg    }
13721ab64890Smrg
13731ab64890Smrg    *from = (XPointer) src;
13741ab64890Smrg    *from_left = srcend - src;
13751ab64890Smrg    *to = (XPointer) dst;
13761ab64890Smrg    *to_left = dstend - dst;
13771ab64890Smrg
13781ab64890Smrg    return unconv_num;
13791ab64890Smrg}
13801ab64890Smrg
13811ab64890Smrgstatic XlcConvMethodsRec methods_wcstostr = {
13821ab64890Smrg    close_converter,
13831ab64890Smrg    our_wcstostr,
13841ab64890Smrg    NULL
13851ab64890Smrg};
13861ab64890Smrg
13871ab64890Smrgstatic XlcConv
13881ab64890Smrgopen_wcstostr(
13891ab64890Smrg    XLCd from_lcd,
13901ab64890Smrg    const char *from_type,
13911ab64890Smrg    XLCd to_lcd,
13921ab64890Smrg    const char *to_type)
13931ab64890Smrg{
13941ab64890Smrg    return create_conv(from_lcd, &methods_wcstostr);
13951ab64890Smrg}
13961ab64890Smrg
13971ab64890Smrg/* from XlcNCharSet to XlcNWideChar */
13981ab64890Smrg
13991ab64890Smrgstatic int
14001ab64890Smrgcstowcs(
14011ab64890Smrg    XlcConv conv,
14021ab64890Smrg    XPointer *from,
14031ab64890Smrg    int *from_left,
14041ab64890Smrg    XPointer *to,
14051ab64890Smrg    int *to_left,
14061ab64890Smrg    XPointer *args,
14071ab64890Smrg    int num_args)
14081ab64890Smrg{
14091ab64890Smrg    XlcCharSet charset;
14101ab64890Smrg    const char *name;
14111ab64890Smrg    Utf8Conv convptr;
14121ab64890Smrg    int i;
14131ab64890Smrg    unsigned char const *src;
14141ab64890Smrg    unsigned char const *srcend;
14151ab64890Smrg    wchar_t *dst;
14161ab64890Smrg    wchar_t *dstend;
14171ab64890Smrg    int unconv_num;
14181ab64890Smrg
14191ab64890Smrg    if (from == NULL || *from == NULL)
14201ab64890Smrg	return 0;
14211ab64890Smrg
14221ab64890Smrg    if (num_args < 1)
14231ab64890Smrg	return -1;
14241ab64890Smrg
14251ab64890Smrg    charset = (XlcCharSet) args[0];
14261ab64890Smrg    name = charset->encoding_name;
14271ab64890Smrg    /* not charset->name because the latter has a ":GL"/":GR" suffix */
14281ab64890Smrg
14291ab64890Smrg    for (convptr = all_charsets, i = all_charsets_count-1; i > 0; convptr++, i--)
14301ab64890Smrg	if (!strcmp(convptr->name, name))
14311ab64890Smrg	    break;
14321ab64890Smrg    if (i == 0)
14331ab64890Smrg	return -1;
14341ab64890Smrg
14351ab64890Smrg    src = (unsigned char const *) *from;
14361ab64890Smrg    srcend = src + *from_left;
14371ab64890Smrg    dst = (wchar_t *) *to;
14381ab64890Smrg    dstend = dst + *to_left;
14391ab64890Smrg    unconv_num = 0;
14401ab64890Smrg
14411ab64890Smrg    while (src < srcend && dst < dstend) {
14421ab64890Smrg	unsigned int wc;
14431ab64890Smrg	int consumed;
14441ab64890Smrg
14451ab64890Smrg	consumed = convptr->cstowc(conv, &wc, src, srcend-src);
14461ab64890Smrg	if (consumed == RET_ILSEQ)
14471ab64890Smrg	    return -1;
14481ab64890Smrg	if (consumed == RET_TOOFEW(0))
14491ab64890Smrg	    break;
14501ab64890Smrg
14511ab64890Smrg	*dst++ = wc;
14521ab64890Smrg	src += consumed;
14531ab64890Smrg    }
14541ab64890Smrg
14551ab64890Smrg    *from = (XPointer) src;
14561ab64890Smrg    *from_left = srcend - src;
14571ab64890Smrg    *to = (XPointer) dst;
14581ab64890Smrg    *to_left = dstend - dst;
14591ab64890Smrg
14601ab64890Smrg    return unconv_num;
14611ab64890Smrg}
14621ab64890Smrg
14631ab64890Smrgstatic XlcConvMethodsRec methods_cstowcs = {
14641ab64890Smrg    close_converter,
14651ab64890Smrg    cstowcs,
14661ab64890Smrg    NULL
14671ab64890Smrg};
14681ab64890Smrg
14691ab64890Smrgstatic XlcConv
14701ab64890Smrgopen_cstowcs(
14711ab64890Smrg    XLCd from_lcd,
14721ab64890Smrg    const char *from_type,
14731ab64890Smrg    XLCd to_lcd,
14741ab64890Smrg    const char *to_type)
14751ab64890Smrg{
14761ab64890Smrg    lazy_init_all_charsets();
14771ab64890Smrg    return create_conv(from_lcd, &methods_cstowcs);
14781ab64890Smrg}
14791ab64890Smrg
14801ab64890Smrg/* from XlcNWideChar to XlcNCharSet */
14811ab64890Smrg
14821ab64890Smrgstatic int
14831ab64890Smrgwcstocs(
14841ab64890Smrg    XlcConv conv,
14851ab64890Smrg    XPointer *from,
14861ab64890Smrg    int *from_left,
14871ab64890Smrg    XPointer *to,
14881ab64890Smrg    int *to_left,
14891ab64890Smrg    XPointer *args,
14901ab64890Smrg    int num_args)
14911ab64890Smrg{
14921ab64890Smrg    Utf8Conv *preferred_charsets;
14931ab64890Smrg    XlcCharSet last_charset = NULL;
14941ab64890Smrg    wchar_t const *src;
14951ab64890Smrg    wchar_t const *srcend;
14961ab64890Smrg    unsigned char *dst;
14971ab64890Smrg    unsigned char *dstend;
14981ab64890Smrg    int unconv_num;
14991ab64890Smrg
15001ab64890Smrg    if (from == NULL || *from == NULL)
15011ab64890Smrg	return 0;
15021ab64890Smrg
15031ab64890Smrg    preferred_charsets = (Utf8Conv *) conv->state;
15041ab64890Smrg    src = (wchar_t const *) *from;
15051ab64890Smrg    srcend = src + *from_left;
15061ab64890Smrg    dst = (unsigned char *) *to;
15071ab64890Smrg    dstend = dst + *to_left;
15081ab64890Smrg    unconv_num = 0;
15091ab64890Smrg
15101ab64890Smrg    while (src < srcend && dst < dstend) {
15111ab64890Smrg	Utf8Conv chosen_charset = NULL;
15121ab64890Smrg	XlcSide chosen_side = XlcNONE;
15131ab64890Smrg	wchar_t wc = *src;
15141ab64890Smrg	int count;
15151ab64890Smrg
15161ab64890Smrg	count = charset_wctocs(preferred_charsets, &chosen_charset, &chosen_side, conv, dst, wc, dstend-dst);
15171ab64890Smrg	if (count == RET_TOOSMALL)
15181ab64890Smrg	    break;
15191ab64890Smrg	if (count == RET_ILSEQ) {
15201ab64890Smrg	    src++;
15211ab64890Smrg	    unconv_num++;
15221ab64890Smrg	    continue;
15231ab64890Smrg	}
15241ab64890Smrg
15251ab64890Smrg	if (last_charset == NULL) {
15261ab64890Smrg	    last_charset =
15271ab64890Smrg	        _XlcGetCharSetWithSide(chosen_charset->name, chosen_side);
15281ab64890Smrg	    if (last_charset == NULL) {
15291ab64890Smrg		src++;
15301ab64890Smrg		unconv_num++;
15311ab64890Smrg		continue;
15321ab64890Smrg	    }
15331ab64890Smrg	} else {
15341ab64890Smrg	    if (!(last_charset->xrm_encoding_name == chosen_charset->xrm_name
15351ab64890Smrg	          && (last_charset->side == XlcGLGR
15361ab64890Smrg	              || last_charset->side == chosen_side)))
15371ab64890Smrg		break;
15381ab64890Smrg	}
15391ab64890Smrg	src++;
15401ab64890Smrg	dst += count;
15411ab64890Smrg    }
15421ab64890Smrg
15431ab64890Smrg    if (last_charset == NULL)
15441ab64890Smrg	return -1;
15451ab64890Smrg
15461ab64890Smrg    *from = (XPointer) src;
15471ab64890Smrg    *from_left = srcend - src;
15481ab64890Smrg    *to = (XPointer) dst;
15491ab64890Smrg    *to_left = dstend - dst;
15501ab64890Smrg
15511ab64890Smrg    if (num_args >= 1)
15521ab64890Smrg	*((XlcCharSet *)args[0]) = last_charset;
15531ab64890Smrg
15541ab64890Smrg    return unconv_num;
15551ab64890Smrg}
15561ab64890Smrg
15571ab64890Smrgstatic XlcConvMethodsRec methods_wcstocs = {
15581ab64890Smrg    close_tocs_converter,
15591ab64890Smrg    wcstocs,
15601ab64890Smrg    NULL
15611ab64890Smrg};
15621ab64890Smrg
15631ab64890Smrgstatic XlcConv
15641ab64890Smrgopen_wcstocs(
15651ab64890Smrg    XLCd from_lcd,
15661ab64890Smrg    const char *from_type,
15671ab64890Smrg    XLCd to_lcd,
15681ab64890Smrg    const char *to_type)
15691ab64890Smrg{
15701ab64890Smrg    return create_tocs_conv(from_lcd, &methods_wcstocs);
15711ab64890Smrg}
15721ab64890Smrg
15731ab64890Smrg/* from XlcNWideChar to XlcNChar */
15741ab64890Smrg
15751ab64890Smrgstatic int
15761ab64890Smrgwcstocs1(
15771ab64890Smrg    XlcConv conv,
15781ab64890Smrg    XPointer *from,
15791ab64890Smrg    int *from_left,
15801ab64890Smrg    XPointer *to,
15811ab64890Smrg    int *to_left,
15821ab64890Smrg    XPointer *args,
15831ab64890Smrg    int num_args)
15841ab64890Smrg{
15851ab64890Smrg    Utf8Conv *preferred_charsets;
15861ab64890Smrg    XlcCharSet last_charset = NULL;
15871ab64890Smrg    wchar_t const *src;
15881ab64890Smrg    wchar_t const *srcend;
15891ab64890Smrg    unsigned char *dst;
15901ab64890Smrg    unsigned char *dstend;
15911ab64890Smrg    int unconv_num;
15921ab64890Smrg
15931ab64890Smrg    if (from == NULL || *from == NULL)
15941ab64890Smrg	return 0;
15951ab64890Smrg
15961ab64890Smrg    preferred_charsets = (Utf8Conv *) conv->state;
15971ab64890Smrg    src = (wchar_t const *) *from;
15981ab64890Smrg    srcend = src + *from_left;
15991ab64890Smrg    dst = (unsigned char *) *to;
16001ab64890Smrg    dstend = dst + *to_left;
16011ab64890Smrg    unconv_num = 0;
16021ab64890Smrg
16031ab64890Smrg    while (src < srcend && dst < dstend) {
16041ab64890Smrg	Utf8Conv chosen_charset = NULL;
16051ab64890Smrg	XlcSide chosen_side = XlcNONE;
16061ab64890Smrg	wchar_t wc = *src;
16071ab64890Smrg	int count;
16081ab64890Smrg
16091ab64890Smrg	count = charset_wctocs(preferred_charsets, &chosen_charset, &chosen_side, conv, dst, wc, dstend-dst);
16101ab64890Smrg	if (count == RET_TOOSMALL)
16111ab64890Smrg	    break;
16121ab64890Smrg	if (count == RET_ILSEQ) {
16131ab64890Smrg	    src++;
16141ab64890Smrg	    unconv_num++;
16151ab64890Smrg	    continue;
16161ab64890Smrg	}
16171ab64890Smrg
16181ab64890Smrg	if (last_charset == NULL) {
16191ab64890Smrg	    last_charset =
16201ab64890Smrg	        _XlcGetCharSetWithSide(chosen_charset->name, chosen_side);
16211ab64890Smrg	    if (last_charset == NULL) {
16221ab64890Smrg		src++;
16231ab64890Smrg		unconv_num++;
16241ab64890Smrg		continue;
16251ab64890Smrg	    }
16261ab64890Smrg	} else {
16271ab64890Smrg	    if (!(last_charset->xrm_encoding_name == chosen_charset->xrm_name
16281ab64890Smrg	          && (last_charset->side == XlcGLGR
16291ab64890Smrg	              || last_charset->side == chosen_side)))
16301ab64890Smrg		break;
16311ab64890Smrg	}
16321ab64890Smrg	src++;
16331ab64890Smrg	dst += count;
16341ab64890Smrg	break;
16351ab64890Smrg    }
16361ab64890Smrg
16371ab64890Smrg    if (last_charset == NULL)
16381ab64890Smrg	return -1;
16391ab64890Smrg
16401ab64890Smrg    *from = (XPointer) src;
16411ab64890Smrg    *from_left = srcend - src;
16421ab64890Smrg    *to = (XPointer) dst;
16431ab64890Smrg    *to_left = dstend - dst;
16441ab64890Smrg
16451ab64890Smrg    if (num_args >= 1)
16461ab64890Smrg	*((XlcCharSet *)args[0]) = last_charset;
16471ab64890Smrg
16481ab64890Smrg    return unconv_num;
16491ab64890Smrg}
16501ab64890Smrg
16511ab64890Smrgstatic XlcConvMethodsRec methods_wcstocs1 = {
16521ab64890Smrg    close_tocs_converter,
16531ab64890Smrg    wcstocs1,
16541ab64890Smrg    NULL
16551ab64890Smrg};
16561ab64890Smrg
16571ab64890Smrgstatic XlcConv
16581ab64890Smrgopen_wcstocs1(
16591ab64890Smrg    XLCd from_lcd,
16601ab64890Smrg    const char *from_type,
16611ab64890Smrg    XLCd to_lcd,
16621ab64890Smrg    const char *to_type)
16631ab64890Smrg{
16641ab64890Smrg    return create_tocs_conv(from_lcd, &methods_wcstocs1);
16651ab64890Smrg}
16661ab64890Smrg
16671ab64890Smrg/* trivial, no conversion */
16681ab64890Smrg
16691ab64890Smrgstatic int
16701ab64890Smrgidentity(
16711ab64890Smrg    XlcConv conv,
16721ab64890Smrg    XPointer *from,
16731ab64890Smrg    int *from_left,
16741ab64890Smrg    XPointer *to,
16751ab64890Smrg    int *to_left,
16761ab64890Smrg    XPointer *args,
16771ab64890Smrg    int num_args)
16781ab64890Smrg{
16791ab64890Smrg    unsigned char const *src;
16801ab64890Smrg    unsigned char const *srcend;
16811ab64890Smrg    unsigned char *dst;
16821ab64890Smrg    unsigned char *dstend;
16831ab64890Smrg
16841ab64890Smrg    if (from == NULL || *from == NULL)
16851ab64890Smrg	return 0;
16861ab64890Smrg
16871ab64890Smrg    src = (unsigned char const *) *from;
16881ab64890Smrg    srcend = src + *from_left;
16891ab64890Smrg    dst = (unsigned char *) *to;
16901ab64890Smrg    dstend = dst + *to_left;
16911ab64890Smrg
16921ab64890Smrg    while (src < srcend && dst < dstend)
16931ab64890Smrg	*dst++ = *src++;
16941ab64890Smrg
16951ab64890Smrg    *from = (XPointer) src;
16961ab64890Smrg    *from_left = srcend - src;
16971ab64890Smrg    *to = (XPointer) dst;
16981ab64890Smrg    *to_left = dstend - dst;
16991ab64890Smrg
17001ab64890Smrg    return 0;
17011ab64890Smrg}
17021ab64890Smrg
17031ab64890Smrgstatic XlcConvMethodsRec methods_identity = {
17041ab64890Smrg    close_converter,
17051ab64890Smrg    identity,
17061ab64890Smrg    NULL
17071ab64890Smrg};
17081ab64890Smrg
17091ab64890Smrgstatic XlcConv
17101ab64890Smrgopen_identity(
17111ab64890Smrg    XLCd from_lcd,
17121ab64890Smrg    const char *from_type,
17131ab64890Smrg    XLCd to_lcd,
17141ab64890Smrg    const char *to_type)
17151ab64890Smrg{
17161ab64890Smrg    return create_conv(from_lcd, &methods_identity);
17171ab64890Smrg}
17181ab64890Smrg
17191ab64890Smrg/* from MultiByte/WideChar to FontCharSet. */
17201ab64890Smrg/* They really use converters to CharSet
17211ab64890Smrg * but with different create_conv procedure. */
17221ab64890Smrg
17231ab64890Smrgstatic XlcConv
17241ab64890Smrgcreate_tofontcs_conv(
17251ab64890Smrg    XLCd lcd,
17261ab64890Smrg    XlcConvMethods methods)
17271ab64890Smrg{
17281ab64890Smrg    XlcConv conv;
17291ab64890Smrg    int i, num, k, count;
17301ab64890Smrg    char **value, buf[20];
17311ab64890Smrg    Utf8Conv *preferred;
17321ab64890Smrg
17331ab64890Smrg    lazy_init_all_charsets();
17341ab64890Smrg
17351ab64890Smrg    for (i = 0, num = 0;; i++) {
17361ab64890Smrg	sprintf(buf, "fs%d.charset.name", i);
17371ab64890Smrg	_XlcGetResource(lcd, "XLC_FONTSET", buf, &value, &count);
17381ab64890Smrg	if (count < 1) {
17391ab64890Smrg	    sprintf(buf, "fs%d.charset", i);
17401ab64890Smrg	    _XlcGetResource(lcd, "XLC_FONTSET", buf, &value, &count);
17411ab64890Smrg	    if (count < 1)
17421ab64890Smrg		break;
17431ab64890Smrg	}
17441ab64890Smrg	num += count;
17451ab64890Smrg    }
17461ab64890Smrg
17471ab64890Smrg    conv = (XlcConv) Xmalloc(sizeof(XlcConvRec) + (num + 1) * sizeof(Utf8Conv));
17481ab64890Smrg    if (conv == (XlcConv) NULL)
17491ab64890Smrg	return (XlcConv) NULL;
17501ab64890Smrg    preferred = (Utf8Conv *) ((char *) conv + sizeof(XlcConvRec));
17511ab64890Smrg
17521ab64890Smrg    /* Loop through all fontsets mentioned in the locale. */
17531ab64890Smrg    for (i = 0, num = 0;; i++) {
17541ab64890Smrg        sprintf(buf, "fs%d.charset.name", i);
17551ab64890Smrg        _XlcGetResource(lcd, "XLC_FONTSET", buf, &value, &count);
17561ab64890Smrg        if (count < 1) {
17571ab64890Smrg            sprintf(buf, "fs%d.charset", i);
17581ab64890Smrg            _XlcGetResource(lcd, "XLC_FONTSET", buf, &value, &count);
17591ab64890Smrg            if (count < 1)
17601ab64890Smrg                break;
17611ab64890Smrg        }
17621ab64890Smrg	while (count-- > 0) {
17631ab64890Smrg	    XlcCharSet charset = _XlcGetCharSet(*value++);
17641ab64890Smrg	    const char *name;
17651ab64890Smrg
17661ab64890Smrg	    if (charset == (XlcCharSet) NULL)
17671ab64890Smrg		continue;
17681ab64890Smrg
17691ab64890Smrg	    name = charset->encoding_name;
17701ab64890Smrg	    /* If it wasn't already encountered... */
17711ab64890Smrg	    for (k = num - 1; k >= 0; k--)
17721ab64890Smrg		if (!strcmp(preferred[k]->name, name))
17731ab64890Smrg		    break;
17741ab64890Smrg	    if (k < 0) {
17751ab64890Smrg                /* For fonts "ISO10646-1" means ucs2, not utf8.*/
17761ab64890Smrg                if (!strcmp("ISO10646-1", name)) {
17771ab64890Smrg                    preferred[num++] = &all_charsets[ucs2_conv_index];
17781ab64890Smrg                    continue;
17791ab64890Smrg                }
17801ab64890Smrg		/* Look it up in all_charsets[]. */
17811ab64890Smrg		for (k = 0; k < all_charsets_count-1; k++)
17821ab64890Smrg		    if (!strcmp(all_charsets[k].name, name)) {
17831ab64890Smrg			/* Add it to the preferred set. */
17841ab64890Smrg			preferred[num++] = &all_charsets[k];
17851ab64890Smrg			break;
17861ab64890Smrg		    }
17871ab64890Smrg	    }
17881ab64890Smrg        }
17891ab64890Smrg    }
17901ab64890Smrg    preferred[num] = (Utf8Conv) NULL;
17911ab64890Smrg
17921ab64890Smrg    conv->methods = methods;
17931ab64890Smrg    conv->state = (XPointer) preferred;
17941ab64890Smrg
17951ab64890Smrg    return conv;
17961ab64890Smrg}
17971ab64890Smrg
17981ab64890Smrgstatic XlcConv
17991ab64890Smrgopen_wcstofcs(
18001ab64890Smrg    XLCd from_lcd,
18011ab64890Smrg    const char *from_type,
18021ab64890Smrg    XLCd to_lcd,
18031ab64890Smrg    const char *to_type)
18041ab64890Smrg{
18051ab64890Smrg    return create_tofontcs_conv(from_lcd, &methods_wcstocs);
18061ab64890Smrg}
18071ab64890Smrg
18081ab64890Smrgstatic XlcConv
18091ab64890Smrgopen_utf8tofcs(
18101ab64890Smrg    XLCd from_lcd,
18111ab64890Smrg    const char *from_type,
18121ab64890Smrg    XLCd to_lcd,
18131ab64890Smrg    const char *to_type)
18141ab64890Smrg{
18151ab64890Smrg    return create_tofontcs_conv(from_lcd, &methods_utf8tocs);
18161ab64890Smrg}
18171ab64890Smrg
181861b2299dSmrg/* ========================== iconv Stuff ================================ */
181961b2299dSmrg
182061b2299dSmrg/* from XlcNCharSet to XlcNMultiByte */
182161b2299dSmrg
182261b2299dSmrgstatic int
182361b2299dSmrgiconv_cstombs(XlcConv conv, XPointer *from, int *from_left,
182461b2299dSmrg	      XPointer *to, int *to_left, XPointer *args, int num_args)
182561b2299dSmrg{
182661b2299dSmrg    XlcCharSet charset;
182761b2299dSmrg    char *name;
182861b2299dSmrg    Utf8Conv convptr;
182961b2299dSmrg    int i;
183061b2299dSmrg    unsigned char const *src;
183161b2299dSmrg    unsigned char const *srcend;
183261b2299dSmrg    unsigned char *dst;
183361b2299dSmrg    unsigned char *dstend;
183461b2299dSmrg    int unconv_num;
183561b2299dSmrg
183661b2299dSmrg    if (from == NULL || *from == NULL)
183761b2299dSmrg	return 0;
183861b2299dSmrg
183961b2299dSmrg    if (num_args < 1)
184061b2299dSmrg	return -1;
184161b2299dSmrg
184261b2299dSmrg    charset = (XlcCharSet) args[0];
184361b2299dSmrg    name = charset->encoding_name;
184461b2299dSmrg    /* not charset->name because the latter has a ":GL"/":GR" suffix */
184561b2299dSmrg
184661b2299dSmrg    for (convptr = all_charsets, i = all_charsets_count-1; i > 0; convptr++, i--)
184761b2299dSmrg	if (!strcmp(convptr->name, name))
184861b2299dSmrg	    break;
184961b2299dSmrg    if (i == 0)
185061b2299dSmrg	return -1;
185161b2299dSmrg
185261b2299dSmrg    src = (unsigned char const *) *from;
185361b2299dSmrg    srcend = src + *from_left;
185461b2299dSmrg    dst = (unsigned char *) *to;
185561b2299dSmrg    dstend = dst + *to_left;
185661b2299dSmrg    unconv_num = 0;
185761b2299dSmrg
185861b2299dSmrg    while (src < srcend) {
185961b2299dSmrg	ucs4_t wc;
186061b2299dSmrg	int consumed;
186161b2299dSmrg	int count;
186261b2299dSmrg
186361b2299dSmrg	consumed = convptr->cstowc(conv, &wc, src, srcend-src);
186461b2299dSmrg	if (consumed == RET_ILSEQ)
186561b2299dSmrg	    return -1;
186661b2299dSmrg	if (consumed == RET_TOOFEW(0))
186761b2299dSmrg	    break;
186861b2299dSmrg
186961b2299dSmrg    /* Use stdc iconv to convert widechar -> multibyte */
187061b2299dSmrg
187161b2299dSmrg	count = wctomb(dst, wc);
187261b2299dSmrg	if (count == 0)
187361b2299dSmrg	    break;
187461b2299dSmrg	if (count == -1) {
187561b2299dSmrg	    count = wctomb(dst, BAD_WCHAR);
187661b2299dSmrg	    if (count == 0)
187761b2299dSmrg		break;
187861b2299dSmrg	    unconv_num++;
187961b2299dSmrg	}
188061b2299dSmrg	src += consumed;
188161b2299dSmrg	dst += count;
188261b2299dSmrg    }
188361b2299dSmrg
188461b2299dSmrg    *from = (XPointer) src;
188561b2299dSmrg    *from_left = srcend - src;
188661b2299dSmrg    *to = (XPointer) dst;
188761b2299dSmrg    *to_left = dstend - dst;
188861b2299dSmrg
188961b2299dSmrg    return unconv_num;
189061b2299dSmrg
189161b2299dSmrg}
189261b2299dSmrg
189361b2299dSmrgstatic XlcConvMethodsRec iconv_cstombs_methods = {
189461b2299dSmrg    close_converter,
189561b2299dSmrg    iconv_cstombs,
189661b2299dSmrg    NULL
189761b2299dSmrg};
189861b2299dSmrg
189961b2299dSmrgstatic XlcConv
190061b2299dSmrgopen_iconv_cstombs(XLCd from_lcd, char *from_type, XLCd to_lcd, char *to_type)
190161b2299dSmrg{
190261b2299dSmrg    lazy_init_all_charsets();
190361b2299dSmrg    return create_conv(from_lcd, &iconv_cstombs_methods);
190461b2299dSmrg}
190561b2299dSmrg
190661b2299dSmrgstatic int
190761b2299dSmrgiconv_mbstocs(XlcConv conv, XPointer *from, int *from_left,
190861b2299dSmrg	      XPointer *to, int *to_left, XPointer *args, int num_args)
190961b2299dSmrg{
191061b2299dSmrg    Utf8Conv *preferred_charsets;
191161b2299dSmrg    XlcCharSet last_charset = NULL;
191261b2299dSmrg    unsigned char const *src;
191361b2299dSmrg    unsigned char const *srcend;
191461b2299dSmrg    unsigned char *dst;
191561b2299dSmrg    unsigned char *dstend;
191661b2299dSmrg    int unconv_num;
191761b2299dSmrg
191861b2299dSmrg    if (from == NULL || *from == NULL)
191961b2299dSmrg	return 0;
192061b2299dSmrg
192161b2299dSmrg    preferred_charsets = (Utf8Conv *) conv->state;
192261b2299dSmrg    src = (unsigned char const *) *from;
192361b2299dSmrg    srcend = src + *from_left;
192461b2299dSmrg    dst = (unsigned char *) *to;
192561b2299dSmrg    dstend = dst + *to_left;
192661b2299dSmrg    unconv_num = 0;
192761b2299dSmrg
192861b2299dSmrg    while (src < srcend && dst < dstend) {
192961b2299dSmrg	Utf8Conv chosen_charset = NULL;
193061b2299dSmrg	XlcSide chosen_side = XlcNONE;
193161b2299dSmrg	wchar_t wc;
193261b2299dSmrg	int consumed;
193361b2299dSmrg	int count;
193461b2299dSmrg
193561b2299dSmrg    /* Uses stdc iconv to convert multibyte -> widechar */
193661b2299dSmrg
193761b2299dSmrg	consumed = mbtowc(&wc, src, srcend-src);
193861b2299dSmrg	if (consumed == 0)
193961b2299dSmrg	    break;
194061b2299dSmrg	if (consumed == -1) {
194161b2299dSmrg	    src++;
194261b2299dSmrg	    unconv_num++;
194361b2299dSmrg	    continue;
194461b2299dSmrg	}
194561b2299dSmrg
194661b2299dSmrg	count = charset_wctocs(preferred_charsets, &chosen_charset, &chosen_side, conv, dst, wc, dstend-dst);
194761b2299dSmrg
194861b2299dSmrg	if (count == RET_TOOSMALL)
194961b2299dSmrg	    break;
195061b2299dSmrg	if (count == RET_ILSEQ) {
195161b2299dSmrg	    src += consumed;
195261b2299dSmrg	    unconv_num++;
195361b2299dSmrg	    continue;
195461b2299dSmrg	}
195561b2299dSmrg
195661b2299dSmrg	if (last_charset == NULL) {
195761b2299dSmrg	    last_charset =
195861b2299dSmrg	        _XlcGetCharSetWithSide(chosen_charset->name, chosen_side);
195961b2299dSmrg	    if (last_charset == NULL) {
196061b2299dSmrg		src += consumed;
196161b2299dSmrg		unconv_num++;
196261b2299dSmrg		continue;
196361b2299dSmrg	    }
196461b2299dSmrg	} else {
196561b2299dSmrg	    if (!(last_charset->xrm_encoding_name == chosen_charset->xrm_name
196661b2299dSmrg	          && (last_charset->side == XlcGLGR
196761b2299dSmrg	              || last_charset->side == chosen_side)))
196861b2299dSmrg		break;
196961b2299dSmrg	}
197061b2299dSmrg	src += consumed;
197161b2299dSmrg	dst += count;
197261b2299dSmrg    }
197361b2299dSmrg
197461b2299dSmrg    if (last_charset == NULL)
197561b2299dSmrg	return -1;
197661b2299dSmrg
197761b2299dSmrg    *from = (XPointer) src;
197861b2299dSmrg    *from_left = srcend - src;
197961b2299dSmrg    *to = (XPointer) dst;
198061b2299dSmrg    *to_left = dstend - dst;
198161b2299dSmrg
198261b2299dSmrg    if (num_args >= 1)
198361b2299dSmrg	*((XlcCharSet *)args[0]) = last_charset;
198461b2299dSmrg
198561b2299dSmrg    return unconv_num;
198661b2299dSmrg}
198761b2299dSmrg
198861b2299dSmrgstatic XlcConvMethodsRec iconv_mbstocs_methods = {
198961b2299dSmrg    close_tocs_converter,
199061b2299dSmrg    iconv_mbstocs,
199161b2299dSmrg    NULL
199261b2299dSmrg};
199361b2299dSmrg
199461b2299dSmrgstatic XlcConv
199561b2299dSmrgopen_iconv_mbstocs(XLCd from_lcd, char *from_type, XLCd to_lcd, char *to_type)
199661b2299dSmrg{
199761b2299dSmrg    return create_tocs_conv(from_lcd, &iconv_mbstocs_methods);
199861b2299dSmrg}
199961b2299dSmrg
200061b2299dSmrg/* from XlcNMultiByte to XlcNChar */
200161b2299dSmrg
200261b2299dSmrgstatic int
200361b2299dSmrgiconv_mbtocs(XlcConv conv, XPointer *from, int *from_left,
200461b2299dSmrg	     XPointer *to, int *to_left, XPointer *args, int num_args)
200561b2299dSmrg{
200661b2299dSmrg    Utf8Conv *preferred_charsets;
200761b2299dSmrg    XlcCharSet last_charset = NULL;
200861b2299dSmrg    unsigned char const *src;
200961b2299dSmrg    unsigned char const *srcend;
201061b2299dSmrg    unsigned char *dst;
201161b2299dSmrg    unsigned char *dstend;
201261b2299dSmrg    int unconv_num;
201361b2299dSmrg
201461b2299dSmrg    if (from == NULL || *from == NULL)
201561b2299dSmrg	return 0;
201661b2299dSmrg
201761b2299dSmrg    preferred_charsets = (Utf8Conv *) conv->state;
201861b2299dSmrg    src = (unsigned char const *) *from;
201961b2299dSmrg    srcend = src + *from_left;
202061b2299dSmrg    dst = (unsigned char *) *to;
202161b2299dSmrg    dstend = dst + *to_left;
202261b2299dSmrg    unconv_num = 0;
202361b2299dSmrg
202461b2299dSmrg    while (src < srcend && dst < dstend) {
202561b2299dSmrg	Utf8Conv chosen_charset = NULL;
202661b2299dSmrg	XlcSide chosen_side = XlcNONE;
202761b2299dSmrg	wchar_t wc;
202861b2299dSmrg	int consumed;
202961b2299dSmrg	int count;
203061b2299dSmrg
203161b2299dSmrg    /* Uses stdc iconv to convert multibyte -> widechar */
203261b2299dSmrg
203361b2299dSmrg	consumed = mbtowc(&wc, src, srcend-src);
203461b2299dSmrg	if (consumed == 0)
203561b2299dSmrg	    break;
203661b2299dSmrg	if (consumed == -1) {
203761b2299dSmrg	    src++;
203861b2299dSmrg	    unconv_num++;
203961b2299dSmrg	    continue;
204061b2299dSmrg	}
204161b2299dSmrg
204261b2299dSmrg	count = charset_wctocs(preferred_charsets, &chosen_charset, &chosen_side, conv, dst, wc, dstend-dst);
204361b2299dSmrg	if (count == RET_TOOSMALL)
204461b2299dSmrg	    break;
204561b2299dSmrg	if (count == RET_ILSEQ) {
204661b2299dSmrg	    src += consumed;
204761b2299dSmrg	    unconv_num++;
204861b2299dSmrg	    continue;
204961b2299dSmrg	}
205061b2299dSmrg
205161b2299dSmrg	if (last_charset == NULL) {
205261b2299dSmrg	    last_charset =
205361b2299dSmrg		_XlcGetCharSetWithSide(chosen_charset->name, chosen_side);
205461b2299dSmrg	    if (last_charset == NULL) {
205561b2299dSmrg		src += consumed;
205661b2299dSmrg		unconv_num++;
205761b2299dSmrg		continue;
205861b2299dSmrg	    }
205961b2299dSmrg	} else {
206061b2299dSmrg	    if (!(last_charset->xrm_encoding_name == chosen_charset->xrm_name
206161b2299dSmrg		  && (last_charset->side == XlcGLGR
206261b2299dSmrg		      || last_charset->side == chosen_side)))
206361b2299dSmrg		break;
206461b2299dSmrg	}
206561b2299dSmrg	src += consumed;
206661b2299dSmrg	dst += count;
206761b2299dSmrg    }
206861b2299dSmrg
206961b2299dSmrg    if (last_charset == NULL)
207061b2299dSmrg	return -1;
207161b2299dSmrg
207261b2299dSmrg    *from = (XPointer) src;
207361b2299dSmrg    *from_left = srcend - src;
207461b2299dSmrg    *to = (XPointer) dst;
207561b2299dSmrg    *to_left = dstend - dst;
207661b2299dSmrg
207761b2299dSmrg    if (num_args >= 1)
207861b2299dSmrg	*((XlcCharSet *)args[0]) = last_charset;
207961b2299dSmrg
208061b2299dSmrg    return unconv_num;
208161b2299dSmrg}
208261b2299dSmrg
208361b2299dSmrgstatic XlcConvMethodsRec iconv_mbtocs_methods = {
208461b2299dSmrg    close_tocs_converter,
208561b2299dSmrg    iconv_mbtocs,
208661b2299dSmrg    NULL
208761b2299dSmrg};
208861b2299dSmrg
208961b2299dSmrgstatic XlcConv
209061b2299dSmrgopen_iconv_mbtocs(XLCd from_lcd, char *from_type, XLCd to_lcd, char *to_type)
209161b2299dSmrg{
209261b2299dSmrg    return create_tocs_conv(from_lcd, &iconv_mbtocs_methods );
209361b2299dSmrg}
209461b2299dSmrg
209561b2299dSmrg/* from XlcNMultiByte to XlcNString */
209661b2299dSmrg
209761b2299dSmrgstatic int
209861b2299dSmrgiconv_mbstostr(XlcConv conv, XPointer *from, int *from_left,
209961b2299dSmrg	       XPointer *to, int *to_left, XPointer *args, int num_args)
210061b2299dSmrg{
210161b2299dSmrg    unsigned char const *src;
210261b2299dSmrg    unsigned char const *srcend;
210361b2299dSmrg    unsigned char *dst;
210461b2299dSmrg    unsigned char *dstend;
210561b2299dSmrg    int unconv_num;
210661b2299dSmrg
210761b2299dSmrg    if (from == NULL || *from == NULL)
210861b2299dSmrg	return 0;
210961b2299dSmrg
211061b2299dSmrg    src = (unsigned char const *) *from;
211161b2299dSmrg    srcend = src + *from_left;
211261b2299dSmrg    dst = (unsigned char *) *to;
211361b2299dSmrg    dstend = dst + *to_left;
211461b2299dSmrg    unconv_num = 0;
211561b2299dSmrg
211661b2299dSmrg    while (src < srcend) {
211761b2299dSmrg	unsigned char c;
211861b2299dSmrg	wchar_t wc;
211961b2299dSmrg	int consumed;
212061b2299dSmrg
212161b2299dSmrg    /* Uses stdc iconv to convert multibyte -> widechar */
212261b2299dSmrg
212361b2299dSmrg	consumed = mbtowc(&wc, src, srcend-src);
212461b2299dSmrg	if (consumed == 0)
212561b2299dSmrg	    break;
212661b2299dSmrg	if (dst == dstend)
212761b2299dSmrg	    break;
212861b2299dSmrg	if (consumed == -1) {
212961b2299dSmrg	    consumed = 1;
213061b2299dSmrg	    c = BAD_CHAR;
213161b2299dSmrg	    unconv_num++;
213261b2299dSmrg	} else {
213361b2299dSmrg	    if ((wc & ~(wchar_t)0xff) != 0) {
213461b2299dSmrg		c = BAD_CHAR;
213561b2299dSmrg		unconv_num++;
213661b2299dSmrg	    } else
213761b2299dSmrg		c = (unsigned char) wc;
213861b2299dSmrg	}
213961b2299dSmrg	*dst++ = c;
214061b2299dSmrg	src += consumed;
214161b2299dSmrg    }
214261b2299dSmrg
214361b2299dSmrg    *from = (XPointer) src;
214461b2299dSmrg    *from_left = srcend - src;
214561b2299dSmrg    *to = (XPointer) dst;
214661b2299dSmrg    *to_left = dstend - dst;
214761b2299dSmrg
214861b2299dSmrg    return unconv_num;
214961b2299dSmrg}
215061b2299dSmrg
215161b2299dSmrgstatic XlcConvMethodsRec iconv_mbstostr_methods = {
215261b2299dSmrg    close_converter,
215361b2299dSmrg    iconv_mbstostr,
215461b2299dSmrg    NULL
215561b2299dSmrg};
215661b2299dSmrg
215761b2299dSmrgstatic XlcConv
215861b2299dSmrgopen_iconv_mbstostr(XLCd from_lcd, char *from_type, XLCd to_lcd, char *to_type)
215961b2299dSmrg{
216061b2299dSmrg    return create_conv(from_lcd, &iconv_mbstostr_methods);
216161b2299dSmrg}
216261b2299dSmrg
216361b2299dSmrg/* from XlcNString to XlcNMultiByte */
216461b2299dSmrgstatic int
216561b2299dSmrgiconv_strtombs(XlcConv conv, XPointer *from, int *from_left,
216661b2299dSmrg	       XPointer *to, int *to_left, XPointer *args, int num_args)
216761b2299dSmrg{
216861b2299dSmrg    unsigned char const *src;
216961b2299dSmrg    unsigned char const *srcend;
217061b2299dSmrg    unsigned char *dst;
217161b2299dSmrg    unsigned char *dstend;
217261b2299dSmrg
217361b2299dSmrg    if (from == NULL || *from == NULL)
217461b2299dSmrg	return 0;
217561b2299dSmrg
217661b2299dSmrg    src = (unsigned char const *) *from;
217761b2299dSmrg    srcend = src + *from_left;
217861b2299dSmrg    dst = (unsigned char *) *to;
217961b2299dSmrg    dstend = dst + *to_left;
218061b2299dSmrg
218161b2299dSmrg    while (src < srcend) {
218261b2299dSmrg	int count = wctomb(dst, *src);
218361b2299dSmrg	if (count < 0)
218461b2299dSmrg	    break;
218561b2299dSmrg	dst += count;
218661b2299dSmrg	src++;
218761b2299dSmrg    }
218861b2299dSmrg
218961b2299dSmrg    *from = (XPointer) src;
219061b2299dSmrg    *from_left = srcend - src;
219161b2299dSmrg    *to = (XPointer) dst;
219261b2299dSmrg    *to_left = dstend - dst;
219361b2299dSmrg
219461b2299dSmrg    return 0;
219561b2299dSmrg}
219661b2299dSmrg
219761b2299dSmrgstatic XlcConvMethodsRec iconv_strtombs_methods= {
219861b2299dSmrg    close_converter,
219961b2299dSmrg    iconv_strtombs,
220061b2299dSmrg    NULL
220161b2299dSmrg};
220261b2299dSmrg
220361b2299dSmrgstatic XlcConv
220461b2299dSmrgopen_iconv_strtombs(XLCd from_lcd, char *from_type, XLCd to_lcd, char *to_type)
220561b2299dSmrg{
220661b2299dSmrg    return create_conv(from_lcd, &iconv_strtombs_methods);
220761b2299dSmrg}
220861b2299dSmrg
220961b2299dSmrg/***************************************************************************/
221061b2299dSmrg/* Part II: An iconv locale loader.
221161b2299dSmrg *
221261b2299dSmrg *Here we can assume that "multi-byte" is iconv and that `wchar_t' is Unicode.
221361b2299dSmrg */
221461b2299dSmrg
221561b2299dSmrg/* from XlcNMultiByte to XlcNWideChar */
221661b2299dSmrgstatic int
221761b2299dSmrgiconv_mbstowcs(XlcConv conv, XPointer *from, int *from_left,
221861b2299dSmrg	       XPointer *to, int *to_left, XPointer *args,  int num_args)
221961b2299dSmrg{
222061b2299dSmrg    char *src = *((char **) from);
222161b2299dSmrg    wchar_t *dst = *((wchar_t **) to);
222261b2299dSmrg    int src_left = *from_left;
222361b2299dSmrg    int dst_left = *to_left;
222461b2299dSmrg    int length, unconv_num = 0;
222561b2299dSmrg
222661b2299dSmrg    while (src_left > 0 && dst_left > 0) {
222761b2299dSmrg	length = mbtowc(dst, src, src_left);
222861b2299dSmrg
222961b2299dSmrg	if (length > 0) {
223061b2299dSmrg	    src += length;
223161b2299dSmrg	    src_left -= length;
223261b2299dSmrg	    if (dst)
223361b2299dSmrg	        dst++;
223461b2299dSmrg	    dst_left--;
223561b2299dSmrg	} else if (length < 0) {
223661b2299dSmrg	    src++;
223761b2299dSmrg	    src_left--;
223861b2299dSmrg	    unconv_num++;
223961b2299dSmrg        } else {
224061b2299dSmrg            /* null ? */
224161b2299dSmrg            src++;
224261b2299dSmrg            src_left--;
224361b2299dSmrg            if (dst)
224461b2299dSmrg                *dst++ = L'\0';
224561b2299dSmrg            dst_left--;
224661b2299dSmrg        }
224761b2299dSmrg    }
224861b2299dSmrg
224961b2299dSmrg    *from = (XPointer) src;
225061b2299dSmrg    if (dst)
225161b2299dSmrg	*to = (XPointer) dst;
225261b2299dSmrg    *from_left = src_left;
225361b2299dSmrg    *to_left = dst_left;
225461b2299dSmrg
225561b2299dSmrg    return unconv_num;
225661b2299dSmrg}
225761b2299dSmrg
225861b2299dSmrgstatic XlcConvMethodsRec iconv_mbstowcs_methods = {
225961b2299dSmrg    close_converter,
226061b2299dSmrg    iconv_mbstowcs,
226161b2299dSmrg    NULL
226261b2299dSmrg} ;
226361b2299dSmrg
226461b2299dSmrgstatic XlcConv
226561b2299dSmrgopen_iconv_mbstowcs(XLCd from_lcd, char *from_type, XLCd to_lcd, char *to_type)
226661b2299dSmrg{
226761b2299dSmrg    return create_conv(from_lcd, &iconv_mbstowcs_methods);
226861b2299dSmrg}
226961b2299dSmrg
227061b2299dSmrgstatic int
227161b2299dSmrgiconv_wcstombs(XlcConv conv, XPointer *from, int *from_left,
227261b2299dSmrg	       XPointer *to, int *to_left, XPointer *args, int num_args)
227361b2299dSmrg{
227461b2299dSmrg    wchar_t *src = *((wchar_t **) from);
227561b2299dSmrg    char *dst = *((char **) to);
227661b2299dSmrg    int src_left = *from_left;
227761b2299dSmrg    int dst_left = *to_left;
227861b2299dSmrg    int length, unconv_num = 0;
227961b2299dSmrg
228061b2299dSmrg    while (src_left > 0 && dst_left >= MB_CUR_MAX) {
228161b2299dSmrg	length = wctomb(dst, *src);		/* XXX */
228261b2299dSmrg
228361b2299dSmrg        if (length > 0) {
228461b2299dSmrg	    src++;
228561b2299dSmrg	    src_left--;
228661b2299dSmrg	    if (dst)
228761b2299dSmrg		dst += length;
228861b2299dSmrg	    dst_left -= length;
228961b2299dSmrg	} else if (length < 0) {
229061b2299dSmrg	    src++;
229161b2299dSmrg	    src_left--;
229261b2299dSmrg	    unconv_num++;
229361b2299dSmrg	}
229461b2299dSmrg    }
229561b2299dSmrg
229661b2299dSmrg    *from = (XPointer) src;
229761b2299dSmrg    if (dst)
229861b2299dSmrg      *to = (XPointer) dst;
229961b2299dSmrg    *from_left = src_left;
230061b2299dSmrg    *to_left = dst_left;
230161b2299dSmrg
230261b2299dSmrg    return unconv_num;
230361b2299dSmrg}
230461b2299dSmrg
230561b2299dSmrgstatic XlcConvMethodsRec iconv_wcstombs_methods = {
230661b2299dSmrg    close_converter,
230761b2299dSmrg    iconv_wcstombs,
230861b2299dSmrg    NULL
230961b2299dSmrg} ;
231061b2299dSmrg
231161b2299dSmrgstatic XlcConv
231261b2299dSmrgopen_iconv_wcstombs(XLCd from_lcd, char *from_type, XLCd to_lcd, char *to_type)
231361b2299dSmrg{
231461b2299dSmrg    return create_conv(from_lcd, &iconv_wcstombs_methods);
231561b2299dSmrg}
231661b2299dSmrg
231761b2299dSmrgstatic XlcConv
231861b2299dSmrgopen_iconv_mbstofcs(
231961b2299dSmrg    XLCd from_lcd,
232061b2299dSmrg    const char *from_type,
232161b2299dSmrg    XLCd to_lcd,
232261b2299dSmrg    const char *to_type)
232361b2299dSmrg{
232461b2299dSmrg    return create_tofontcs_conv(from_lcd, &iconv_mbstocs_methods);
232561b2299dSmrg}
232661b2299dSmrg
23271ab64890Smrg/* Registers UTF-8 converters for a UTF-8 locale. */
23281ab64890Smrg
23291ab64890Smrgvoid
23301ab64890Smrg_XlcAddUtf8LocaleConverters(
23311ab64890Smrg    XLCd lcd)
23321ab64890Smrg{
23331ab64890Smrg    /* Register elementary converters. */
23341ab64890Smrg
23351ab64890Smrg    _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNWideChar, open_utf8towcs);
23361ab64890Smrg
23371ab64890Smrg    _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNMultiByte, open_wcstoutf8);
23381ab64890Smrg    _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNString, open_wcstostr);
23391ab64890Smrg
23401ab64890Smrg    _XlcSetConverter(lcd, XlcNString, lcd, XlcNWideChar, open_strtowcs);
23411ab64890Smrg
23421ab64890Smrg    /* Register converters for XlcNCharSet. This implicitly provides
23431ab64890Smrg     * converters from and to XlcNCompoundText. */
23441ab64890Smrg
23451ab64890Smrg    _XlcSetConverter(lcd, XlcNCharSet, lcd, XlcNMultiByte, open_cstoutf8);
23461ab64890Smrg    _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNCharSet, open_utf8tocs);
23471ab64890Smrg    _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNChar, open_utf8tocs1);
23481ab64890Smrg
23491ab64890Smrg    _XlcSetConverter(lcd, XlcNCharSet, lcd, XlcNWideChar, open_cstowcs);
23501ab64890Smrg    _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNCharSet, open_wcstocs);
23511ab64890Smrg    _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNChar, open_wcstocs1);
23521ab64890Smrg
23531ab64890Smrg    _XlcSetConverter(lcd, XlcNString, lcd, XlcNMultiByte, open_strtoutf8);
23541ab64890Smrg    _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNString, open_utf8tostr);
23551ab64890Smrg    _XlcSetConverter(lcd, XlcNUtf8String, lcd, XlcNMultiByte, open_identity);
23561ab64890Smrg    _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNUtf8String, open_identity);
23571ab64890Smrg
23581ab64890Smrg    /* Register converters for XlcNFontCharSet */
23591ab64890Smrg    _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNFontCharSet, open_utf8tofcs);
23601ab64890Smrg    _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNFontCharSet, open_wcstofcs);
23611ab64890Smrg}
236261b2299dSmrg
236361b2299dSmrgvoid
236461b2299dSmrg_XlcAddGB18030LocaleConverters(
236561b2299dSmrg    XLCd lcd)
236661b2299dSmrg{
236761b2299dSmrg
236861b2299dSmrg    /* Register elementary converters. */
236961b2299dSmrg    _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNWideChar, open_iconv_mbstowcs);
237061b2299dSmrg    _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNMultiByte, open_iconv_wcstombs);
237161b2299dSmrg
237261b2299dSmrg    /* Register converters for XlcNCharSet. This implicitly provides
237361b2299dSmrg     * converters from and to XlcNCompoundText. */
237461b2299dSmrg
237561b2299dSmrg    _XlcSetConverter(lcd, XlcNCharSet, lcd, XlcNMultiByte, open_iconv_cstombs);
237661b2299dSmrg    _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNCharSet, open_iconv_mbstocs);
237761b2299dSmrg    _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNChar, open_iconv_mbtocs);
237861b2299dSmrg    _XlcSetConverter(lcd, XlcNString, lcd, XlcNMultiByte, open_iconv_strtombs);
237961b2299dSmrg    _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNString, open_iconv_mbstostr);
238061b2299dSmrg
238161b2299dSmrg    /* Register converters for XlcNFontCharSet */
238261b2299dSmrg    _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNFontCharSet, open_iconv_mbstofcs);
238361b2299dSmrg
238461b2299dSmrg    _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNString, open_wcstostr);
238561b2299dSmrg    _XlcSetConverter(lcd, XlcNString, lcd, XlcNWideChar, open_strtowcs);
238661b2299dSmrg    _XlcSetConverter(lcd, XlcNCharSet, lcd, XlcNWideChar, open_cstowcs);
238761b2299dSmrg    _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNCharSet, open_wcstocs);
238861b2299dSmrg    _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNChar, open_wcstocs1);
238961b2299dSmrg
239061b2299dSmrg    /* Register converters for XlcNFontCharSet */
239161b2299dSmrg    _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNFontCharSet, open_wcstofcs);
239261b2299dSmrg}
2393