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 /* Uses CONV to convert the INBYTES starting at IP into the OUTBYTES starting
102 at OP, and appends a null terminator to the output.
104 Returns true if successful, false if the output buffer is too small. */
106 try_recode (iconv_t conv,
107 const char *ip, size_t inbytes,
108 char *op, size_t outbytes)
110 /* FIXME: Need to ensure that this char is valid in the target encoding */
111 const char fallbackchar = '?';
113 /* Put the converter into the initial shift state, in case there was any
114 state information left over from its last usage. */
115 iconv (conv, NULL, 0, NULL, 0);
117 while (iconv (conv, (ICONV_CONST char **) &ip, &inbytes,
118 &op, &outbytes) == -1)
126 *op++ = fallbackchar;
136 /* should never happen */
137 fprintf (stderr, "Character conversion error: %s\n", strerror (errno));
149 /* Converts the string TEXT, which should be encoded in FROM-encoding, to a
150 dynamically allocated string in TO-encoding. Any characters which cannot be
151 converted will be represented by '?'.
153 LENGTH should be the length of the string or -1, if null terminated.
155 The returned string will be allocated on POOL.
157 This function's behaviour differs from that of g_convert_with_fallback
158 provided by GLib. The GLib function will fail (returns NULL) if any part of
159 the input string is not valid in the declared input encoding. This function
160 however perseveres even in the presence of badly encoded input. */
162 recode_string_pool (const char *to, const char *from,
163 const char *text, int length, struct pool *pool)
165 size_t outbufferlength;
172 length = strlen(text);
175 to = default_encoding;
178 from = default_encoding;
180 conv = create_iconv (to, from);
182 if ( (iconv_t) -1 == conv )
183 return xstrdup (text);
185 for ( outbufferlength = 1 ; outbufferlength != 0; outbufferlength <<= 1 )
186 if ( outbufferlength > length)
188 char *output = pool_malloc (pool, outbufferlength);
189 if (try_recode (conv, text, length, output, outbufferlength))
191 pool_free (pool, output);
201 setlocale (LC_CTYPE, "");
203 setlocale (LC_MESSAGES, "");
206 setlocale (LC_PAPER, "");
208 bindtextdomain (PACKAGE, relocate(locale_dir));
209 textdomain (PACKAGE);
210 #endif /* ENABLE_NLS */
212 assert (default_encoding == NULL);
213 default_encoding = xstrdup (locale_charset ());
220 get_default_encoding (void)
222 return default_encoding;
226 set_default_encoding (const char *enc)
228 free (default_encoding);
229 default_encoding = xstrdup (enc);
233 /* Attempts to set the encoding from a locale name
234 returns true if successfull.
235 This function does not (should not!) alter the current locale.
238 set_encoding_from_locale (const char *loc)
243 char *tmp = xstrdup (setlocale (LC_CTYPE, NULL));
245 setlocale (LC_CTYPE, "C");
246 c_encoding = xstrdup (locale_charset ());
248 setlocale (LC_CTYPE, loc);
249 loc_encoding = xstrdup (locale_charset ());
252 if ( 0 == strcmp (loc_encoding, c_encoding))
258 setlocale (LC_CTYPE, tmp);
264 free (default_encoding);
265 default_encoding = loc_encoding;
278 struct hmapx_node *node;
279 struct converter *cvtr;
281 HMAPX_FOR_EACH (cvtr, node, &map)
284 free (cvtr->fromcode);
285 iconv_close (cvtr->conv);
289 hmapx_destroy (&map);
291 free (default_encoding);
292 default_encoding = NULL;
298 valid_encoding (const char *enc)
300 iconv_t conv = iconv_open ("UTF8", enc);
302 if ( conv == (iconv_t) -1)
311 /* Return the system local's idea of the
312 decimal seperator character */
314 get_system_decimal (void)
318 char *ol = xstrdup (setlocale (LC_NUMERIC, NULL));
319 setlocale (LC_NUMERIC, "");
322 radix_char = nl_langinfo (RADIXCHAR)[0];
326 snprintf (buf, sizeof buf, "%f", 2.5);
331 /* We MUST leave LC_NUMERIC untouched, since it would
332 otherwise interfere with data_{in,out} */
333 setlocale (LC_NUMERIC, ol);