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)
124 *op++ = fallbackchar;
131 *op++ = fallbackchar;
141 /* should never happen */
142 fprintf (stderr, "Character conversion error: %s\n", strerror (errno));
154 /* Converts the string TEXT, which should be encoded in FROM-encoding, to a
155 dynamically allocated string in TO-encoding. Any characters which cannot be
156 converted will be represented by '?'.
158 LENGTH should be the length of the string or -1, if null terminated.
160 The returned string will be allocated on POOL.
162 This function's behaviour differs from that of g_convert_with_fallback
163 provided by GLib. The GLib function will fail (returns NULL) if any part of
164 the input string is not valid in the declared input encoding. This function
165 however perseveres even in the presence of badly encoded input. */
167 recode_string_pool (const char *to, const char *from,
168 const char *text, int length, struct pool *pool)
170 size_t outbufferlength;
177 length = strlen(text);
180 to = default_encoding;
183 from = default_encoding;
185 conv = create_iconv (to, from);
187 if ( (iconv_t) -1 == conv )
188 return xstrdup (text);
190 for ( outbufferlength = 1 ; outbufferlength != 0; outbufferlength <<= 1 )
191 if ( outbufferlength > length)
193 char *output = pool_malloc (pool, outbufferlength);
194 if (try_recode (conv, text, length, output, outbufferlength))
196 pool_free (pool, output);
206 setlocale (LC_CTYPE, "");
208 setlocale (LC_MESSAGES, "");
211 setlocale (LC_PAPER, "");
213 bindtextdomain (PACKAGE, relocate(locale_dir));
214 textdomain (PACKAGE);
215 #endif /* ENABLE_NLS */
217 assert (default_encoding == NULL);
218 default_encoding = xstrdup (locale_charset ());
225 get_default_encoding (void)
227 return default_encoding;
231 set_default_encoding (const char *enc)
233 free (default_encoding);
234 default_encoding = xstrdup (enc);
238 /* Attempts to set the encoding from a locale name
239 returns true if successfull.
240 This function does not (should not!) alter the current locale.
243 set_encoding_from_locale (const char *loc)
248 char *tmp = xstrdup (setlocale (LC_CTYPE, NULL));
250 setlocale (LC_CTYPE, "C");
251 c_encoding = xstrdup (locale_charset ());
253 setlocale (LC_CTYPE, loc);
254 loc_encoding = xstrdup (locale_charset ());
257 if ( 0 == strcmp (loc_encoding, c_encoding))
263 setlocale (LC_CTYPE, tmp);
269 free (default_encoding);
270 default_encoding = loc_encoding;
283 struct hmapx_node *node;
284 struct converter *cvtr;
286 HMAPX_FOR_EACH (cvtr, node, &map)
289 free (cvtr->fromcode);
290 iconv_close (cvtr->conv);
294 hmapx_destroy (&map);
296 free (default_encoding);
297 default_encoding = NULL;
303 valid_encoding (const char *enc)
305 iconv_t conv = iconv_open ("UTF8", enc);
307 if ( conv == (iconv_t) -1)
316 /* Return the system local's idea of the
317 decimal seperator character */
319 get_system_decimal (void)
323 char *ol = xstrdup (setlocale (LC_NUMERIC, NULL));
324 setlocale (LC_NUMERIC, "");
327 radix_char = nl_langinfo (RADIXCHAR)[0];
331 snprintf (buf, sizeof buf, "%f", 2.5);
336 /* We MUST leave LC_NUMERIC untouched, since it would
337 otherwise interfere with data_{in,out} */
338 setlocale (LC_NUMERIC, ol);