devctl.h: update for POSIX-1.2024
[newlib-cygwin.git] / newlib / libc / iconv / lib / iconv.c
blob458541cb94841ec1441cf614a3cedef5a8a11467
1 /*
2 * Copyright (c) 2003-2004, Artem B. Bityuckiy
3 * Copyright (c) 1999,2000, Konstantin Chuguev. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
28 FUNCTION
29 <<iconv>>, <<iconv_open>>, <<iconv_close>>---charset conversion routines
31 INDEX
32 iconv
33 INDEX
34 iconv_open
35 INDEX
36 iconv_close
37 INDEX
38 _iconv_r
39 INDEX
40 _iconv_open_r
41 INDEX
42 _iconv_close_r
44 SYNOPSIS
45 #include <iconv.h>
46 iconv_t iconv_open (const char *<[to]>, const char *<[from]>);
47 int iconv_close (iconv_t <[cd]>);
48 size_t iconv (iconv_t <[cd]>, char **restrict <[inbuf]>,
49 size_t *restrict <[inbytesleft]>,
50 char **restrict <[outbuf]>,
51 size_t *restrict <[outbytesleft]>);
53 iconv_t _iconv_open_r (struct _reent *<[rptr]>,
54 const char *<[to]>, const char *<[from]>);
55 int _iconv_close_r (struct _reent *<[rptr]>, iconv_t <[cd]>);
56 size_t _iconv_r (struct _reent *<[rptr]>,
57 iconv_t <[cd]>, const char **<[inbuf]>,
58 size_t *<[inbytesleft]>,
59 char **<[outbuf]>, size_t *<[outbytesleft]>);
61 DESCRIPTION
62 The function <<iconv>> converts characters from <[in]> which are in one
63 encoding to characters of another encoding, outputting them to <[out]>.
64 The value <[inleft]> specifies the number of input bytes to convert whereas
65 the value <[outleft]> specifies the size remaining in the <[out]> buffer.
66 The conversion descriptor <[cd]> specifies the conversion being performed
67 and is created via <<iconv_open>>.
69 An <<iconv>> conversion stops if: the input bytes are exhausted, the output
70 buffer is full, an invalid input character sequence occurs, or the
71 conversion specifier is invalid.
73 The function <<iconv_open>> is used to specify a conversion from one
74 encoding: <[from]> to another: <[to]>. The result of the call is
75 to create a conversion specifier that can be used with <<iconv>>.
77 The function <<iconv_close>> is used to close a conversion specifier after
78 it is no longer needed.
80 The <<_iconv_r>>, <<_iconv_open_r>>, and <<_iconv_close_r>> functions are
81 reentrant versions of <<iconv>>, <<iconv_open>>, and <<iconv_close>>,
82 respectively. An additional reentrancy struct pointer: <[rptr]> is passed
83 to properly set <<errno>>.
85 RETURNS
86 The <<iconv>> function returns the number of non-identical conversions
87 performed. If an error occurs, (size_t)-1 is returned and <<errno>>
88 is set appropriately. The values of <[inleft]>, <[in]>, <[out]>,
89 and <[outleft]> are modified to indicate how much input was processed
90 and how much output was created.
92 The <<iconv_open>> function returns either a valid conversion specifier
93 or (iconv_t)-1 to indicate failure. If failure occurs, <<errno>> is set
94 appropriately.
96 The <<iconv_close>> function returns 0 on success or -1 on failure.
97 If failure occurs <<errno>> is set appropriately.
99 PORTABILITY
100 <<iconv>>, <<iconv_open>>, and <<iconv_close>> are non-ANSI and are specified
101 by the Single Unix specification.
103 No supporting OS subroutine calls are required.
105 #include <_ansi.h>
106 #include <reent.h>
107 #include <sys/types.h>
108 #include <errno.h>
109 #include <string.h>
110 #include <stdlib.h>
111 #include <iconv.h>
112 #include <wchar.h>
113 #include <sys/iconvnls.h>
114 #include "local.h"
115 #include "conv.h"
116 #include "ucsconv.h"
119 * iconv interface functions as specified by Single Unix specification.
122 iconv_t
123 iconv_open (const char *to,
124 const char *from)
126 return _iconv_open_r (_REENT, to, from);
130 size_t
131 iconv (iconv_t cd,
132 char **__restrict inbuf,
133 size_t *__restrict inbytesleft,
134 char **__restrict outbuf,
135 size_t *__restrict outbytesleft)
137 return _iconv_r (_REENT, cd, (const char **) inbuf, inbytesleft,
138 outbuf, outbytesleft);
143 iconv_close (iconv_t cd)
145 return _iconv_close_r (_REENT, cd);
149 #ifndef _REENT_ONLY
150 iconv_t
151 _iconv_open_r (struct _reent *rptr,
152 const char *to,
153 const char *from)
155 iconv_conversion_t *ic;
157 if (to == NULL || from == NULL || *to == '\0' || *from == '\0')
158 return (iconv_t)-1;
160 if ((to = (const char *)_iconv_resolve_encoding_name (rptr, to)) == NULL)
161 return (iconv_t)-1;
163 if ((from = (const char *)_iconv_resolve_encoding_name (rptr, from)) == NULL)
165 _free_r (rptr, (void *)to);
166 return (iconv_t)-1;
169 ic = (iconv_conversion_t *)_malloc_r (rptr, sizeof (iconv_conversion_t));
170 if (ic == NULL)
171 return (iconv_t)-1;
173 /* Select which conversion type to use */
174 if (strcmp (from, to) == 0)
176 /* Use null conversion */
177 ic->handlers = &_iconv_null_conversion_handlers;
178 ic->data = ic->handlers->open (rptr, to, from);
180 else
182 /* Use UCS-based conversion */
183 ic->handlers = &_iconv_ucs_conversion_handlers;
184 ic->data = ic->handlers->open (rptr, to, from);
187 _free_r (rptr, (void *)to);
188 _free_r (rptr, (void *)from);
190 if (ic->data == NULL)
192 _free_r (rptr, (void *)ic);
193 return (iconv_t)-1;
196 return (void *)ic;
200 size_t
201 _iconv_r (struct _reent *rptr,
202 iconv_t cd,
203 const char **inbuf,
204 size_t *inbytesleft,
205 char **outbuf,
206 size_t *outbytesleft)
208 iconv_conversion_t *ic = (iconv_conversion_t *)cd;
210 if ((void *)cd == NULL || cd == (iconv_t)-1 || ic->data == NULL
211 || (ic->handlers != &_iconv_null_conversion_handlers
212 && ic->handlers != &_iconv_ucs_conversion_handlers))
214 _REENT_ERRNO (rptr) = EBADF;
215 return (size_t)-1;
218 if (inbuf == NULL || *inbuf == NULL)
220 mbstate_t state_null = ICONV_ZERO_MB_STATE_T;
222 if (!ic->handlers->is_stateful(ic->data, 1))
223 return (size_t)0;
225 if (outbuf == NULL || *outbuf == NULL)
227 /* Reset shift state */
228 ic->handlers->set_state (ic->data, &state_null, 1);
230 return (size_t)0;
233 if (outbytesleft != NULL)
235 mbstate_t state_save = ICONV_ZERO_MB_STATE_T;
237 /* Save current shift state */
238 ic->handlers->get_state (ic->data, &state_save, 1);
240 /* Reset shift state */
241 ic->handlers->set_state (ic->data, &state_null, 1);
243 /* Get initial shift state sequence and it's length */
244 ic->handlers->get_state (ic->data, &state_null, 1);
246 if (*outbytesleft >= state_null.__count)
248 memcpy ((void *)(*outbuf), (void *)&state_null, state_null.__count);
250 *outbuf += state_null.__count;
251 *outbytesleft -= state_null.__count;
253 return (size_t)0;
256 /* Restore shift state if output buffer is too small */
257 ic->handlers->set_state (ic->data, &state_save, 1);
260 _REENT_ERRNO (rptr) = E2BIG;
261 return (size_t)-1;
264 if (*inbytesleft == 0)
266 _REENT_ERRNO (rptr) = EINVAL;
267 return (size_t)-1;
270 if (*outbytesleft == 0 || *outbuf == NULL)
272 _REENT_ERRNO (rptr) = E2BIG;
273 return (size_t)-1;
276 return ic->handlers->convert (rptr,
277 ic->data,
278 (const unsigned char**)inbuf,
279 inbytesleft,
280 (unsigned char**)outbuf,
281 outbytesleft,
287 _iconv_close_r (struct _reent *rptr,
288 iconv_t cd)
290 int res;
291 iconv_conversion_t *ic = (iconv_conversion_t *)cd;
293 if ((void *)cd == NULL || cd == (iconv_t)-1 || ic->data == NULL
294 || (ic->handlers != &_iconv_null_conversion_handlers
295 && ic->handlers != &_iconv_ucs_conversion_handlers))
297 _REENT_ERRNO (rptr) = EBADF;
298 return -1;
301 res = (int)ic->handlers->close (rptr, ic->data);
303 _free_r (rptr, (void *)cd);
305 return res;
307 #endif /* !_REENT_ONLY */