1*a939078aSHiroo HAYASHI /* Convert string to wide string.
2*a939078aSHiroo HAYASHI Copyright (C) 2008-2021 Free Software Foundation, Inc.
3*a939078aSHiroo HAYASHI Written by Bruno Haible <bruno@clisp.org>, 2008.
4*a939078aSHiroo HAYASHI
5*a939078aSHiroo HAYASHI This file is free software: you can redistribute it and/or modify
6*a939078aSHiroo HAYASHI it under the terms of the GNU Lesser General Public License as
7*a939078aSHiroo HAYASHI published by the Free Software Foundation; either version 2.1 of the
8*a939078aSHiroo HAYASHI License, or (at your option) any later version.
9*a939078aSHiroo HAYASHI
10*a939078aSHiroo HAYASHI This file is distributed in the hope that it will be useful,
11*a939078aSHiroo HAYASHI but WITHOUT ANY WARRANTY; without even the implied warranty of
12*a939078aSHiroo HAYASHI MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*a939078aSHiroo HAYASHI GNU Lesser General Public License for more details.
14*a939078aSHiroo HAYASHI
15*a939078aSHiroo HAYASHI You should have received a copy of the GNU Lesser General Public License
16*a939078aSHiroo HAYASHI along with this program. If not, see <https://www.gnu.org/licenses/>. */
17*a939078aSHiroo HAYASHI
18*a939078aSHiroo HAYASHI size_t
FUNC(DCHAR_T * dest,const char ** srcp,size_t len,mbstate_t * ps)19*a939078aSHiroo HAYASHI FUNC (DCHAR_T *dest, const char **srcp, size_t len, mbstate_t *ps)
20*a939078aSHiroo HAYASHI {
21*a939078aSHiroo HAYASHI if (ps == NULL)
22*a939078aSHiroo HAYASHI ps = &INTERNAL_STATE;
23*a939078aSHiroo HAYASHI {
24*a939078aSHiroo HAYASHI const char *src = *srcp;
25*a939078aSHiroo HAYASHI
26*a939078aSHiroo HAYASHI if (dest != NULL)
27*a939078aSHiroo HAYASHI {
28*a939078aSHiroo HAYASHI DCHAR_T *destptr = dest;
29*a939078aSHiroo HAYASHI
30*a939078aSHiroo HAYASHI for (; len > 0; destptr++, len--)
31*a939078aSHiroo HAYASHI {
32*a939078aSHiroo HAYASHI size_t src_avail;
33*a939078aSHiroo HAYASHI size_t ret;
34*a939078aSHiroo HAYASHI
35*a939078aSHiroo HAYASHI /* An optimized variant of
36*a939078aSHiroo HAYASHI src_avail = strnlen1 (src, MB_LEN_MAX); */
37*a939078aSHiroo HAYASHI if (src[0] == '\0')
38*a939078aSHiroo HAYASHI src_avail = 1;
39*a939078aSHiroo HAYASHI else if (src[1] == '\0')
40*a939078aSHiroo HAYASHI src_avail = 2;
41*a939078aSHiroo HAYASHI else if (src[2] == '\0')
42*a939078aSHiroo HAYASHI src_avail = 3;
43*a939078aSHiroo HAYASHI else if (MB_LEN_MAX <= 4 || src[3] == '\0')
44*a939078aSHiroo HAYASHI src_avail = 4;
45*a939078aSHiroo HAYASHI else
46*a939078aSHiroo HAYASHI src_avail = 4 + strnlen1 (src + 4, MB_LEN_MAX - 4);
47*a939078aSHiroo HAYASHI
48*a939078aSHiroo HAYASHI /* Parse the next multibyte character. */
49*a939078aSHiroo HAYASHI ret = MBRTOWC (destptr, src, src_avail, ps);
50*a939078aSHiroo HAYASHI
51*a939078aSHiroo HAYASHI if (ret == (size_t)(-2))
52*a939078aSHiroo HAYASHI /* Encountered a multibyte character that extends past a '\0' byte
53*a939078aSHiroo HAYASHI or that is longer than MB_LEN_MAX bytes. Cannot happen. */
54*a939078aSHiroo HAYASHI abort ();
55*a939078aSHiroo HAYASHI
56*a939078aSHiroo HAYASHI if (ret == (size_t)(-1))
57*a939078aSHiroo HAYASHI goto bad_input;
58*a939078aSHiroo HAYASHI if (ret == 0)
59*a939078aSHiroo HAYASHI {
60*a939078aSHiroo HAYASHI src = NULL;
61*a939078aSHiroo HAYASHI /* Here mbsinit (ps). */
62*a939078aSHiroo HAYASHI break;
63*a939078aSHiroo HAYASHI }
64*a939078aSHiroo HAYASHI src += ret;
65*a939078aSHiroo HAYASHI }
66*a939078aSHiroo HAYASHI
67*a939078aSHiroo HAYASHI *srcp = src;
68*a939078aSHiroo HAYASHI return destptr - dest;
69*a939078aSHiroo HAYASHI }
70*a939078aSHiroo HAYASHI else
71*a939078aSHiroo HAYASHI {
72*a939078aSHiroo HAYASHI /* Ignore dest and len, don't store *srcp at the end, and
73*a939078aSHiroo HAYASHI don't clobber *ps. */
74*a939078aSHiroo HAYASHI mbstate_t state = *ps;
75*a939078aSHiroo HAYASHI size_t totalcount = 0;
76*a939078aSHiroo HAYASHI
77*a939078aSHiroo HAYASHI for (;; totalcount++)
78*a939078aSHiroo HAYASHI {
79*a939078aSHiroo HAYASHI size_t src_avail;
80*a939078aSHiroo HAYASHI size_t ret;
81*a939078aSHiroo HAYASHI
82*a939078aSHiroo HAYASHI /* An optimized variant of
83*a939078aSHiroo HAYASHI src_avail = strnlen1 (src, MB_LEN_MAX); */
84*a939078aSHiroo HAYASHI if (src[0] == '\0')
85*a939078aSHiroo HAYASHI src_avail = 1;
86*a939078aSHiroo HAYASHI else if (src[1] == '\0')
87*a939078aSHiroo HAYASHI src_avail = 2;
88*a939078aSHiroo HAYASHI else if (src[2] == '\0')
89*a939078aSHiroo HAYASHI src_avail = 3;
90*a939078aSHiroo HAYASHI else if (MB_LEN_MAX <= 4 || src[3] == '\0')
91*a939078aSHiroo HAYASHI src_avail = 4;
92*a939078aSHiroo HAYASHI else
93*a939078aSHiroo HAYASHI src_avail = 4 + strnlen1 (src + 4, MB_LEN_MAX - 4);
94*a939078aSHiroo HAYASHI
95*a939078aSHiroo HAYASHI /* Parse the next multibyte character. */
96*a939078aSHiroo HAYASHI ret = MBRTOWC (NULL, src, src_avail, &state);
97*a939078aSHiroo HAYASHI
98*a939078aSHiroo HAYASHI if (ret == (size_t)(-2))
99*a939078aSHiroo HAYASHI /* Encountered a multibyte character that extends past a '\0' byte
100*a939078aSHiroo HAYASHI or that is longer than MB_LEN_MAX bytes. Cannot happen. */
101*a939078aSHiroo HAYASHI abort ();
102*a939078aSHiroo HAYASHI
103*a939078aSHiroo HAYASHI if (ret == (size_t)(-1))
104*a939078aSHiroo HAYASHI goto bad_input2;
105*a939078aSHiroo HAYASHI if (ret == 0)
106*a939078aSHiroo HAYASHI {
107*a939078aSHiroo HAYASHI /* Here mbsinit (&state). */
108*a939078aSHiroo HAYASHI break;
109*a939078aSHiroo HAYASHI }
110*a939078aSHiroo HAYASHI src += ret;
111*a939078aSHiroo HAYASHI }
112*a939078aSHiroo HAYASHI
113*a939078aSHiroo HAYASHI return totalcount;
114*a939078aSHiroo HAYASHI }
115*a939078aSHiroo HAYASHI
116*a939078aSHiroo HAYASHI bad_input:
117*a939078aSHiroo HAYASHI *srcp = src;
118*a939078aSHiroo HAYASHI bad_input2:
119*a939078aSHiroo HAYASHI errno = EILSEQ;
120*a939078aSHiroo HAYASHI return (size_t)(-1);
121*a939078aSHiroo HAYASHI }
122*a939078aSHiroo HAYASHI }
123