r1107: Added a configure check for iconv.h.
[rox-filer.git] / ROX-Filer / src / gconvert.c
blobdb97104bf2b9cef85b830885d7dffaeaddf48f50
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"
36 #ifdef HAVE_ICONV_H
37 # include <iconv.h>
38 #endif
40 #include <errno.h>
41 #include <string.h>
42 #include <stdlib.h>
44 #include <stdlib.h>
45 #include <string.h>
47 #include "global.h"
49 #include "gconvert.h"
51 static gboolean
52 g_utf8_get_charset_internal (const char **a)
54 const char *charset = getenv("CHARSET");
56 if (charset && *charset)
58 *a = charset;
60 if (charset && strstr (charset, "UTF-8"))
61 return TRUE;
62 else
63 return FALSE;
66 /* Assume this for compatibility at present. */
67 *a = "ISO8859-1";
69 return FALSE;
72 static int utf8_locale_cache = -1;
73 static const char *utf8_charset_cache = NULL;
75 gboolean
76 g_get_charset (const char **charset)
78 if (utf8_locale_cache != -1)
80 if (charset)
81 *charset = utf8_charset_cache;
82 return utf8_locale_cache;
84 utf8_locale_cache = g_utf8_get_charset_internal (&utf8_charset_cache);
85 if (charset)
86 *charset = utf8_charset_cache;
87 return utf8_locale_cache;
90 /* unicode_strchr */
92 #ifdef HAVE_ICONV_H
93 size_t
94 g_iconv (GIConv converter,
95 gchar **inbuf,
96 gsize *inbytes_left,
97 gchar **outbuf,
98 gsize *outbytes_left)
100 iconv_t cd = (iconv_t)converter;
102 return iconv (cd, inbuf, inbytes_left, outbuf, outbytes_left);
105 gint
106 g_iconv_close (GIConv converter)
108 iconv_t cd = (iconv_t)converter;
110 return iconv_close (cd);
113 static GIConv
114 open_converter (const gchar *to_codeset,
115 const gchar *from_codeset,
116 GError **error)
118 GIConv cd = (GIConv) iconv_open (to_codeset, from_codeset);
120 if (cd == (iconv_t) -1)
122 /* Something went wrong. */
123 if (errno == EINVAL)
124 g_warning("Conversion from character set '%s' to '%s' is not supported",
125 from_codeset, to_codeset);
126 else
127 g_warning("Could not open converter from '%s' to '%s': %s",
128 from_codeset, to_codeset, strerror (errno));
131 return cd;
134 #endif
136 gchar*
137 g_convert (const gchar *str,
138 gssize len,
139 const gchar *to_codeset,
140 const gchar *from_codeset,
141 gsize *bytes_read,
142 gsize *bytes_written,
143 GError **error)
145 gchar *res;
146 #ifdef HAVE_ICONV_H
147 GIConv cd;
149 g_return_val_if_fail (str != NULL, NULL);
150 g_return_val_if_fail (to_codeset != NULL, NULL);
151 g_return_val_if_fail (from_codeset != NULL, NULL);
153 cd = open_converter (to_codeset, from_codeset, error);
155 if (cd == (GIConv) -1)
157 if (bytes_read)
158 *bytes_read = 0;
160 if (bytes_written)
161 *bytes_written = 0;
163 return NULL;
166 res = g_convert_with_iconv (str, len, cd,
167 bytes_read, bytes_written,
168 error);
170 g_iconv_close (cd);
171 #else
172 res = g_strdup(str);
173 #endif
175 return res;
178 #ifdef HAVE_ICONV_H
179 gchar*
180 g_convert_with_iconv (const gchar *str,
181 gssize len,
182 GIConv converter,
183 gsize *bytes_read,
184 gsize *bytes_written,
185 GError **error)
187 gchar *dest;
188 gchar *outp;
189 const gchar *p;
190 gsize inbytes_remaining;
191 gsize outbytes_remaining;
192 gsize err;
193 gsize outbuf_size;
194 gboolean have_error = FALSE;
196 g_return_val_if_fail (str != NULL, NULL);
197 g_return_val_if_fail (converter != (GIConv) -1, NULL);
199 if (len < 0)
200 len = strlen (str);
202 p = str;
203 inbytes_remaining = len;
204 outbuf_size = len + 1; /* + 1 for nul in case len == 1 */
206 outbytes_remaining = outbuf_size - 1; /* -1 for nul */
207 outp = dest = g_malloc (outbuf_size);
209 again:
211 err = g_iconv (converter, (char **)&p, &inbytes_remaining, &outp, &outbytes_remaining);
213 if (err == (size_t) -1)
215 switch (errno)
217 case EINVAL:
218 /* Incomplete text, do not report an error */
219 break;
220 case E2BIG:
222 size_t used = outp - dest;
224 outbuf_size *= 2;
225 dest = g_realloc (dest, outbuf_size);
227 outp = dest + used;
228 outbytes_remaining = outbuf_size - used - 1; /* -1 for nul */
230 goto again;
232 case EILSEQ:
233 g_warning("Invalid byte sequence in conversion input");
234 have_error = TRUE;
235 break;
236 default:
237 g_warning("Error during conversion: %s", strerror (errno));
238 have_error = TRUE;
239 break;
243 *outp = '\0';
245 if (bytes_read)
246 *bytes_read = p - str;
247 else
249 if ((p - str) != len)
251 if (!have_error)
253 g_warning("Partial character sequence at end of input");
254 have_error = TRUE;
259 if (bytes_written)
260 *bytes_written = outp - dest; /* Doesn't include '\0' */
262 if (have_error)
264 g_free (dest);
265 return NULL;
267 else
268 return dest;
270 #endif
272 gchar *
273 g_locale_to_utf8 (const gchar *opsysstring,
274 gssize len,
275 gsize *bytes_read,
276 gsize *bytes_written,
277 GError **error)
279 const char *charset;
281 if (g_get_charset (&charset))
282 return g_strdup (opsysstring);
283 else
284 return g_convert (opsysstring, len,
285 "UTF-8", charset, bytes_read, bytes_written, error);
288 gchar *
289 g_locale_from_utf8 (const gchar *utf8string,
290 gssize len,
291 gsize *bytes_read,
292 gsize *bytes_written,
293 GError **error)
295 const gchar *charset;
297 if (g_get_charset (&charset))
298 return g_strdup (utf8string);
299 else
300 return g_convert (utf8string, len,
301 charset, "UTF-8", bytes_read, bytes_written, error);
304 #endif