Release 0.0.6.
[libidn.git] / toutf8.c
blobb78cc515328880d40cd8357ba4047310d816138e
1 /* toutf8.c convert strings from system locale into UTF-8
2 * Copyright (C) 2002 Simon Josefsson
4 * This file is part of libstringprep.
6 * Libstringprep is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * Libstringprep is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with libstringprep; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "internal.h"
24 #ifdef HAVE_ICONV
26 #include <iconv.h>
28 #if LOCALE_WORKS
29 #include <langinfo.h>
30 #include <locale.h>
31 #endif
33 static const char *
34 stringprep_locale_charset_slow ()
36 const char *charset = getenv ("CHARSET");
37 char *p;
39 if (charset && *charset)
40 return charset;
42 #if LOCALE_WORKS
43 p = setlocale (LC_CTYPE, NULL);
44 setlocale (LC_CTYPE, "");
46 charset = nl_langinfo (CODESET);
48 setlocale (LC_CTYPE, p);
49 #endif
51 if (charset && *charset)
52 return charset;
54 return "ASCII";
57 static const char *stringprep_locale_charset_cache = NULL;
59 const char *
60 stringprep_locale_charset ()
62 if (!stringprep_locale_charset_cache)
63 stringprep_locale_charset_cache = stringprep_locale_charset_slow ();
65 return stringprep_locale_charset_cache;
68 char *
69 stringprep_convert (const char *str,
70 const char *to_codeset, const char *from_codeset)
72 iconv_t cd;
73 char *dest;
74 char *outp;
75 char *p;
76 size_t inbytes_remaining;
77 size_t outbytes_remaining;
78 size_t err;
79 size_t outbuf_size;
80 int have_error = 0;
81 int len;
83 if (strcmp (to_codeset, from_codeset) == 0)
84 return strdup (str);
86 cd = iconv_open (to_codeset, from_codeset);
88 if (cd == (iconv_t) - 1)
89 return NULL;
91 len = strlen (str);
93 p = (char *) str;
94 inbytes_remaining = len;
95 outbuf_size = len + 1; /* + 1 for nul in case len == 1 */
97 outbytes_remaining = outbuf_size - 1; /* -1 for nul */
98 outp = dest = malloc (outbuf_size);
100 again:
102 err = iconv (cd, &p, &inbytes_remaining, &outp, &outbytes_remaining);
104 if (err == (size_t) - 1)
106 switch (errno)
108 case EINVAL:
109 /* Incomplete text, do not report an error */
110 break;
112 case E2BIG:
114 size_t used = outp - dest;
116 outbuf_size *= 2;
117 dest = realloc (dest, outbuf_size);
119 outp = dest + used;
120 outbytes_remaining = outbuf_size - used - 1; /* -1 for nul */
122 goto again;
124 break;
126 case EILSEQ:
127 have_error = 1;
128 break;
130 default:
131 have_error = 1;
132 break;
136 *outp = '\0';
138 if ((p - str) != len)
139 have_error = 1;
141 iconv_close (cd);
143 if (have_error)
145 free (dest);
146 dest = NULL;
149 return dest;
152 #else
154 const char *
155 stringprep_locale_charset ()
157 return NULL;
160 char *
161 stringprep_convert (const char *str,
162 const char *to_codeset, const char *from_codeset)
164 return NULL;
167 #endif
169 char *
170 stringprep_locale_to_utf8 (const char *str)
172 return stringprep_convert (str, "UTF-8", stringprep_locale_charset ());