]> git.ipfire.org Git - thirdparty/glibc.git/blob - wcsmbs/c16rtomb.c
More char16_t and char32_t support
[thirdparty/glibc.git] / wcsmbs / c16rtomb.c
1 /* Copyright (C) 2011, 2012 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, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
19
20 #include <assert.h>
21 #include <dlfcn.h>
22 #include <errno.h>
23 #include <gconv.h>
24 #include <stdlib.h>
25 #include <uchar.h>
26 #include <wcsmbsload.h>
27
28 #include <sysdep.h>
29
30 #ifndef EILSEQ
31 # define EILSEQ EINVAL
32 #endif
33
34 #if __STDC__ >= 201000L
35 # define u(c) U##c
36 #else
37 # define u(c) L##c
38 #endif
39
40
41 /* This is the private state used if PS is NULL. */
42 static mbstate_t state;
43
44 size_t
45 c16rtomb (char *s, char16_t c16, mbstate_t *ps)
46 {
47 #if 1
48 // XXX The ISO C 11 spec I have does not say anything about handling
49 // XXX surrogates in this interface.
50 return wcrtomb (s, c16, ps ?: &state);
51 #else
52 char buf[MB_LEN_MAX];
53 struct __gconv_step_data data;
54 int status;
55 size_t result;
56 size_t dummy;
57 const struct gconv_fcts *fcts;
58
59 /* Set information for this step. */
60 data.__invocation_counter = 0;
61 data.__internal_use = 1;
62 data.__flags = __GCONV_IS_LAST;
63 data.__statep = ps ?: &state;
64 data.__trans = NULL;
65
66 /* A first special case is if S is NULL. This means put PS in the
67 initial state. */
68 if (s == NULL)
69 {
70 s = buf;
71 c16 = u('\0');
72 }
73
74 /* Tell where we want to have the result. */
75 data.__outbuf = (unsigned char *) s;
76 data.__outbufend = (unsigned char *) s + MB_CUR_MAX;
77
78 /* Get the conversion functions. */
79 fcts = get_gconv_fcts (_NL_CURRENT_DATA (LC_CTYPE));
80 __gconv_fct fct = fcts->fromc16->__fct;
81 #ifdef PTR_DEMANGLE
82 if (fcts->tomb->__shlib_handle != NULL)
83 PTR_DEMANGLE (fct);
84 #endif
85
86 /* If C16 is the NUL character we write into the output buffer
87 the byte sequence necessary for PS to get into the initial
88 state, followed by a NUL byte. */
89 if (c16 == L'\0')
90 {
91 status = DL_CALL_FCT (fct, (fcts->fromc16, &data, NULL, NULL,
92 NULL, &dummy, 1, 1));
93
94 if (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT)
95 *data.__outbuf++ = '\0';
96 }
97 else
98 {
99 /* Do a normal conversion. */
100 const unsigned char *inbuf = (const unsigned char *) &c16;
101
102 status = DL_CALL_FCT (fct,
103 (fcts->fromc16, &data, &inbuf,
104 inbuf + sizeof (char16_t), NULL, &dummy,
105 0, 1));
106 }
107
108 /* There must not be any problems with the conversion but illegal input
109 characters. The output buffer must be large enough, otherwise the
110 definition of MB_CUR_MAX is not correct. All the other possible
111 errors also must not happen. */
112 assert (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT
113 || status == __GCONV_ILLEGAL_INPUT
114 || status == __GCONV_INCOMPLETE_INPUT
115 || status == __GCONV_FULL_OUTPUT);
116
117 if (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT
118 || status == __GCONV_FULL_OUTPUT)
119 result = data.__outbuf - (unsigned char *) s;
120 else
121 {
122 result = (size_t) -1;
123 __set_errno (EILSEQ);
124 }
125
126 return result;
127 #endif
128 }