xref: /Universal-ctags/gnulib/mbsrtowcs-impl.h (revision a939078a69878851c19820eb92e6cb95ba429546)
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