lcConv.c revision 818534a1
1/*
2 * Copyright 1992, 1993 by TOSHIBA Corp.
3 *
4 * Permission to use, copy, modify, and distribute this software and its
5 * documentation for any purpose and without fee is hereby granted, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of TOSHIBA not be used in advertising
9 * or publicity pertaining to distribution of the software without specific,
10 * written prior permission. TOSHIBA make no representations about the
11 * suitability of this software for any purpose.  It is provided "as is"
12 * without express or implied warranty.
13 *
14 * TOSHIBA DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16 * TOSHIBA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20 * SOFTWARE.
21 *
22 * Author: Katsuhisa Yano	TOSHIBA Corp.
23 *			   	mopi@osa.ilab.toshiba.co.jp
24 */
25
26#ifdef HAVE_CONFIG_H
27#include <config.h>
28#endif
29#include "Xlibint.h"
30#include "XlcPubI.h"
31#include <stdio.h>
32
33typedef struct _XlcConverterListRec {
34    XLCd from_lcd;
35    const char *from;
36    XrmQuark from_type;
37    XLCd to_lcd;
38    const char *to;
39    XrmQuark to_type;
40    XlcOpenConverterProc converter;
41    struct _XlcConverterListRec *next;
42} XlcConverterListRec, *XlcConverterList;
43
44static XlcConverterList conv_list = NULL;
45
46static void
47close_converter(
48    XlcConv conv)
49{
50    (*conv->methods->close)(conv);
51}
52
53static XlcConv
54get_converter(
55    XLCd from_lcd,
56    XrmQuark from_type,
57    XLCd to_lcd,
58    XrmQuark to_type)
59{
60    XlcConverterList list, prev = NULL;
61
62    for (list = conv_list; list; list = list->next) {
63	if (list->from_lcd == from_lcd && list->to_lcd == to_lcd
64	    && list->from_type == from_type && list->to_type == to_type) {
65
66	    if (prev && prev != conv_list) {	/* XXX */
67		prev->next = list->next;
68		list->next = conv_list;
69		conv_list = list;
70	    }
71
72	    return (*list->converter)(from_lcd, list->from, to_lcd, list->to);
73	}
74
75	prev = list;
76    }
77
78    return (XlcConv) NULL;
79}
80
81Bool
82_XlcSetConverter(
83    XLCd from_lcd,
84    const char *from,
85    XLCd to_lcd,
86    const char *to,
87    XlcOpenConverterProc converter)
88{
89    XlcConverterList list;
90    XrmQuark from_type, to_type;
91
92    from_type = XrmStringToQuark(from);
93    to_type = XrmStringToQuark(to);
94
95    for (list = conv_list; list; list = list->next) {
96	if (list->from_lcd == from_lcd && list->to_lcd == to_lcd
97	    && list->from_type == from_type && list->to_type == to_type) {
98
99	    list->converter = converter;
100	    return True;
101	}
102    }
103
104    list = Xmalloc(sizeof(XlcConverterListRec));
105    if (list == NULL)
106	return False;
107
108    list->from_lcd = from_lcd;
109    list->from = from;
110    list->from_type = from_type;
111    list->to_lcd = to_lcd;
112    list->to = to;
113    list->to_type = to_type;
114    list->converter = converter;
115    list->next = conv_list;
116    conv_list = list;
117
118    return True;
119}
120
121typedef struct _ConvRec {
122    XlcConv from_conv;
123    XlcConv to_conv;
124} ConvRec, *Conv;
125
126static int
127indirect_convert(
128    XlcConv lc_conv,
129    XPointer *from,
130    int *from_left,
131    XPointer *to,
132    int *to_left,
133    XPointer *args,
134    int num_args)
135{
136    Conv conv = (Conv) lc_conv->state;
137    XlcConv from_conv = conv->from_conv;
138    XlcConv to_conv = conv->to_conv;
139    XlcCharSet charset;
140    char buf[BUFSIZ], *cs;
141    XPointer tmp_args[1];
142    int cs_left, ret, length, unconv_num = 0;
143
144    if (from == NULL || *from == NULL) {
145	if (from_conv->methods->reset)
146	    (*from_conv->methods->reset)(from_conv);
147
148	if (to_conv->methods->reset)
149	    (*to_conv->methods->reset)(to_conv);
150
151	return 0;
152    }
153
154    while (*from_left > 0) {
155	cs = buf;
156	cs_left = BUFSIZ;
157	tmp_args[0] = (XPointer) &charset;
158
159	ret = (*from_conv->methods->convert)(from_conv, from, from_left, &cs,
160					     &cs_left, tmp_args, 1);
161	if (ret < 0)
162	    break;
163
164	unconv_num += ret;
165
166	length = cs - buf;
167	if (length > 0) {
168	    cs_left = length;
169	    cs = buf;
170
171	    tmp_args[0] = (XPointer) charset;
172
173	    ret = (*to_conv->methods->convert)(to_conv, &cs, &cs_left, to, to_left,
174					       tmp_args, 1);
175	    if (ret < 0) {
176		unconv_num += length / (charset->char_size > 0 ? charset->char_size : 1);
177		continue;
178	    }
179
180	    unconv_num += ret;
181
182	    if (*to_left < 1)
183		break;
184	}
185    }
186
187    return unconv_num;
188}
189
190static void
191close_indirect_converter(
192    XlcConv lc_conv)
193{
194    Conv conv = (Conv) lc_conv->state;
195
196    if (conv) {
197	if (conv->from_conv)
198	    close_converter(conv->from_conv);
199	if (conv->to_conv)
200	    close_converter(conv->to_conv);
201
202	Xfree(conv);
203    }
204
205    Xfree(lc_conv);
206}
207
208static void
209reset_indirect_converter(
210    XlcConv lc_conv)
211{
212    Conv conv = (Conv) lc_conv->state;
213
214    if (conv) {
215	if (conv->from_conv && conv->from_conv->methods->reset)
216	    (*conv->from_conv->methods->reset)(conv->from_conv);
217	if (conv->to_conv && conv->to_conv->methods->reset)
218	    (*conv->to_conv->methods->reset)(conv->to_conv);
219    }
220}
221
222static XlcConvMethodsRec conv_methods = {
223    close_indirect_converter,
224    indirect_convert,
225    reset_indirect_converter
226} ;
227
228static XlcConv
229open_indirect_converter(
230    XLCd from_lcd,
231    const char *from,
232    XLCd to_lcd,
233    const char *to)
234{
235    XlcConv lc_conv, from_conv, to_conv;
236    Conv conv;
237    XrmQuark from_type, to_type;
238    static XrmQuark QChar, QCharSet, QCTCharSet = (XrmQuark) 0;
239
240    if (QCTCharSet == (XrmQuark) 0) {
241	QCTCharSet = XrmStringToQuark(XlcNCTCharSet);
242	QCharSet = XrmStringToQuark(XlcNCharSet);
243	QChar = XrmStringToQuark(XlcNChar);
244    }
245
246    from_type = XrmStringToQuark(from);
247    to_type = XrmStringToQuark(to);
248
249    if (from_type == QCharSet || from_type == QChar || to_type == QCharSet ||
250	to_type == QChar)
251	return (XlcConv) NULL;
252
253    lc_conv = Xmalloc(sizeof(XlcConvRec));
254    if (lc_conv == NULL)
255	return (XlcConv) NULL;
256
257    lc_conv->methods = &conv_methods;
258
259    lc_conv->state = Xcalloc(1, sizeof(ConvRec));
260    if (lc_conv->state == NULL)
261	goto err;
262
263    conv = (Conv) lc_conv->state;
264
265    from_conv = get_converter(from_lcd, from_type, from_lcd, QCTCharSet);
266    if (from_conv == NULL)
267	from_conv = get_converter(from_lcd, from_type, from_lcd, QCharSet);
268    if (from_conv == NULL)
269	from_conv = get_converter((XLCd)NULL, from_type, (XLCd)NULL, QCharSet);
270    if (from_conv == NULL)
271	from_conv = get_converter(from_lcd, from_type, from_lcd, QChar);
272    if (from_conv == NULL)
273	goto err;
274    conv->from_conv = from_conv;
275
276    to_conv = get_converter(to_lcd, QCTCharSet, to_lcd, to_type);
277    if (to_conv == NULL)
278	to_conv = get_converter(to_lcd, QCharSet, to_lcd, to_type);
279    if (to_conv == NULL)
280	to_conv = get_converter((XLCd) NULL, QCharSet, (XLCd) NULL, to_type);
281    if (to_conv == NULL)
282	goto err;
283    conv->to_conv = to_conv;
284
285    return lc_conv;
286
287err:
288    close_indirect_converter(lc_conv);
289
290    return (XlcConv) NULL;
291}
292
293XlcConv
294_XlcOpenConverter(
295    XLCd from_lcd,
296    const char *from,
297    XLCd to_lcd,
298    const char *to)
299{
300    XlcConv conv;
301    XrmQuark from_type, to_type;
302
303    from_type = XrmStringToQuark(from);
304    to_type = XrmStringToQuark(to);
305
306    if ((conv = get_converter(from_lcd, from_type, to_lcd, to_type)))
307	return conv;
308
309    return open_indirect_converter(from_lcd, from, to_lcd, to);
310}
311
312void
313_XlcCloseConverter(
314    XlcConv conv)
315{
316    close_converter(conv);
317}
318
319int
320_XlcConvert(
321    XlcConv conv,
322    XPointer *from,
323    int *from_left,
324    XPointer *to,
325    int *to_left,
326    XPointer *args,
327    int num_args)
328{
329    return (*conv->methods->convert)(conv, from, from_left, to, to_left, args,
330				     num_args);
331}
332
333void
334_XlcResetConverter(
335    XlcConv conv)
336{
337    if (conv->methods->reset)
338	(*conv->methods->reset)(conv);
339}
340