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 for ( outbufferlength = 1 ; outbufferlength != 0; outbufferlength <<= 1 )
141 if ( outbufferlength > length)
144 outbuf = pool_malloc (pool, outbufferlength);
147 outbytes = outbufferlength;
151 conv = create_iconv (to, from);
153 if ( (iconv_t) -1 == conv )
154 return xstrdup (text);
157 const char *ip = text;
158 result = iconv (conv, (ICONV_CONST char **) &text, &inbytes,
163 int the_error = errno;
171 *op++ = fallbackchar;
179 pool_free (pool, outbuf);
180 outbufferlength <<= 1;
181 outbuf = pool_malloc (pool, outbufferlength);
183 outbytes = outbufferlength;
188 /* should never happen */
189 fprintf (stderr, "Character conversion error: %s\n",
190 strerror (the_error));
195 } while ( -1 == result );
199 char *const oldaddr = outbuf;
200 outbuf = pool_realloc (pool, outbuf, outbufferlength + 1);
202 op += (outbuf - oldaddr) ;
215 setlocale (LC_CTYPE, "");
217 setlocale (LC_MESSAGES, "");
220 setlocale (LC_PAPER, "");
222 bindtextdomain (PACKAGE, relocate(locale_dir));
223 textdomain (PACKAGE);
224 #endif /* ENABLE_NLS */
226 assert (default_encoding == NULL);
227 default_encoding = xstrdup (locale_charset ());
234 get_default_encoding (void)
236 return default_encoding;
240 set_default_encoding (const char *enc)
242 free (default_encoding);
243 default_encoding = xstrdup (enc);
247 /* Attempts to set the encoding from a locale name
248 returns true if successfull.
249 This function does not (should not!) alter the current locale.
252 set_encoding_from_locale (const char *loc)
257 char *tmp = xstrdup (setlocale (LC_CTYPE, NULL));
259 setlocale (LC_CTYPE, "C");
260 c_encoding = xstrdup (locale_charset ());
262 setlocale (LC_CTYPE, loc);
263 loc_encoding = xstrdup (locale_charset ());
266 if ( 0 == strcmp (loc_encoding, c_encoding))
272 setlocale (LC_CTYPE, tmp);
278 free (default_encoding);
279 default_encoding = loc_encoding;
292 struct hmapx_node *node;
293 struct converter *cvtr;
295 HMAPX_FOR_EACH (cvtr, node, &map)
298 free (cvtr->fromcode);
299 iconv_close (cvtr->conv);
303 hmapx_destroy (&map);
305 free (default_encoding);
306 default_encoding = NULL;
312 valid_encoding (const char *enc)
314 iconv_t conv = iconv_open ("UTF8", enc);
316 if ( conv == (iconv_t) -1)
325 /* Return the system local's idea of the
326 decimal seperator character */
328 get_system_decimal (void)
332 char *ol = xstrdup (setlocale (LC_NUMERIC, NULL));
333 setlocale (LC_NUMERIC, "");
336 radix_char = nl_langinfo (RADIXCHAR)[0];
340 snprintf (buf, sizeof buf, "%f", 2.5);
345 /* We MUST leave LC_NUMERIC untouched, since it would
346 otherwise interfere with data_{in,out} */
347 setlocale (LC_NUMERIC, ol);