Merge commit 'a39d4083cab589d7cd6a13e8a4b8db8875261d75'
[gnulib.git] / lib / wcsnrtombs-impl.h
1 /* Convert wide string to 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 wcsnrtombs (char *dest, const wchar_t **srcp, size_t srclen, size_t len, mbstate_t *ps)
20 {
21   if (ps == NULL)
22     ps = &_gl_wcsrtombs_state;
23   {
24     const wchar_t *src = *srcp;
25     size_t cur_max = MB_CUR_MAX;
26     char buf[64];
27
28     if (!(cur_max <= sizeof (buf)))
29       abort ();
30
31     if (dest != NULL)
32       {
33         char *destptr = dest;
34
35         for (; srclen > 0 && len > 0; src++, srclen--)
36           {
37             wchar_t wc = *src;
38             size_t ret = wcrtomb (len >= cur_max ? destptr : buf, wc, ps);
39
40             if (ret == (size_t)(-1))
41               goto bad_input;
42             if (!(ret <= cur_max))
43               abort ();
44             if (len < ret)
45               break;
46             if (len < cur_max)
47               memcpy (destptr, buf, ret);
48             if (wc == 0)
49               {
50                 src = NULL;
51                 /* Here mbsinit (ps).  */
52                 break;
53               }
54             destptr += ret;
55             len -= ret;
56           }
57         *srcp = src;
58         return destptr - dest;
59       }
60     else
61       {
62         /* Ignore dest and len, don't store *srcp at the end, and
63            don't clobber *ps.  */
64         mbstate_t state = *ps;
65         size_t totalcount = 0;
66
67         for (; srclen > 0; src++, srclen--)
68           {
69             wchar_t wc = *src;
70             size_t ret = wcrtomb (buf, wc, &state);
71
72             if (ret == (size_t)(-1))
73               goto bad_input2;
74             if (wc == 0)
75               {
76                 /* Here mbsinit (&state).  */
77                 break;
78               }
79             totalcount += ret;
80           }
81         return totalcount;
82       }
83
84    bad_input:
85     *srcp = src;
86    bad_input2:
87     errno = EILSEQ;
88     return (size_t)(-1);
89   }
90 }