1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2006, 2009 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 instead of
91 in a pool. It is the caller's responsibility to free the returned value. */
93 recode_string (const char *to, const char *from,
94 const char *text, int length)
96 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
103 be 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 provided
110 by GLib. The GLib function will fail (returns NULL) if any part of the input
111 string is not valid in the declared input encoding. This function however perseveres
112 even in the presence of badly encoded input.
115 recode_string_pool (const char *to, const char *from,
116 const char *text, int length, struct pool *pool)
119 size_t outbufferlength;
126 /* FIXME: Need to ensure that this char is valid in the target encoding */
127 const char fallbackchar = '?';
133 length = strlen(text);
136 to = default_encoding;
139 from = default_encoding;
141 for ( outbufferlength = 1 ; outbufferlength != 0; outbufferlength <<= 1 )
142 if ( outbufferlength > length)
145 outbuf = pool_malloc (pool, outbufferlength);
148 outbytes = outbufferlength;
152 conv = create_iconv (to, from);
154 if ( (iconv_t) -1 == conv )
155 return xstrdup (text);
158 const char *ip = text;
159 result = iconv (conv, (ICONV_CONST char **) &text, &inbytes,
164 int the_error = errno;
172 *op++ = fallbackchar;
181 outbufferlength <<= 1;
182 outbuf = pool_malloc (pool, outbufferlength);
184 outbytes = outbufferlength;
189 /* should never happen */
190 fprintf (stderr, "Character conversion error: %s\n", 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;
294 HMAPX_FOR_EACH (cvtr, node, &map)
296 iconv_close (cvtr->conv);
300 hmapx_destroy (&map);
302 free (default_encoding);
303 default_encoding = NULL;
309 valid_encoding (const char *enc)
311 iconv_t conv = iconv_open ("UTF8", enc);
313 if ( conv == (iconv_t) -1)
322 /* Return the system local's idea of the
323 decimal seperator character */
325 get_system_decimal (void)
329 char *ol = xstrdup (setlocale (LC_NUMERIC, NULL));
330 setlocale (LC_NUMERIC, "");
333 radix_char = nl_langinfo (RADIXCHAR)[0];
337 snprintf (buf, sizeof buf, "%f", 2.5);
342 /* We MUST leave LC_NUMERIC untouched, since it would
343 otherwise interfere with data_{in,out} */
344 setlocale (LC_NUMERIC, ol);