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 #include "locking.h"
33
34 #ifdef XTHREADS
35 LockInfoPtr _conv_lock;
36 #endif
37
38 typedef struct _XlcConverterListRec {
39 XLCd from_lcd;
40 const char *from;
41 XrmQuark from_type;
42 XLCd to_lcd;
43 const char *to;
44 XrmQuark to_type;
45 XlcOpenConverterProc converter;
46 struct _XlcConverterListRec *next;
47 } XlcConverterListRec, *XlcConverterList;
48
49 static XlcConverterList conv_list = NULL;
50
51 static void
close_converter(XlcConv conv)52 close_converter(
53 XlcConv conv)
54 {
55 (*conv->methods->close)(conv);
56 }
57
58 static XlcConv
get_converter(XLCd from_lcd,XrmQuark from_type,XLCd to_lcd,XrmQuark to_type)59 get_converter(
60 XLCd from_lcd,
61 XrmQuark from_type,
62 XLCd to_lcd,
63 XrmQuark to_type)
64 {
65 XlcConverterList list, prev = NULL;
66 XlcConv conv = NULL;
67
68 _XLockMutex(_conv_lock);
69
70 for (list = conv_list; list; list = list->next) {
71 if (list->from_lcd == from_lcd && list->to_lcd == to_lcd
72 && list->from_type == from_type && list->to_type == to_type) {
73
74 if (prev && prev != conv_list) { /* XXX */
75 prev->next = list->next;
76 list->next = conv_list;
77 conv_list = list;
78 }
79
80 conv = (*list->converter)(from_lcd, list->from, to_lcd, list->to);
81 break;
82 }
83
84 prev = list;
85 }
86
87 _XUnlockMutex(_conv_lock);
88
89 return conv;
90 }
91
92 Bool
_XlcSetConverter(XLCd from_lcd,const char * from,XLCd to_lcd,const char * to,XlcOpenConverterProc converter)93 _XlcSetConverter(
94 XLCd from_lcd,
95 const char *from,
96 XLCd to_lcd,
97 const char *to,
98 XlcOpenConverterProc converter)
99 {
100 XlcConverterList list;
101 XrmQuark from_type, to_type;
102
103 from_type = XrmStringToQuark(from);
104 to_type = XrmStringToQuark(to);
105
106 _XLockMutex(_conv_lock);
107
108 for (list = conv_list; list; list = list->next) {
109 if (list->from_lcd == from_lcd && list->to_lcd == to_lcd
110 && list->from_type == from_type && list->to_type == to_type) {
111
112 list->converter = converter;
113 goto ret;
114 }
115 }
116
117 list = Xmalloc(sizeof(XlcConverterListRec));
118 if (list == NULL)
119 goto ret;
120
121 list->from_lcd = from_lcd;
122 list->from = from;
123 list->from_type = from_type;
124 list->to_lcd = to_lcd;
125 list->to = to;
126 list->to_type = to_type;
127 list->converter = converter;
128 list->next = conv_list;
129 conv_list = list;
130
131 ret:
132 _XUnlockMutex(_conv_lock);
133 return list != NULL;
134 }
135
136 typedef struct _ConvRec {
137 XlcConv from_conv;
138 XlcConv to_conv;
139 } ConvRec, *Conv;
140
141 static int
indirect_convert(XlcConv lc_conv,XPointer * from,int * from_left,XPointer * to,int * to_left,XPointer * args,int num_args)142 indirect_convert(
143 XlcConv lc_conv,
144 XPointer *from,
145 int *from_left,
146 XPointer *to,
147 int *to_left,
148 XPointer *args,
149 int num_args)
150 {
151 Conv conv = (Conv) lc_conv->state;
152 XlcConv from_conv = conv->from_conv;
153 XlcConv to_conv = conv->to_conv;
154 XlcCharSet charset;
155 char buf[BUFSIZ], *cs;
156 XPointer tmp_args[1];
157 int cs_left, ret, length, unconv_num = 0;
158
159 if (from == NULL || *from == NULL) {
160 if (from_conv->methods->reset)
161 (*from_conv->methods->reset)(from_conv);
162
163 if (to_conv->methods->reset)
164 (*to_conv->methods->reset)(to_conv);
165
166 return 0;
167 }
168
169 while (*from_left > 0) {
170 cs = buf;
171 cs_left = BUFSIZ;
172 tmp_args[0] = (XPointer) &charset;
173
174 ret = (*from_conv->methods->convert)(from_conv, from, from_left, &cs,
175 &cs_left, tmp_args, 1);
176 if (ret < 0)
177 break;
178
179 unconv_num += ret;
180
181 length = cs - buf;
182 if (length > 0) {
183 cs_left = length;
184 cs = buf;
185
186 tmp_args[0] = (XPointer) charset;
187
188 ret = (*to_conv->methods->convert)(to_conv, &cs, &cs_left, to, to_left,
189 tmp_args, 1);
190 if (ret < 0) {
191 unconv_num += length / (charset->char_size > 0 ? charset->char_size : 1);
192 continue;
193 }
194
195 unconv_num += ret;
196
197 if (*to_left < 1)
198 break;
199 }
200 }
201
202 return unconv_num;
203 }
204
205 static void
close_indirect_converter(XlcConv lc_conv)206 close_indirect_converter(
207 XlcConv lc_conv)
208 {
209 Conv conv = (Conv) lc_conv->state;
210
211 if (conv) {
212 if (conv->from_conv)
213 close_converter(conv->from_conv);
214 if (conv->to_conv)
215 close_converter(conv->to_conv);
216
217 Xfree(conv);
218 }
219
220 Xfree(lc_conv);
221 }
222
223 static void
reset_indirect_converter(XlcConv lc_conv)224 reset_indirect_converter(
225 XlcConv lc_conv)
226 {
227 Conv conv = (Conv) lc_conv->state;
228
229 if (conv) {
230 if (conv->from_conv && conv->from_conv->methods->reset)
231 (*conv->from_conv->methods->reset)(conv->from_conv);
232 if (conv->to_conv && conv->to_conv->methods->reset)
233 (*conv->to_conv->methods->reset)(conv->to_conv);
234 }
235 }
236
237 static XlcConvMethodsRec conv_methods = {
238 close_indirect_converter,
239 indirect_convert,
240 reset_indirect_converter
241 } ;
242
243 static XlcConv
open_indirect_converter(XLCd from_lcd,const char * from,XLCd to_lcd,const char * to)244 open_indirect_converter(
245 XLCd from_lcd,
246 const char *from,
247 XLCd to_lcd,
248 const char *to)
249 {
250 XlcConv lc_conv, from_conv, to_conv;
251 Conv conv;
252 XrmQuark from_type, to_type;
253 static XrmQuark QChar, QCharSet, QCTCharSet = (XrmQuark) 0;
254
255 if (QCTCharSet == (XrmQuark) 0) {
256 QCTCharSet = XrmStringToQuark(XlcNCTCharSet);
257 QCharSet = XrmStringToQuark(XlcNCharSet);
258 QChar = XrmStringToQuark(XlcNChar);
259 }
260
261 from_type = XrmStringToQuark(from);
262 to_type = XrmStringToQuark(to);
263
264 if (from_type == QCharSet || from_type == QChar || to_type == QCharSet ||
265 to_type == QChar)
266 return (XlcConv) NULL;
267
268 lc_conv = Xmalloc(sizeof(XlcConvRec));
269 if (lc_conv == NULL)
270 return (XlcConv) NULL;
271
272 lc_conv->methods = &conv_methods;
273
274 lc_conv->state = Xcalloc(1, sizeof(ConvRec));
275 if (lc_conv->state == NULL)
276 goto err;
277
278 conv = (Conv) lc_conv->state;
279
280 from_conv = get_converter(from_lcd, from_type, from_lcd, QCTCharSet);
281 if (from_conv == NULL)
282 from_conv = get_converter(from_lcd, from_type, from_lcd, QCharSet);
283 if (from_conv == NULL)
284 from_conv = get_converter((XLCd)NULL, from_type, (XLCd)NULL, QCharSet);
285 if (from_conv == NULL)
286 from_conv = get_converter(from_lcd, from_type, from_lcd, QChar);
287 if (from_conv == NULL)
288 goto err;
289 conv->from_conv = from_conv;
290
291 to_conv = get_converter(to_lcd, QCTCharSet, to_lcd, to_type);
292 if (to_conv == NULL)
293 to_conv = get_converter(to_lcd, QCharSet, to_lcd, to_type);
294 if (to_conv == NULL)
295 to_conv = get_converter((XLCd) NULL, QCharSet, (XLCd) NULL, to_type);
296 if (to_conv == NULL)
297 goto err;
298 conv->to_conv = to_conv;
299
300 return lc_conv;
301
302 err:
303 close_indirect_converter(lc_conv);
304
305 return (XlcConv) NULL;
306 }
307
308 XlcConv
_XlcOpenConverter(XLCd from_lcd,const char * from,XLCd to_lcd,const char * to)309 _XlcOpenConverter(
310 XLCd from_lcd,
311 const char *from,
312 XLCd to_lcd,
313 const char *to)
314 {
315 XlcConv conv;
316 XrmQuark from_type, to_type;
317
318 from_type = XrmStringToQuark(from);
319 to_type = XrmStringToQuark(to);
320
321 if ((conv = get_converter(from_lcd, from_type, to_lcd, to_type)))
322 return conv;
323
324 return open_indirect_converter(from_lcd, from, to_lcd, to);
325 }
326
327 void
_XlcCloseConverter(XlcConv conv)328 _XlcCloseConverter(
329 XlcConv conv)
330 {
331 close_converter(conv);
332 }
333
334 int
_XlcConvert(XlcConv conv,XPointer * from,int * from_left,XPointer * to,int * to_left,XPointer * args,int num_args)335 _XlcConvert(
336 XlcConv conv,
337 XPointer *from,
338 int *from_left,
339 XPointer *to,
340 int *to_left,
341 XPointer *args,
342 int num_args)
343 {
344 return (*conv->methods->convert)(conv, from, from_left, to, to_left, args,
345 num_args);
346 }
347
348 void
_XlcResetConverter(XlcConv conv)349 _XlcResetConverter(
350 XlcConv conv)
351 {
352 if (conv->methods->reset)
353 (*conv->methods->reset)(conv);
354 }
355