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;
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 conv = create_iconv (to, from);
143 if ( (iconv_t) -1 == conv )
144 return xstrdup (text);
146 /* Put the converter into the initial shift state, in case there was any
147 state information left over from its last usage. */
148 iconv (conv, NULL, 0, NULL, 0);
150 for ( outbufferlength = 1 ; outbufferlength != 0; outbufferlength <<= 1 )
151 if ( outbufferlength > length)
156 outbuf = pool_malloc (pool, outbufferlength);
159 outbytes = outbufferlength;
164 result = iconv (conv, (ICONV_CONST char **) &ip, &inbytes,
169 int the_error = errno;
177 *op++ = fallbackchar;
185 iconv (conv, NULL, 0, NULL, 0);
186 pool_free (pool, outbuf);
187 outbufferlength <<= 1;
188 outbuf = pool_malloc (pool, outbufferlength);
190 outbytes = outbufferlength;
195 /* should never happen */
196 fprintf (stderr, "Character conversion error: %s\n",
197 strerror (the_error));
202 } while ( -1 == result );
206 char *const oldaddr = outbuf;
207 outbuf = pool_realloc (pool, outbuf, outbufferlength + 1);
209 op += (outbuf - oldaddr) ;
222 setlocale (LC_CTYPE, "");
224 setlocale (LC_MESSAGES, "");
227 setlocale (LC_PAPER, "");
229 bindtextdomain (PACKAGE, relocate(locale_dir));
230 textdomain (PACKAGE);
231 #endif /* ENABLE_NLS */
233 assert (default_encoding == NULL);
234 default_encoding = xstrdup (locale_charset ());
241 get_default_encoding (void)
243 return default_encoding;
247 set_default_encoding (const char *enc)
249 free (default_encoding);
250 default_encoding = xstrdup (enc);
254 /* Attempts to set the encoding from a locale name
255 returns true if successfull.
256 This function does not (should not!) alter the current locale.
259 set_encoding_from_locale (const char *loc)
264 char *tmp = xstrdup (setlocale (LC_CTYPE, NULL));
266 setlocale (LC_CTYPE, "C");
267 c_encoding = xstrdup (locale_charset ());
269 setlocale (LC_CTYPE, loc);
270 loc_encoding = xstrdup (locale_charset ());
273 if ( 0 == strcmp (loc_encoding, c_encoding))
279 setlocale (LC_CTYPE, tmp);
285 free (default_encoding);
286 default_encoding = loc_encoding;
299 struct hmapx_node *node;
300 struct converter *cvtr;
302 HMAPX_FOR_EACH (cvtr, node, &map)
305 free (cvtr->fromcode);
306 iconv_close (cvtr->conv);
310 hmapx_destroy (&map);
312 free (default_encoding);
313 default_encoding = NULL;
319 valid_encoding (const char *enc)
321 iconv_t conv = iconv_open ("UTF8", enc);
323 if ( conv == (iconv_t) -1)
332 /* Return the system local's idea of the
333 decimal seperator character */
335 get_system_decimal (void)
339 char *ol = xstrdup (setlocale (LC_NUMERIC, NULL));
340 setlocale (LC_NUMERIC, "");
343 radix_char = nl_langinfo (RADIXCHAR)[0];
347 snprintf (buf, sizeof buf, "%f", 2.5);
352 /* We MUST leave LC_NUMERIC untouched, since it would
353 otherwise interfere with data_{in,out} */
354 setlocale (LC_NUMERIC, ol);