Imported Upstream version 0.18.1.1
[platform/upstream/gettext.git] / gettext-tools / gnulib-lib / mbsrtowcs.c
1 /* Convert string to wide string.
2    Copyright (C) 2008, 2009, 2010 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 #include <config.h>
19
20 /* Specification.  */
21 #include <wchar.h>
22
23 #include <errno.h>
24 #include <limits.h>
25 #include <stdlib.h>
26
27 #include "strnlen1.h"
28
29
30 extern mbstate_t _gl_mbsrtowcs_state;
31
32 size_t
33 mbsrtowcs (wchar_t *dest, const char **srcp, size_t len, mbstate_t *ps)
34 {
35   if (ps == NULL)
36     ps = &_gl_mbsrtowcs_state;
37   {
38     const char *src = *srcp;
39
40     if (dest != NULL)
41       {
42         wchar_t *destptr = dest;
43
44         for (; len > 0; destptr++, len--)
45           {
46             size_t src_avail;
47             size_t ret;
48
49             /* An optimized variant of
50                src_avail = strnlen1 (src, MB_LEN_MAX);  */
51             if (src[0] == '\0')
52               src_avail = 1;
53             else if (src[1] == '\0')
54               src_avail = 2;
55             else if (src[2] == '\0')
56               src_avail = 3;
57             else if (MB_LEN_MAX <= 4 || src[3] == '\0')
58               src_avail = 4;
59             else
60               src_avail = 4 + strnlen1 (src + 4, MB_LEN_MAX - 4);
61
62             /* Parse the next multibyte character.  */
63             ret = mbrtowc (destptr, src, src_avail, ps);
64
65             if (ret == (size_t)(-2))
66               /* Encountered a multibyte character that extends past a '\0' byte
67                  or that is longer than MB_LEN_MAX bytes.  Cannot happen.  */
68               abort ();
69
70             if (ret == (size_t)(-1))
71               goto bad_input;
72             if (ret == 0)
73               {
74                 src = NULL;
75                 /* Here mbsinit (ps).  */
76                 break;
77               }
78             src += ret;
79           }
80
81         *srcp = src;
82         return destptr - dest;
83       }
84     else
85       {
86         /* Ignore dest and len, don't store *srcp at the end, and
87            don't clobber *ps.  */
88         mbstate_t state = *ps;
89         size_t totalcount = 0;
90
91         for (;; totalcount++)
92           {
93             size_t src_avail;
94             size_t ret;
95
96             /* An optimized variant of
97                src_avail = strnlen1 (src, MB_LEN_MAX);  */
98             if (src[0] == '\0')
99               src_avail = 1;
100             else if (src[1] == '\0')
101               src_avail = 2;
102             else if (src[2] == '\0')
103               src_avail = 3;
104             else if (MB_LEN_MAX <= 4 || src[3] == '\0')
105               src_avail = 4;
106             else
107               src_avail = 4 + strnlen1 (src + 4, MB_LEN_MAX - 4);
108
109             /* Parse the next multibyte character.  */
110             ret = mbrtowc (NULL, src, src_avail, &state);
111
112             if (ret == (size_t)(-2))
113               /* Encountered a multibyte character that extends past a '\0' byte
114                  or that is longer than MB_LEN_MAX bytes.  Cannot happen.  */
115               abort ();
116
117             if (ret == (size_t)(-1))
118               goto bad_input2;
119             if (ret == 0)
120               {
121                 /* Here mbsinit (&state).  */
122                 break;
123               }
124             src += ret;
125           }
126
127         return totalcount;
128       }
129
130    bad_input:
131     *srcp = src;
132    bad_input2:
133     errno = EILSEQ;
134     return (size_t)(-1);
135   }
136 }