r1101: Big changes to internationalisation for pinboards and panels to fix problems
[rox-filer.git] / ROX-Filer / src / gconvert.c
blob70288bc72fdde9ed5b46307cd0218c3b7d226372
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18 * Place, Suite 330, Boston, MA 02111-1307 USA
21 /* This code is taken from glib2 and has been converted to the GPL, as allowed
22 * under the terms of the LGPL. Removed lots of stuff! When we move fully to
23 * glib2, this file will disappear.
25 * gconvert.c: Convert between character sets using iconv
26 * Copyright Red Hat Inc., 2000
27 * Authors: Havoc Pennington <hp@redhat.com>, Owen Taylor <otaylor@redhat.com
30 #include "config.h"
32 #ifndef GTK2
34 #include "gunicode.h"
35 #include <iconv.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <stdlib.h>
40 #include <stdlib.h>
41 #include <string.h>
43 #include "global.h"
45 #include "gconvert.h"
47 static gboolean
48 g_utf8_get_charset_internal (const char **a)
50 const char *charset = getenv("CHARSET");
52 if (charset && *charset)
54 *a = charset;
56 if (charset && strstr (charset, "UTF-8"))
57 return TRUE;
58 else
59 return FALSE;
62 /* Assume this for compatibility at present. */
63 *a = "iso-8859-1";
65 return FALSE;
68 static int utf8_locale_cache = -1;
69 static const char *utf8_charset_cache = NULL;
71 gboolean
72 g_get_charset (const char **charset)
74 if (utf8_locale_cache != -1)
76 if (charset)
77 *charset = utf8_charset_cache;
78 return utf8_locale_cache;
80 utf8_locale_cache = g_utf8_get_charset_internal (&utf8_charset_cache);
81 if (charset)
82 *charset = utf8_charset_cache;
83 return utf8_locale_cache;
86 /* unicode_strchr */
89 #if defined(USE_LIBICONV) && !defined (_LIBICONV_H)
90 #error libiconv in use but included iconv.h not from libiconv
91 #endif
92 #if !defined(USE_LIBICONV) && defined (_LIBICONV_H)
93 #error libiconv not in use but included iconv.h is from libiconv
94 #endif
96 size_t
97 g_iconv (GIConv converter,
98 gchar **inbuf,
99 gsize *inbytes_left,
100 gchar **outbuf,
101 gsize *outbytes_left)
103 iconv_t cd = (iconv_t)converter;
105 return iconv (cd, inbuf, inbytes_left, outbuf, outbytes_left);
108 gint
109 g_iconv_close (GIConv converter)
111 iconv_t cd = (iconv_t)converter;
113 return iconv_close (cd);
116 static GIConv
117 open_converter (const gchar *to_codeset,
118 const gchar *from_codeset,
119 GError **error)
121 GIConv cd = (GIConv) iconv_open (to_codeset, from_codeset);
123 if (cd == (iconv_t) -1)
125 /* Something went wrong. */
126 if (errno == EINVAL)
127 g_warning("Conversion from character set '%s' to '%s' is not supported",
128 from_codeset, to_codeset);
129 else
130 g_warning("Could not open converter from '%s' to '%s': %s",
131 from_codeset, to_codeset, strerror (errno));
134 return cd;
138 gchar*
139 g_convert (const gchar *str,
140 gssize len,
141 const gchar *to_codeset,
142 const gchar *from_codeset,
143 gsize *bytes_read,
144 gsize *bytes_written,
145 GError **error)
147 gchar *res;
148 GIConv cd;
150 g_return_val_if_fail (str != NULL, NULL);
151 g_return_val_if_fail (to_codeset != NULL, NULL);
152 g_return_val_if_fail (from_codeset != NULL, NULL);
154 cd = open_converter (to_codeset, from_codeset, error);
156 if (cd == (GIConv) -1)
158 if (bytes_read)
159 *bytes_read = 0;
161 if (bytes_written)
162 *bytes_written = 0;
164 return NULL;
167 res = g_convert_with_iconv (str, len, cd,
168 bytes_read, bytes_written,
169 error);
171 g_iconv_close (cd);
173 return res;
176 gchar*
177 g_convert_with_iconv (const gchar *str,
178 gssize len,
179 GIConv converter,
180 gsize *bytes_read,
181 gsize *bytes_written,
182 GError **error)
184 gchar *dest;
185 gchar *outp;
186 const gchar *p;
187 gsize inbytes_remaining;
188 gsize outbytes_remaining;
189 gsize err;
190 gsize outbuf_size;
191 gboolean have_error = FALSE;
193 g_return_val_if_fail (str != NULL, NULL);
194 g_return_val_if_fail (converter != (GIConv) -1, NULL);
196 if (len < 0)
197 len = strlen (str);
199 p = str;
200 inbytes_remaining = len;
201 outbuf_size = len + 1; /* + 1 for nul in case len == 1 */
203 outbytes_remaining = outbuf_size - 1; /* -1 for nul */
204 outp = dest = g_malloc (outbuf_size);
206 again:
208 err = g_iconv (converter, (char **)&p, &inbytes_remaining, &outp, &outbytes_remaining);
210 if (err == (size_t) -1)
212 switch (errno)
214 case EINVAL:
215 /* Incomplete text, do not report an error */
216 break;
217 case E2BIG:
219 size_t used = outp - dest;
221 outbuf_size *= 2;
222 dest = g_realloc (dest, outbuf_size);
224 outp = dest + used;
225 outbytes_remaining = outbuf_size - used - 1; /* -1 for nul */
227 goto again;
229 case EILSEQ:
230 g_warning("Invalid byte sequence in conversion input");
231 have_error = TRUE;
232 break;
233 default:
234 g_warning("Error during conversion: %s", strerror (errno));
235 have_error = TRUE;
236 break;
240 *outp = '\0';
242 if (bytes_read)
243 *bytes_read = p - str;
244 else
246 if ((p - str) != len)
248 if (!have_error)
250 g_warning("Partial character sequence at end of input");
251 have_error = TRUE;
256 if (bytes_written)
257 *bytes_written = outp - dest; /* Doesn't include '\0' */
259 if (have_error)
261 g_free (dest);
262 return NULL;
264 else
265 return dest;
268 gchar *
269 g_locale_to_utf8 (const gchar *opsysstring,
270 gssize len,
271 gsize *bytes_read,
272 gsize *bytes_written,
273 GError **error)
275 const char *charset;
277 if (g_get_charset (&charset))
278 return g_strdup (opsysstring);
279 else
280 return g_convert (opsysstring, len,
281 "UTF-8", charset, bytes_read, bytes_written, error);
284 gchar *
285 g_locale_from_utf8 (const gchar *utf8string,
286 gssize len,
287 gsize *bytes_read,
288 gsize *bytes_written,
289 GError **error)
291 const gchar *charset;
293 if (g_get_charset (&charset))
294 return g_strdup (utf8string);
295 else
296 return g_convert (utf8string, len,
297 charset, "UTF-8", bytes_read, bytes_written, error);
300 #endif