1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2006, 2009, 2010 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
27 #include <relocatable.h>
28 #include "assertion.h"
30 #include "hash-functions.h"
37 #include <localcharset.h>
51 static char *default_encoding;
52 static struct hmapx map;
54 /* A wrapper around iconv_open */
56 create_iconv (const char* tocode, const char* fromcode)
59 struct hmapx_node *node;
60 struct converter *converter;
63 hash = hash_string (tocode, hash_string (fromcode, 0));
64 HMAPX_FOR_EACH_WITH_HASH (converter, node, hash, &map)
65 if (!strcmp (tocode, converter->tocode)
66 && !strcmp (fromcode, converter->fromcode))
67 return converter->conv;
69 converter = xmalloc (sizeof *converter);
70 converter->tocode = xstrdup (tocode);
71 converter->fromcode = xstrdup (fromcode);
72 converter->conv = iconv_open (tocode, fromcode);
73 hmapx_insert (&map, converter, hash);
75 /* I don't think it's safe to translate this string or to use messaging
76 as the converters have not yet been set up */
77 if ( (iconv_t) -1 == converter->conv && 0 != strcmp (tocode, fromcode))
79 const int err = errno;
82 "cannot create a converter for `%s' to `%s': %s\n",
83 fromcode, tocode, strerror (err));
86 return converter->conv;
90 /* Similar to recode_string_pool, but allocates the returned value on the heap
91 instead of in a pool. It is the caller's responsibility to free the
94 recode_string (const char *to, const char *from,
95 const char *text, int length)
97 return recode_string_pool (to, from, text, length, NULL);
101 /* Converts the string TEXT, which should be encoded in FROM-encoding, to a
102 dynamically allocated string in TO-encoding. Any characters which cannot be
103 converted will be represented by '?'.
105 LENGTH should be the length of the string or -1, if null terminated.
107 The returned string will be allocated on POOL.
109 This function's behaviour differs from that of g_convert_with_fallback
110 provided by GLib. The GLib function will fail (returns NULL) if any part of
111 the input string is not valid in the declared input encoding. This function
112 however perseveres even in the presence of badly encoded input. */
114 recode_string_pool (const char *to, const char *from,
115 const char *text, int length, struct pool *pool)
118 size_t outbufferlength;
125 /* FIXME: Need to ensure that this char is valid in the target encoding */
126 const char fallbackchar = '?';
132 length = strlen(text);
135 to = default_encoding;
138 from = default_encoding;
140 conv = create_iconv (to, from);
142 if ( (iconv_t) -1 == conv )
143 return xstrdup (text);
145 /* Put the converter into the initial shift state, in case there was any
146 state information left over from its last usage. */
147 iconv (conv, NULL, 0, NULL, 0);
149 for ( outbufferlength = 1 ; outbufferlength != 0; outbufferlength <<= 1 )
150 if ( outbufferlength > length)
153 outbuf = pool_malloc (pool, outbufferlength);
156 outbytes = outbufferlength;
161 const char *ip = text;
162 result = iconv (conv, (ICONV_CONST char **) &text, &inbytes,
167 int the_error = errno;
175 *op++ = fallbackchar;
183 iconv (conv, NULL, 0, NULL, 0);
184 pool_free (pool, outbuf);
185 outbufferlength <<= 1;
186 outbuf = pool_malloc (pool, outbufferlength);
188 outbytes = outbufferlength;
193 /* should never happen */
194 fprintf (stderr, "Character conversion error: %s\n",
195 strerror (the_error));
200 } while ( -1 == result );
204 char *const oldaddr = outbuf;
205 outbuf = pool_realloc (pool, outbuf, outbufferlength + 1);
207 op += (outbuf - oldaddr) ;
220 setlocale (LC_CTYPE, "");
222 setlocale (LC_MESSAGES, "");
225 setlocale (LC_PAPER, "");
227 bindtextdomain (PACKAGE, relocate(locale_dir));
228 textdomain (PACKAGE);
229 #endif /* ENABLE_NLS */
231 assert (default_encoding == NULL);
232 default_encoding = xstrdup (locale_charset ());
239 get_default_encoding (void)
241 return default_encoding;
245 set_default_encoding (const char *enc)
247 free (default_encoding);
248 default_encoding = xstrdup (enc);
252 /* Attempts to set the encoding from a locale name
253 returns true if successfull.
254 This function does not (should not!) alter the current locale.
257 set_encoding_from_locale (const char *loc)
262 char *tmp = xstrdup (setlocale (LC_CTYPE, NULL));
264 setlocale (LC_CTYPE, "C");
265 c_encoding = xstrdup (locale_charset ());
267 setlocale (LC_CTYPE, loc);
268 loc_encoding = xstrdup (locale_charset ());
271 if ( 0 == strcmp (loc_encoding, c_encoding))
277 setlocale (LC_CTYPE, tmp);
283 free (default_encoding);
284 default_encoding = loc_encoding;
297 struct hmapx_node *node;
298 struct converter *cvtr;
300 HMAPX_FOR_EACH (cvtr, node, &map)
303 free (cvtr->fromcode);
304 iconv_close (cvtr->conv);
308 hmapx_destroy (&map);
310 free (default_encoding);
311 default_encoding = NULL;
317 valid_encoding (const char *enc)
319 iconv_t conv = iconv_open ("UTF8", enc);
321 if ( conv == (iconv_t) -1)
330 /* Return the system local's idea of the
331 decimal seperator character */
333 get_system_decimal (void)
337 char *ol = xstrdup (setlocale (LC_NUMERIC, NULL));
338 setlocale (LC_NUMERIC, "");
341 radix_char = nl_langinfo (RADIXCHAR)[0];
345 snprintf (buf, sizeof buf, "%f", 2.5);
350 /* We MUST leave LC_NUMERIC untouched, since it would
351 otherwise interfere with data_{in,out} */
352 setlocale (LC_NUMERIC, ol);