Added copying conditions.
[libidn.git] / toutf8.c
bloba31a80241d7279b8a1f826f285b12d2ce87cd794
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 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
26 #ifdef HAVE_ICONV
28 #include <iconv.h>
30 #ifdef STDC_HEADERS
31 #include <stdlib.h>
32 #endif
33 #if HAVE_STRING_H
34 # if !STDC_HEADERS && HAVE_MEMORY_H
35 # include <memory.h>
36 # endif
37 # include <string.h>
38 #endif
39 #if HAVE_STRINGS_H
40 # include <strings.h>
41 #endif
43 #ifdef HAVE_ERRNO_H
44 #include <errno.h>
45 #endif
46 extern int errno;
48 #if LOCALE_WORKS
49 #include <langinfo.h>
50 #include <locale.h>
51 #endif
53 static const char *
54 stringprep_locale_charset_slow ()
56 const char *charset = getenv ("CHARSET");
57 char *p;
59 if (charset && *charset)
60 return charset;
62 #if LOCALE_WORKS
63 p = setlocale (LC_CTYPE, NULL);
64 setlocale (LC_CTYPE, "");
66 charset = nl_langinfo (CODESET);
68 setlocale (LC_CTYPE, p);
69 #endif
71 if (charset && *charset)
72 return charset;
74 return "ASCII";
77 static const char *stringprep_locale_charset_cache = NULL;
79 const char *
80 stringprep_locale_charset ()
82 if (!stringprep_locale_charset_cache)
83 stringprep_locale_charset_cache = stringprep_locale_charset_slow ();
85 return stringprep_locale_charset_cache;
88 char *
89 stringprep_convert (const char *str,
90 const char *to_codeset, const char *from_codeset)
92 iconv_t cd;
93 char *dest;
94 char *outp;
95 char *p;
96 size_t inbytes_remaining;
97 size_t outbytes_remaining;
98 size_t err;
99 size_t outbuf_size;
100 int have_error = 0;
101 int len;
103 if (strcmp (to_codeset, from_codeset) == 0)
104 return strdup (str);
106 cd = iconv_open (to_codeset, from_codeset);
108 if (cd == (iconv_t) - 1)
109 return NULL;
111 len = strlen (str);
113 p = (char *) str;
114 inbytes_remaining = len;
115 outbuf_size = len + 1; /* + 1 for nul in case len == 1 */
117 outbytes_remaining = outbuf_size - 1; /* -1 for nul */
118 outp = dest = malloc (outbuf_size);
120 again:
122 err = iconv (cd, &p, &inbytes_remaining, &outp, &outbytes_remaining);
124 if (err == (size_t) - 1)
126 switch (errno)
128 case EINVAL:
129 /* Incomplete text, do not report an error */
130 break;
132 case E2BIG:
134 size_t used = outp - dest;
136 outbuf_size *= 2;
137 dest = realloc (dest, outbuf_size);
139 outp = dest + used;
140 outbytes_remaining = outbuf_size - used - 1; /* -1 for nul */
142 goto again;
144 break;
146 case EILSEQ:
147 have_error = 1;
148 break;
150 default:
151 have_error = 1;
152 break;
156 *outp = '\0';
158 if ((p - str) != len)
159 have_error = 1;
161 iconv_close (cd);
163 if (have_error)
165 free (dest);
166 dest = NULL;
169 return dest;
172 #else
174 const char *
175 stringprep_locale_charset ()
177 return NULL;
180 char *
181 stringprep_convert (const char *str,
182 const char *to_codeset, const char *from_codeset)
184 return NULL;
187 #endif
189 char *
190 stringprep_locale_to_utf8 (const char *str)
192 return stringprep_convert (str, "UTF-8", stringprep_locale_charset ());