11ab64890Smrg/*
21ab64890Smrg * Copyright 1992, 1993 by TOSHIBA Corp.
31ab64890Smrg *
41ab64890Smrg * Permission to use, copy, modify, and distribute this software and its
51ab64890Smrg * documentation for any purpose and without fee is hereby granted, provided
61ab64890Smrg * that the above copyright notice appear in all copies and that both that
71ab64890Smrg * copyright notice and this permission notice appear in supporting
81ab64890Smrg * documentation, and that the name of TOSHIBA not be used in advertising
91ab64890Smrg * or publicity pertaining to distribution of the software without specific,
101ab64890Smrg * written prior permission. TOSHIBA make no representations about the
111ab64890Smrg * suitability of this software for any purpose.  It is provided "as is"
121ab64890Smrg * without express or implied warranty.
131ab64890Smrg *
141ab64890Smrg * TOSHIBA DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
151ab64890Smrg * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
161ab64890Smrg * TOSHIBA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
171ab64890Smrg * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
181ab64890Smrg * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
191ab64890Smrg * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
201ab64890Smrg * SOFTWARE.
211ab64890Smrg *
221ab64890Smrg * Author: Katsuhisa Yano	TOSHIBA Corp.
231ab64890Smrg *			   	mopi@osa.ilab.toshiba.co.jp
241ab64890Smrg */
251ab64890Smrg
261ab64890Smrg#ifdef HAVE_CONFIG_H
271ab64890Smrg#include <config.h>
281ab64890Smrg#endif
291ab64890Smrg#include "Xlibint.h"
301ab64890Smrg#include "XlcPubI.h"
311ab64890Smrg#include <stdio.h>
32d4a3aaf4Smrg#include "locking.h"
33d4a3aaf4Smrg
34d4a3aaf4Smrg#ifdef XTHREADS
35d4a3aaf4SmrgLockInfoPtr _conv_lock;
36d4a3aaf4Smrg#endif
371ab64890Smrg
381ab64890Smrgtypedef struct _XlcConverterListRec {
391ab64890Smrg    XLCd from_lcd;
401ab64890Smrg    const char *from;
411ab64890Smrg    XrmQuark from_type;
421ab64890Smrg    XLCd to_lcd;
431ab64890Smrg    const char *to;
441ab64890Smrg    XrmQuark to_type;
451ab64890Smrg    XlcOpenConverterProc converter;
461ab64890Smrg    struct _XlcConverterListRec *next;
471ab64890Smrg} XlcConverterListRec, *XlcConverterList;
481ab64890Smrg
491ab64890Smrgstatic XlcConverterList conv_list = NULL;
501ab64890Smrg
511ab64890Smrgstatic void
521ab64890Smrgclose_converter(
531ab64890Smrg    XlcConv conv)
541ab64890Smrg{
551ab64890Smrg    (*conv->methods->close)(conv);
561ab64890Smrg}
571ab64890Smrg
581ab64890Smrgstatic XlcConv
591ab64890Smrgget_converter(
601ab64890Smrg    XLCd from_lcd,
611ab64890Smrg    XrmQuark from_type,
621ab64890Smrg    XLCd to_lcd,
631ab64890Smrg    XrmQuark to_type)
641ab64890Smrg{
651ab64890Smrg    XlcConverterList list, prev = NULL;
66d4a3aaf4Smrg    XlcConv conv = NULL;
67d4a3aaf4Smrg
68d4a3aaf4Smrg    _XLockMutex(_conv_lock);
691ab64890Smrg
701ab64890Smrg    for (list = conv_list; list; list = list->next) {
7161b2299dSmrg	if (list->from_lcd == from_lcd && list->to_lcd == to_lcd
721ab64890Smrg	    && list->from_type == from_type && list->to_type == to_type) {
731ab64890Smrg
741ab64890Smrg	    if (prev && prev != conv_list) {	/* XXX */
751ab64890Smrg		prev->next = list->next;
761ab64890Smrg		list->next = conv_list;
771ab64890Smrg		conv_list = list;
781ab64890Smrg	    }
791ab64890Smrg
80d4a3aaf4Smrg	    conv = (*list->converter)(from_lcd, list->from, to_lcd, list->to);
81d4a3aaf4Smrg	    break;
821ab64890Smrg	}
831ab64890Smrg
841ab64890Smrg	prev = list;
851ab64890Smrg    }
861ab64890Smrg
87d4a3aaf4Smrg    _XUnlockMutex(_conv_lock);
88d4a3aaf4Smrg
89d4a3aaf4Smrg    return conv;
901ab64890Smrg}
911ab64890Smrg
921ab64890SmrgBool
931ab64890Smrg_XlcSetConverter(
941ab64890Smrg    XLCd from_lcd,
951ab64890Smrg    const char *from,
961ab64890Smrg    XLCd to_lcd,
971ab64890Smrg    const char *to,
981ab64890Smrg    XlcOpenConverterProc converter)
991ab64890Smrg{
1001ab64890Smrg    XlcConverterList list;
1011ab64890Smrg    XrmQuark from_type, to_type;
1021ab64890Smrg
1031ab64890Smrg    from_type = XrmStringToQuark(from);
1041ab64890Smrg    to_type = XrmStringToQuark(to);
1051ab64890Smrg
106d4a3aaf4Smrg    _XLockMutex(_conv_lock);
107d4a3aaf4Smrg
1081ab64890Smrg    for (list = conv_list; list; list = list->next) {
10961b2299dSmrg	if (list->from_lcd == from_lcd && list->to_lcd == to_lcd
1101ab64890Smrg	    && list->from_type == from_type && list->to_type == to_type) {
1111ab64890Smrg
1121ab64890Smrg	    list->converter = converter;
113d4a3aaf4Smrg	    goto ret;
1141ab64890Smrg	}
1151ab64890Smrg    }
1161ab64890Smrg
117818534a1Smrg    list = Xmalloc(sizeof(XlcConverterListRec));
1181ab64890Smrg    if (list == NULL)
119d4a3aaf4Smrg	goto ret;
1201ab64890Smrg
1211ab64890Smrg    list->from_lcd = from_lcd;
1221ab64890Smrg    list->from = from;
1231ab64890Smrg    list->from_type = from_type;
1241ab64890Smrg    list->to_lcd = to_lcd;
1251ab64890Smrg    list->to = to;
1261ab64890Smrg    list->to_type = to_type;
1271ab64890Smrg    list->converter = converter;
1281ab64890Smrg    list->next = conv_list;
1291ab64890Smrg    conv_list = list;
1301ab64890Smrg
131d4a3aaf4Smrgret:
132d4a3aaf4Smrg    _XUnlockMutex(_conv_lock);
133d4a3aaf4Smrg    return list != NULL;
1341ab64890Smrg}
1351ab64890Smrg
1361ab64890Smrgtypedef struct _ConvRec {
1371ab64890Smrg    XlcConv from_conv;
1381ab64890Smrg    XlcConv to_conv;
1391ab64890Smrg} ConvRec, *Conv;
1401ab64890Smrg
1411ab64890Smrgstatic int
1421ab64890Smrgindirect_convert(
1431ab64890Smrg    XlcConv lc_conv,
1441ab64890Smrg    XPointer *from,
1451ab64890Smrg    int *from_left,
1461ab64890Smrg    XPointer *to,
1471ab64890Smrg    int *to_left,
1481ab64890Smrg    XPointer *args,
1491ab64890Smrg    int num_args)
1501ab64890Smrg{
1511ab64890Smrg    Conv conv = (Conv) lc_conv->state;
1521ab64890Smrg    XlcConv from_conv = conv->from_conv;
1531ab64890Smrg    XlcConv to_conv = conv->to_conv;
1541ab64890Smrg    XlcCharSet charset;
1551ab64890Smrg    char buf[BUFSIZ], *cs;
1561ab64890Smrg    XPointer tmp_args[1];
1571ab64890Smrg    int cs_left, ret, length, unconv_num = 0;
1581ab64890Smrg
1591ab64890Smrg    if (from == NULL || *from == NULL) {
1601ab64890Smrg	if (from_conv->methods->reset)
1611ab64890Smrg	    (*from_conv->methods->reset)(from_conv);
1621ab64890Smrg
1631ab64890Smrg	if (to_conv->methods->reset)
1641ab64890Smrg	    (*to_conv->methods->reset)(to_conv);
1651ab64890Smrg
1661ab64890Smrg	return 0;
1671ab64890Smrg    }
1681ab64890Smrg
1691ab64890Smrg    while (*from_left > 0) {
1701ab64890Smrg	cs = buf;
1711ab64890Smrg	cs_left = BUFSIZ;
1721ab64890Smrg	tmp_args[0] = (XPointer) &charset;
1731ab64890Smrg
1741ab64890Smrg	ret = (*from_conv->methods->convert)(from_conv, from, from_left, &cs,
1751ab64890Smrg					     &cs_left, tmp_args, 1);
1761ab64890Smrg	if (ret < 0)
1771ab64890Smrg	    break;
1781ab64890Smrg
1791ab64890Smrg	unconv_num += ret;
1801ab64890Smrg
1811ab64890Smrg	length = cs - buf;
1821ab64890Smrg	if (length > 0) {
1831ab64890Smrg	    cs_left = length;
1841ab64890Smrg	    cs = buf;
1851ab64890Smrg
1861ab64890Smrg	    tmp_args[0] = (XPointer) charset;
1871ab64890Smrg
1881ab64890Smrg	    ret = (*to_conv->methods->convert)(to_conv, &cs, &cs_left, to, to_left,
1891ab64890Smrg					       tmp_args, 1);
1901ab64890Smrg	    if (ret < 0) {
1911ab64890Smrg		unconv_num += length / (charset->char_size > 0 ? charset->char_size : 1);
1921ab64890Smrg		continue;
1931ab64890Smrg	    }
1941ab64890Smrg
1951ab64890Smrg	    unconv_num += ret;
1961ab64890Smrg
1971ab64890Smrg	    if (*to_left < 1)
1981ab64890Smrg		break;
1991ab64890Smrg	}
2001ab64890Smrg    }
2011ab64890Smrg
2021ab64890Smrg    return unconv_num;
2031ab64890Smrg}
2041ab64890Smrg
2051ab64890Smrgstatic void
2061ab64890Smrgclose_indirect_converter(
2071ab64890Smrg    XlcConv lc_conv)
2081ab64890Smrg{
2091ab64890Smrg    Conv conv = (Conv) lc_conv->state;
2101ab64890Smrg
2111ab64890Smrg    if (conv) {
2121ab64890Smrg	if (conv->from_conv)
2131ab64890Smrg	    close_converter(conv->from_conv);
2141ab64890Smrg	if (conv->to_conv)
2151ab64890Smrg	    close_converter(conv->to_conv);
2161ab64890Smrg
217818534a1Smrg	Xfree(conv);
2181ab64890Smrg    }
2191ab64890Smrg
220818534a1Smrg    Xfree(lc_conv);
2211ab64890Smrg}
2221ab64890Smrg
2231ab64890Smrgstatic void
2241ab64890Smrgreset_indirect_converter(
2251ab64890Smrg    XlcConv lc_conv)
2261ab64890Smrg{
2271ab64890Smrg    Conv conv = (Conv) lc_conv->state;
2281ab64890Smrg
2291ab64890Smrg    if (conv) {
2301ab64890Smrg	if (conv->from_conv && conv->from_conv->methods->reset)
2311ab64890Smrg	    (*conv->from_conv->methods->reset)(conv->from_conv);
2321ab64890Smrg	if (conv->to_conv && conv->to_conv->methods->reset)
2331ab64890Smrg	    (*conv->to_conv->methods->reset)(conv->to_conv);
2341ab64890Smrg    }
2351ab64890Smrg}
2361ab64890Smrg
2371ab64890Smrgstatic XlcConvMethodsRec conv_methods = {
2381ab64890Smrg    close_indirect_converter,
2391ab64890Smrg    indirect_convert,
2401ab64890Smrg    reset_indirect_converter
2411ab64890Smrg} ;
2421ab64890Smrg
2431ab64890Smrgstatic XlcConv
2441ab64890Smrgopen_indirect_converter(
2451ab64890Smrg    XLCd from_lcd,
2461ab64890Smrg    const char *from,
2471ab64890Smrg    XLCd to_lcd,
2481ab64890Smrg    const char *to)
2491ab64890Smrg{
2501ab64890Smrg    XlcConv lc_conv, from_conv, to_conv;
2511ab64890Smrg    Conv conv;
2521ab64890Smrg    XrmQuark from_type, to_type;
2531ab64890Smrg    static XrmQuark QChar, QCharSet, QCTCharSet = (XrmQuark) 0;
2541ab64890Smrg
2551ab64890Smrg    if (QCTCharSet == (XrmQuark) 0) {
2561ab64890Smrg	QCTCharSet = XrmStringToQuark(XlcNCTCharSet);
2571ab64890Smrg	QCharSet = XrmStringToQuark(XlcNCharSet);
2581ab64890Smrg	QChar = XrmStringToQuark(XlcNChar);
2591ab64890Smrg    }
2601ab64890Smrg
2611ab64890Smrg    from_type = XrmStringToQuark(from);
2621ab64890Smrg    to_type = XrmStringToQuark(to);
2631ab64890Smrg
2641ab64890Smrg    if (from_type == QCharSet || from_type == QChar || to_type == QCharSet ||
2651ab64890Smrg	to_type == QChar)
2661ab64890Smrg	return (XlcConv) NULL;
2671ab64890Smrg
268818534a1Smrg    lc_conv = Xmalloc(sizeof(XlcConvRec));
2691ab64890Smrg    if (lc_conv == NULL)
2701ab64890Smrg	return (XlcConv) NULL;
2711ab64890Smrg
2721ab64890Smrg    lc_conv->methods = &conv_methods;
2731ab64890Smrg
274818534a1Smrg    lc_conv->state = Xcalloc(1, sizeof(ConvRec));
2751ab64890Smrg    if (lc_conv->state == NULL)
2761ab64890Smrg	goto err;
2771ab64890Smrg
2781ab64890Smrg    conv = (Conv) lc_conv->state;
2791ab64890Smrg
2801ab64890Smrg    from_conv = get_converter(from_lcd, from_type, from_lcd, QCTCharSet);
2811ab64890Smrg    if (from_conv == NULL)
2821ab64890Smrg	from_conv = get_converter(from_lcd, from_type, from_lcd, QCharSet);
2831ab64890Smrg    if (from_conv == NULL)
2841ab64890Smrg	from_conv = get_converter((XLCd)NULL, from_type, (XLCd)NULL, QCharSet);
2851ab64890Smrg    if (from_conv == NULL)
2861ab64890Smrg	from_conv = get_converter(from_lcd, from_type, from_lcd, QChar);
2871ab64890Smrg    if (from_conv == NULL)
2881ab64890Smrg	goto err;
2891ab64890Smrg    conv->from_conv = from_conv;
2901ab64890Smrg
2911ab64890Smrg    to_conv = get_converter(to_lcd, QCTCharSet, to_lcd, to_type);
2921ab64890Smrg    if (to_conv == NULL)
2931ab64890Smrg	to_conv = get_converter(to_lcd, QCharSet, to_lcd, to_type);
2941ab64890Smrg    if (to_conv == NULL)
2951ab64890Smrg	to_conv = get_converter((XLCd) NULL, QCharSet, (XLCd) NULL, to_type);
2961ab64890Smrg    if (to_conv == NULL)
2971ab64890Smrg	goto err;
2981ab64890Smrg    conv->to_conv = to_conv;
2991ab64890Smrg
3001ab64890Smrg    return lc_conv;
3011ab64890Smrg
3021ab64890Smrgerr:
3031ab64890Smrg    close_indirect_converter(lc_conv);
3041ab64890Smrg
3051ab64890Smrg    return (XlcConv) NULL;
3061ab64890Smrg}
3071ab64890Smrg
3081ab64890SmrgXlcConv
3091ab64890Smrg_XlcOpenConverter(
3101ab64890Smrg    XLCd from_lcd,
3111ab64890Smrg    const char *from,
3121ab64890Smrg    XLCd to_lcd,
3131ab64890Smrg    const char *to)
3141ab64890Smrg{
3151ab64890Smrg    XlcConv conv;
3161ab64890Smrg    XrmQuark from_type, to_type;
3171ab64890Smrg
3181ab64890Smrg    from_type = XrmStringToQuark(from);
3191ab64890Smrg    to_type = XrmStringToQuark(to);
3201ab64890Smrg
3211ab64890Smrg    if ((conv = get_converter(from_lcd, from_type, to_lcd, to_type)))
3221ab64890Smrg	return conv;
3231ab64890Smrg
3241ab64890Smrg    return open_indirect_converter(from_lcd, from, to_lcd, to);
3251ab64890Smrg}
3261ab64890Smrg
3271ab64890Smrgvoid
3281ab64890Smrg_XlcCloseConverter(
3291ab64890Smrg    XlcConv conv)
3301ab64890Smrg{
3311ab64890Smrg    close_converter(conv);
3321ab64890Smrg}
3331ab64890Smrg
3341ab64890Smrgint
3351ab64890Smrg_XlcConvert(
3361ab64890Smrg    XlcConv conv,
3371ab64890Smrg    XPointer *from,
3381ab64890Smrg    int *from_left,
3391ab64890Smrg    XPointer *to,
3401ab64890Smrg    int *to_left,
3411ab64890Smrg    XPointer *args,
3421ab64890Smrg    int num_args)
3431ab64890Smrg{
3441ab64890Smrg    return (*conv->methods->convert)(conv, from, from_left, to, to_left, args,
3451ab64890Smrg				     num_args);
3461ab64890Smrg}
3471ab64890Smrg
3481ab64890Smrgvoid
3491ab64890Smrg_XlcResetConverter(
3501ab64890Smrg    XlcConv conv)
3511ab64890Smrg{
3521ab64890Smrg    if (conv->methods->reset)
3531ab64890Smrg	(*conv->methods->reset)(conv);
3541ab64890Smrg}
355