* Fixed StickyAcrossPages style in the FvwmPager.
[fvwm.git] / libs / Ficonv.c
blobf402e29052a1727df856088d1759f0561cfb52ca
1 /* -*-c-*- */
2 /* Copyright (C) 2002 Olivier Chapuis */
3 /* This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 /* Some code (convert_charsets) inspired by the glib-2 (gutf8.c) copyrighted
19 * by Tom Tromey & Red Hat, Inc. */
21 /* ---------------------------- included header files ---------------------- */
23 #include "config.h"
24 #include <stdio.h>
25 #include <errno.h>
27 #include <X11/Xlib.h>
29 #include "FlocaleCharset.h"
30 #include "Ficonv.h"
32 #if FiconvSupport
33 #include <iconv.h>
35 #if defined(USE_LIBICONV) && !defined (_LIBICONV_H)
36 #error libiconv in use but included iconv.h not from libiconv
37 #endif
38 #if !defined(USE_LIBICONV) && defined (_LIBICONV_H)
39 #error libiconv not in use but included iconv.h is from libiconv
40 #endif
41 #endif /* FiconvSupport */
43 /* ---------------------------- local definitions -------------------------- */
45 /* ---------------------------- local macros ------------------------------- */
47 /* ---------------------------- imports ------------------------------------ */
49 /* ---------------------------- included code files ------------------------ */
51 /* ---------------------------- local types -------------------------------- */
53 /* ---------------------------- forward declarations ----------------------- */
55 /* ---------------------------- local variables ---------------------------- */
57 static Bool FiconvInitialized = False;
58 static FlocaleCharset *FLCIconvUtf8Charset = NULL; /* UTF-8 charset */
59 static FlocaleCharset *FLCIconvDefaultCharset = NULL;
61 /* ---------------------------- exported variables (globals) --------------- */
63 /* ---------------------------- local functions ---------------------------- */
65 static
66 Bool is_iconv_supported(char *c1, char *c2)
68 Ficonv_t cd1,cd2;
69 Bool r = False;
70 int dummy;
72 if (!FiconvSupport || !c1 || !c2)
73 return False;
75 cd1 = Ficonv_open(c1, c2);
76 cd2 = Ficonv_open(c2, c1);
77 if (cd1 != (Ficonv_t) -1 && cd2 != (Ficonv_t) -1)
78 r = True;
79 if (cd1 != (Ficonv_t) -1)
80 dummy = Ficonv_close(cd1);
81 if (cd2 != (Ficonv_t) -1)
82 dummy = Ficonv_close(cd2);
83 return r;
86 static
87 int set_default_iconv_charsets(FlocaleCharset *fc)
89 int i=0,j=0;
91 if (!FiconvSupport || FLCIconvUtf8Charset == NULL || fc == NULL)
92 return False;
94 while(FLC_GET_LOCALE_CHARSET(FLCIconvUtf8Charset,i) != NULL)
96 j = 0;
97 while(FLC_GET_LOCALE_CHARSET(fc,j) != NULL)
99 if (is_iconv_supported(
100 FLC_GET_LOCALE_CHARSET(
101 FLCIconvUtf8Charset,i),
102 FLC_GET_LOCALE_CHARSET(fc,j)))
104 FLC_SET_ICONV_INDEX(FLCIconvUtf8Charset,i);
105 FLC_SET_ICONV_INDEX(fc,j);
106 return 1;
108 j++;
110 i++;
112 FLC_SET_ICONV_INDEX(FLCIconvUtf8Charset,
113 FLC_INDEX_ICONV_CHARSET_NOT_FOUND);
114 FLC_SET_ICONV_INDEX(fc, FLC_INDEX_ICONV_CHARSET_NOT_FOUND);
115 return 0;
118 static
119 void set_iconv_charset_index(FlocaleCharset *fc)
121 int i = 0;
123 if (!FiconvSupport || fc == NULL)
124 return;
126 if (FLC_DO_ICONV_CHARSET_INITIALIZED(fc))
127 return; /* already set */
128 if (FLCIconvUtf8Charset == NULL ||
129 !FLC_DO_ICONV_CHARSET_INITIALIZED(FLCIconvUtf8Charset))
131 FLC_SET_ICONV_INDEX(fc, FLC_INDEX_ICONV_CHARSET_NOT_FOUND);
132 return;
134 while(FLC_GET_LOCALE_CHARSET(fc,i) != NULL)
136 if (is_iconv_supported(
137 FLC_GET_ICONV_CHARSET(FLCIconvUtf8Charset),
138 FLC_GET_LOCALE_CHARSET(fc,i)))
140 FLC_SET_ICONV_INDEX(fc,i);
141 return;
143 i++;
145 FLC_SET_ICONV_INDEX(fc, FLC_INDEX_ICONV_CHARSET_NOT_FOUND);
148 static
149 char *convert_charsets(const char *in_charset, const char *out_charset,
150 const char *in, unsigned int in_size)
152 static int error_count = 0;
153 Ficonv_t cd;
154 int have_error = 0;
155 int is_finished = 0;
156 size_t nconv;
157 size_t insize,outbuf_size,outbytes_remaining,len;
158 const char *inptr;
159 char *dest;
160 char *outp;
162 if (in == NULL || !FiconvSupport)
163 return NULL;
165 cd = Ficonv_open(out_charset, in_charset);
166 if (cd == (Ficonv_t) -1)
168 /* Something went wrong. */
169 if (error_count > FICONV_CONVERSION_MAX_NUMBER_OF_WARNING)
170 return NULL;
171 error_count++;
172 if (errno == EINVAL)
174 fprintf(
175 stderr,
176 "[fvwm][convert_charsets]: WARNING -\n\t");
177 fprintf(
178 stderr,
179 "conversion from `%s' to `%s' not available\n",
180 in_charset,out_charset);
182 else
184 fprintf(
185 stderr,
186 "[fvwm][convert_charsets]: WARNING -\n\t");
187 fprintf(
188 stderr,
189 "conversion from `%s' to `%s' fail (init)\n",
190 in_charset,out_charset);
192 /* Terminate the output string. */
193 return NULL;
196 /* in maybe a none terminate string */
197 len = in_size;
199 outbuf_size = len + 1;
200 outbytes_remaining = outbuf_size - 1;
201 insize = len;
202 outp = dest = safemalloc(outbuf_size);
204 inptr = in;
206 for (is_finished = 0; is_finished == 0; )
208 nconv = Ficonv(
209 cd, (ICONV_ARG_CONST char **)&inptr, &insize, &outp,
210 &outbytes_remaining);
211 is_finished = 1;
212 if (nconv == (size_t) - 1)
214 switch (errno)
216 case EINVAL:
217 /* Incomplete text, do not report an error */
218 break;
219 case E2BIG:
221 size_t used = outp - dest;
223 outbuf_size *= 2;
224 dest = realloc (dest, outbuf_size);
226 outp = dest + used;
227 /* -1 for nul */
228 outbytes_remaining = outbuf_size - used - 1;
229 is_finished = 0;
230 break;
232 #ifdef EILSEQ
233 case EILSEQ:
234 /* Something went wrong. */
235 if (error_count <=
236 FICONV_CONVERSION_MAX_NUMBER_OF_WARNING)
238 fprintf(
239 stderr,
240 "[fvwm][convert_charsets]:"
241 " WARNING -\n\t");
242 fprintf(
243 stderr,
244 "Invalid byte sequence during"
245 " conversion from %s to %s\n",
246 in_charset,out_charset);
248 have_error = 1;
249 break;
250 #endif
251 default:
252 if (error_count <=
253 FICONV_CONVERSION_MAX_NUMBER_OF_WARNING)
255 fprintf(
256 stderr,
257 "[fvwm][convert_charsets]:"
258 " WARNING -\n\t");
259 fprintf(
260 stderr,
261 "Error during conversion from"
262 " %s to %s\n", in_charset,
263 out_charset);
265 have_error = 1;
266 break;
271 /* Terminate the output string */
272 *outp = '\0';
274 if (Ficonv_close (cd) != 0)
276 fprintf(
277 stderr,
278 "[fvwm][convert_charsets]: WARNING - iconv_close"
279 " fail\n");
282 if (have_error)
284 error_count++;
285 free (dest);
286 return NULL;
288 else
290 return dest;
294 static
295 void FiconvInit(Display *dpy, const char *module)
297 int suc = False;
299 if (!FiconvSupport || FiconvInitialized)
300 return;
302 FiconvInitialized = True;
303 FlocaleCharsetInit(dpy, module);
304 FLCIconvUtf8Charset = FlocaleCharsetGetUtf8Charset();
305 FLCIconvDefaultCharset = FlocaleCharsetGetFLCXOMCharset();
307 suc = set_default_iconv_charsets(FLCIconvDefaultCharset);
308 if (!suc)
310 FLCIconvDefaultCharset = FlocaleCharsetGetLocaleCharset();
311 suc = set_default_iconv_charsets(FLCIconvDefaultCharset);
313 if (!suc)
315 fprintf(stderr,
316 "[%s][FiconvInit]: WARN -- Cannot get default "
317 "iconv charset for default charsets '%s' and '%s'\n",
318 module,
319 FLC_DEBUG_GET_X_CHARSET(
320 FlocaleCharsetGetFLCXOMCharset()),
321 FLC_DEBUG_GET_X_CHARSET(FLCIconvDefaultCharset));
322 FLCIconvUtf8Charset = NULL;
323 FLCIconvDefaultCharset = NULL;
326 #if FLOCALE_DEBUG_CHARSET
327 fprintf(stderr,"[FiconvInit] iconv charset: x:%s, iconv:%s\n",
328 FLC_DEBUG_GET_X_CHARSET(FLCIconvDefaultCharset),
329 FLC_DEBUG_GET_ICONV_CHARSET(FLCIconvDefaultCharset));
330 fprintf(stderr,"[FiconvInit] UTF-8 charset: x:%s, iconv:%s\n",
331 FLC_DEBUG_GET_X_CHARSET(FLCIconvUtf8Charset),
332 FLC_DEBUG_GET_ICONV_CHARSET(FLCIconvUtf8Charset));
333 #endif
337 static
338 FlocaleCharset *FiconvSetupConversion(Display *dpy, FlocaleCharset *fc)
340 FlocaleCharset *my_fc = NULL;
342 if (!FiconvSupport)
344 return NULL;
347 if (!FiconvInitialized)
349 FiconvInit(dpy, "fvwm");
352 if (FLCIconvUtf8Charset == NULL)
354 return NULL;
357 if (fc == NULL)
359 my_fc = FLCIconvDefaultCharset;
360 if (my_fc == NULL)
362 return NULL;
365 else
367 my_fc = fc;
370 if (!FLC_DO_ICONV_CHARSET_INITIALIZED(my_fc))
372 set_iconv_charset_index(my_fc);
373 #if FLOCALE_DEBUG_CHARSET
374 fprintf(stderr, "[Flocale] set up iconv charset: "
375 "x: %s, iconv: %s\n",
376 FLC_DEBUG_GET_X_CHARSET(my_fc),
377 FLC_DEBUG_GET_ICONV_CHARSET(my_fc));
378 #endif
379 if (!FLC_HAVE_ICONV_CHARSET(my_fc))
381 fprintf(
382 stderr,
383 "[fvwmlibs] cannot get iconv converter "
384 "for charset %s\n",
385 FLC_DEBUG_GET_X_CHARSET(my_fc));
386 return NULL;
389 if (!FLC_HAVE_ICONV_CHARSET(my_fc))
391 return NULL;
394 return my_fc;
397 /* ---------------------------- interface functions ------------------------ */
399 /* conversion from UTF8 to the "current" charset */
400 char *FiconvUtf8ToCharset(Display *dpy, FlocaleCharset *fc,
401 const char *in, unsigned int in_size)
403 char *out = NULL;
404 FlocaleCharset *my_fc = NULL;
406 if (!FiconvSupport)
408 return NULL;
411 my_fc = FiconvSetupConversion(dpy, fc);
412 if (my_fc == NULL)
414 return NULL;
417 #if FLOCALE_DEBUG_ICONV
418 fprintf(stderr, "[FiconvUtf8ToCharset] conversion from %s to %s\n",
419 FLC_DEBUG_GET_ICONV_CHARSET(FLCIconvUtf8Charset),
420 FLC_DEBUG_GET_ICONV_CHARSET(my_fc));
421 #endif
423 if (FLC_ENCODING_TYPE_IS_UTF_8(my_fc))
425 /* in can be a none terminate string so do not use CopyString
427 out = safemalloc(in_size+1);
428 strncpy(out, in, in_size);
429 out[in_size]=0;
431 else
433 out = convert_charsets(
434 FLC_GET_ICONV_CHARSET(FLCIconvUtf8Charset),
435 FLC_GET_ICONV_CHARSET(my_fc),
436 in, in_size);
439 return out;
442 /* conversion from the current charset to UTF8 */
443 char *FiconvCharsetToUtf8(Display *dpy, FlocaleCharset *fc,
444 const char *in, unsigned int in_size)
446 char *out = NULL;
447 FlocaleCharset *my_fc = NULL;
449 if (!FiconvSupport)
451 return NULL;
454 my_fc = FiconvSetupConversion(dpy, fc);
455 if (my_fc == NULL)
457 return NULL;
460 #if FLOCALE_DEBUG_ICONV
461 fprintf(stderr, "[FiconvCharsetToUtf8] conversion from %s to %s\n",
462 FLC_DEBUG_GET_ICONV_CHARSET(my_fc),
463 FLC_DEBUG_GET_ICONV_CHARSET(FLCIconvUtf8Charset));
464 #endif
466 if (FLC_ENCODING_TYPE_IS_UTF_8(my_fc))
468 /* in can be a non terminate string so do not use CopyString */
469 out = safemalloc(in_size+1);
470 strncpy(out, in, in_size);
471 out[in_size]=0;
473 else
475 out = convert_charsets(
476 FLC_GET_ICONV_CHARSET(my_fc),
477 FLC_GET_ICONV_CHARSET(FLCIconvUtf8Charset),
478 in, in_size);
480 return out;
483 /* conversion from charset to charset */
484 char *FiconvCharsetToCharset(
485 Display *dpy, FlocaleCharset *in_fc, FlocaleCharset *out_fc,
486 const char *in, unsigned int in_size)
488 char *out = NULL;
489 char *tmp = NULL;
490 int tmp_len;
491 Bool free_tmp = False;
492 FlocaleCharset *my_in_fc;
493 FlocaleCharset *my_out_fc;
495 if (!FiconvSupport ||
496 (my_in_fc = FiconvSetupConversion(dpy, in_fc)) == NULL)
498 return NULL;
500 if (!FiconvSupport ||
501 (my_out_fc = FiconvSetupConversion(dpy, out_fc)) == NULL)
503 return NULL;
506 tmp = (char *)in;
507 tmp_len = in_size;
508 if (!FLC_ENCODING_TYPE_IS_UTF_8(my_in_fc))
510 tmp = FiconvCharsetToUtf8(
511 dpy, my_in_fc, (const char *)in, in_size);
512 if (tmp != NULL)
514 free_tmp = True;
515 tmp_len = strlen(tmp);
517 else
519 /* fail to convert */
520 return NULL;
524 out = tmp;
525 if (!FLC_ENCODING_TYPE_IS_UTF_8(my_out_fc))
527 out = FiconvUtf8ToCharset(
528 dpy, my_out_fc, (const char *)tmp, tmp_len);
529 if (free_tmp)
531 free(tmp);
535 return out;