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