source: trunk/libs/newlib/src/newlib/libc/iconv/lib/iconv.c @ 444

Last change on this file since 444 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 9.0 KB
Line 
1/*
2 * Copyright (c) 2003-2004, Artem B. Bityuckiy
3 * Copyright (c) 1999,2000, Konstantin Chuguev. All rights reserved.
4 *
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.
13 *
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.
25 */
26
27/*
28FUNCTION
29<<iconv>>, <<iconv_open>>, <<iconv_close>>---charset conversion routines
30
31INDEX
32        iconv
33INDEX
34        iconv_open
35INDEX
36        iconv_close
37INDEX
38        _iconv_r
39INDEX
40        _iconv_open_r
41INDEX
42        _iconv_close_r
43
44SYNOPSIS
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]>);
52
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]>);
60
61DESCRIPTION
62The function <<iconv>> converts characters from <[in]> which are in one
63encoding to characters of another encoding, outputting them to <[out]>.
64The value <[inleft]> specifies the number of input bytes to convert whereas
65the value <[outleft]> specifies the size remaining in the <[out]> buffer.
66The conversion descriptor <[cd]> specifies the conversion being performed
67and is created via <<iconv_open>>.
68
69An <<iconv>> conversion stops if: the input bytes are exhausted, the output
70buffer is full, an invalid input character sequence occurs, or the
71conversion specifier is invalid.
72
73The function <<iconv_open>> is used to specify a conversion from one
74encoding: <[from]> to another: <[to]>.  The result of the call is
75to create a conversion specifier that can be used with <<iconv>>.
76
77The function <<iconv_close>> is used to close a conversion specifier after
78it is no longer needed.
79
80The <<_iconv_r>>, <<_iconv_open_r>>, and <<_iconv_close_r>> functions are
81reentrant versions of <<iconv>>, <<iconv_open>>, and <<iconv_close>>,
82respectively.  An additional reentrancy struct pointer: <[rptr]> is passed
83to properly set <<errno>>.
84
85RETURNS
86The <<iconv>> function returns the number of non-identical conversions
87performed.  If an error occurs, (size_t)-1 is returned and <<errno>>
88is set appropriately.  The values of <[inleft]>, <[in]>, <[out]>,
89and <[outleft]> are modified to indicate how much input was processed
90and how much output was created.
91
92The <<iconv_open>> function returns either a valid conversion specifier
93or (iconv_t)-1 to indicate failure.  If failure occurs, <<errno>> is set
94appropriately.
95
96The <<iconv_close>> function returns 0 on success or -1 on failure.
97If failure occurs <<errno>> is set appropriately.
98
99PORTABILITY
100<<iconv>>, <<iconv_open>>, and <<iconv_close>> are non-ANSI and are specified
101by the Single Unix specification.
102
103No supporting OS subroutine calls are required.
104*/
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"
117
118/*
119 * iconv interface functions as specified by Single Unix specification.
120 */
121
122iconv_t
123iconv_open (const char *to,
124                   const char *from)
125{
126  return _iconv_open_r (_REENT, to, from);
127}
128
129
130size_t
131iconv (iconv_t cd,
132              char **__restrict inbuf,
133              size_t *__restrict inbytesleft,
134              char **__restrict outbuf,
135              size_t *__restrict outbytesleft)
136{
137    return _iconv_r (_REENT, cd, (const char **) inbuf, inbytesleft,
138                     outbuf, outbytesleft);
139}
140
141
142int
143iconv_close (iconv_t cd)
144{
145    return _iconv_close_r (_REENT, cd);
146}
147
148
149#ifndef _REENT_ONLY
150iconv_t
151_iconv_open_r (struct _reent *rptr,
152                      const char *to,
153                      const char *from)
154{
155  iconv_conversion_t *ic;
156   
157  if (to == NULL || from == NULL || *to == '\0' || *from == '\0')
158    return (iconv_t)-1;
159
160  if ((to = (const char *)_iconv_resolve_encoding_name (rptr, to)) == NULL)
161    return (iconv_t)-1;
162
163  if ((from = (const char *)_iconv_resolve_encoding_name (rptr, from)) == NULL)
164    {
165      _free_r (rptr, (void *)to);
166      return (iconv_t)-1;
167    }
168
169  ic = (iconv_conversion_t *)_malloc_r (rptr, sizeof (iconv_conversion_t));
170  if (ic == NULL)
171    return (iconv_t)-1;
172
173  /* Select which conversion type to use */
174  if (strcmp (from, to) == 0)
175    {
176      /* Use null conversion */
177      ic->handlers = &_iconv_null_conversion_handlers;
178      ic->data = ic->handlers->open (rptr, to, from);
179    }
180  else 
181    {
182      /* Use UCS-based conversion */
183      ic->handlers = &_iconv_ucs_conversion_handlers;
184      ic->data = ic->handlers->open (rptr, to, from);
185    }
186
187  _free_r (rptr, (void *)to);
188  _free_r (rptr, (void *)from);
189
190  if (ic->data == NULL)
191    {
192      _free_r (rptr, (void *)ic);
193      return (iconv_t)-1;
194    }
195
196  return (void *)ic;
197}
198
199
200size_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)
207{
208  iconv_conversion_t *ic = (iconv_conversion_t *)cd;
209
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))
213    {
214      __errno_r (rptr) = EBADF;
215      return (size_t)-1;
216    }
217
218  if (inbuf == NULL || *inbuf == NULL)
219    {
220      mbstate_t state_null = ICONV_ZERO_MB_STATE_T;
221     
222      if (!ic->handlers->is_stateful(ic->data, 1))
223        return (size_t)0;
224     
225      if (outbuf == NULL || *outbuf == NULL)
226        {
227          /* Reset shift state */
228          ic->handlers->set_state (ic->data, &state_null, 1);
229         
230          return (size_t)0;
231        }
232       
233      if (outbytesleft != NULL)
234        {
235          mbstate_t state_save = ICONV_ZERO_MB_STATE_T;
236         
237          /* Save current shift state */         
238          ic->handlers->get_state (ic->data, &state_save, 1);
239         
240          /* Reset shift state */
241          ic->handlers->set_state (ic->data, &state_null, 1);
242
243          /* Get initial shift state sequence and it's length */
244          ic->handlers->get_state (ic->data, &state_null, 1);
245         
246          if (*outbytesleft >= state_null.__count)
247            {
248              memcpy ((void *)(*outbuf), (void *)&state_null, state_null.__count);
249             
250              *outbuf += state_null.__count;
251              *outbytesleft -= state_null.__count;
252
253              return (size_t)0;
254            }
255
256           /* Restore shift state if output buffer is too small */
257           ic->handlers->set_state (ic->data, &state_save, 1);
258        }
259       
260      __errno_r (rptr) = E2BIG;
261      return (size_t)-1;
262    }
263 
264  if (*inbytesleft == 0)
265    {
266      __errno_r (rptr) = EINVAL;
267      return (size_t)-1;
268    }
269   
270  if (*outbytesleft == 0 || *outbuf == NULL)
271    {
272      __errno_r (rptr) = E2BIG;
273      return (size_t)-1;
274    }
275
276  return ic->handlers->convert (rptr,
277                                ic->data,
278                                (const unsigned char**)inbuf,
279                                inbytesleft,
280                                (unsigned char**)outbuf,
281                                outbytesleft,
282                                0);
283}
284
285
286int
287_iconv_close_r (struct _reent *rptr,
288                       iconv_t cd)
289{
290  int res;
291  iconv_conversion_t *ic = (iconv_conversion_t *)cd;
292 
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))
296    {
297      __errno_r (rptr) = EBADF;
298      return -1;
299    }
300
301  res = (int)ic->handlers->close (rptr, ic->data);
302 
303  _free_r (rptr, (void *)cd);
304
305  return res;
306}
307#endif /* !_REENT_ONLY */
Note: See TracBrowser for help on using the repository browser.