Complete the removal of __gconv_translit_find
[platform/upstream/glibc.git] / wcsmbs / mbrtoc16.c
1 /* Copyright (C) 2011-2014 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #include <assert.h>
20 #include <dlfcn.h>
21 #include <errno.h>
22 #include <gconv.h>
23 #include <uchar.h>
24 #include <wcsmbsload.h>
25
26 #include <sysdep.h>
27
28 #ifndef EILSEQ
29 # define EILSEQ EINVAL
30 #endif
31
32
33 /* This is the private state used if PS is NULL.  */
34 static mbstate_t state;
35
36 size_t
37 mbrtoc16 (char16_t *pc16, const char *s, size_t n, mbstate_t *ps)
38 {
39   if (ps == NULL)
40     ps = &state;
41
42   /* The standard text does not say that S being NULL means the state
43      is reset even if the second half of a surrogate still have to be
44      returned.  In fact, the error code description indicates
45      otherwise.  Therefore always first try to return a second
46      half.  */
47   if (ps->__count & 0x80000000)
48     {
49       /* We have to return the second word for a surrogate.  */
50       ps->__count &= 0x7fffffff;
51       *pc16 = ps->__value.__wch;
52       ps->__value.__wch = L'\0';
53       return (size_t) -3;
54     }
55
56   wchar_t wc;
57   struct __gconv_step_data data;
58   int status;
59   size_t result;
60   size_t dummy;
61   const unsigned char *inbuf, *endbuf;
62   unsigned char *outbuf = (unsigned char *) &wc;
63   const struct gconv_fcts *fcts;
64
65   /* Set information for this step.  */
66   data.__invocation_counter = 0;
67   data.__internal_use = 1;
68   data.__flags = __GCONV_IS_LAST;
69   data.__statep = ps;
70
71   /* A first special case is if S is NULL.  This means put PS in the
72      initial state.  */
73   if (s == NULL)
74     {
75       pc16 = NULL;
76       s = "";
77       n = 1;
78     }
79
80   /* Tell where we want the result.  */
81   data.__outbuf = outbuf;
82   data.__outbufend = outbuf + sizeof (wchar_t);
83
84   /* Get the conversion functions.  */
85   fcts = get_gconv_fcts (_NL_CURRENT_DATA (LC_CTYPE));
86
87   /* Do a normal conversion.  */
88   inbuf = (const unsigned char *) s;
89   endbuf = inbuf + n;
90   if (__glibc_unlikely (endbuf < inbuf))
91     {
92       endbuf = (const unsigned char *) ~(uintptr_t) 0;
93       if (endbuf == inbuf)
94         goto ilseq;
95     }
96   __gconv_fct fct = fcts->towc->__fct;
97 #ifdef PTR_DEMANGLE
98   if (fcts->towc->__shlib_handle != NULL)
99     PTR_DEMANGLE (fct);
100 #endif
101
102   status = DL_CALL_FCT (fct, (fcts->towc, &data, &inbuf, endbuf,
103                               NULL, &dummy, 0, 1));
104
105   /* There must not be any problems with the conversion but illegal input
106      characters.  The output buffer must be large enough, otherwise the
107      definition of MB_CUR_MAX is not correct.  All the other possible
108      errors also must not happen.  */
109   assert (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT
110           || status == __GCONV_ILLEGAL_INPUT
111           || status == __GCONV_INCOMPLETE_INPUT
112           || status == __GCONV_FULL_OUTPUT);
113
114   if (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT
115       || status == __GCONV_FULL_OUTPUT)
116     {
117       result = inbuf - (const unsigned char *) s;
118
119       if (wc < 0x10000)
120         {
121           if (pc16 != NULL)
122             *pc16 = wc;
123
124           if (data.__outbuf != outbuf && wc == L'\0')
125             {
126               /* The converted character is the NUL character.  */
127               assert (__mbsinit (data.__statep));
128               result = 0;
129             }
130         }
131       else
132         {
133           /* This is a surrogate.  */
134           if (pc16 != NULL)
135             *pc16 = 0xd7c0 + (wc >> 10);
136
137           ps->__count |= 0x80000000;
138           ps->__value.__wch = 0xdc00 + (wc & 0x3ff);
139         }
140     }
141   else if (status == __GCONV_INCOMPLETE_INPUT)
142     result = (size_t) -2;
143   else
144     {
145     ilseq:
146       result = (size_t) -1;
147       __set_errno (EILSEQ);
148     }
149
150   return result;
151 }