1ea2741973acd73619da693548388a05527b92d57David Chisnall/*-
2ea2741973acd73619da693548388a05527b92d57David Chisnall * Copyright (c) 2002-2004 Tim J. Robbins.
3ea2741973acd73619da693548388a05527b92d57David Chisnall *
4ea2741973acd73619da693548388a05527b92d57David Chisnall * Redistribution and use in source and binary forms, with or without
5ea2741973acd73619da693548388a05527b92d57David Chisnall * modification, are permitted provided that the following conditions
6ea2741973acd73619da693548388a05527b92d57David Chisnall * are met:
7ea2741973acd73619da693548388a05527b92d57David Chisnall * 1. Redistributions of source code must retain the above copyright
8ea2741973acd73619da693548388a05527b92d57David Chisnall *    notice, this list of conditions and the following disclaimer.
9ea2741973acd73619da693548388a05527b92d57David Chisnall * 2. Redistributions in binary form must reproduce the above copyright
10ea2741973acd73619da693548388a05527b92d57David Chisnall *    notice, this list of conditions and the following disclaimer in the
11ea2741973acd73619da693548388a05527b92d57David Chisnall *    documentation and/or other materials provided with the distribution.
12ea2741973acd73619da693548388a05527b92d57David Chisnall *
13ea2741973acd73619da693548388a05527b92d57David Chisnall * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14ea2741973acd73619da693548388a05527b92d57David Chisnall * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15ea2741973acd73619da693548388a05527b92d57David Chisnall * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16ea2741973acd73619da693548388a05527b92d57David Chisnall * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17ea2741973acd73619da693548388a05527b92d57David Chisnall * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18ea2741973acd73619da693548388a05527b92d57David Chisnall * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19ea2741973acd73619da693548388a05527b92d57David Chisnall * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20ea2741973acd73619da693548388a05527b92d57David Chisnall * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21ea2741973acd73619da693548388a05527b92d57David Chisnall * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22ea2741973acd73619da693548388a05527b92d57David Chisnall * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23ea2741973acd73619da693548388a05527b92d57David Chisnall * SUCH DAMAGE.
24ea2741973acd73619da693548388a05527b92d57David Chisnall */
25ea2741973acd73619da693548388a05527b92d57David Chisnall
26ea2741973acd73619da693548388a05527b92d57David Chisnall
27ea2741973acd73619da693548388a05527b92d57David Chisnallsize_t
28ea2741973acd73619da693548388a05527b92d57David Chisnallwcsnrtombs_l(char * __restrict dst, const wchar_t ** __restrict src,
29ea2741973acd73619da693548388a05527b92d57David Chisnall    size_t nwc, size_t len, mbstate_t * __restrict ps, locale_t loc)
30ea2741973acd73619da693548388a05527b92d57David Chisnall{
31ea2741973acd73619da693548388a05527b92d57David Chisnall  FIX_LOCALE(loc);
32ea2741973acd73619da693548388a05527b92d57David Chisnall  mbstate_t mbsbak;
33ea2741973acd73619da693548388a05527b92d57David Chisnall  char buf[MB_CUR_MAX_L(loc)];
34ea2741973acd73619da693548388a05527b92d57David Chisnall  const wchar_t *s;
35ea2741973acd73619da693548388a05527b92d57David Chisnall  size_t nbytes;
36ea2741973acd73619da693548388a05527b92d57David Chisnall  size_t nb;
37ea2741973acd73619da693548388a05527b92d57David Chisnall
38ea2741973acd73619da693548388a05527b92d57David Chisnall  s = *src;
39ea2741973acd73619da693548388a05527b92d57David Chisnall  nbytes = 0;
40ea2741973acd73619da693548388a05527b92d57David Chisnall
41ea2741973acd73619da693548388a05527b92d57David Chisnall  if (dst == NULL) {
42ea2741973acd73619da693548388a05527b92d57David Chisnall    while (nwc-- > 0) {
43ea2741973acd73619da693548388a05527b92d57David Chisnall      if ((nb = wcrtomb_l(buf, *s, ps, loc)) == (size_t)-1)
44ea2741973acd73619da693548388a05527b92d57David Chisnall        /* Invalid character - wcrtomb() sets errno. */
45ea2741973acd73619da693548388a05527b92d57David Chisnall        return ((size_t)-1);
46ea2741973acd73619da693548388a05527b92d57David Chisnall      else if (*s == L'\0')
47ea2741973acd73619da693548388a05527b92d57David Chisnall        return (nbytes + nb - 1);
48ea2741973acd73619da693548388a05527b92d57David Chisnall      s++;
49ea2741973acd73619da693548388a05527b92d57David Chisnall      nbytes += nb;
50ea2741973acd73619da693548388a05527b92d57David Chisnall    }
51ea2741973acd73619da693548388a05527b92d57David Chisnall    return (nbytes);
52ea2741973acd73619da693548388a05527b92d57David Chisnall  }
53ea2741973acd73619da693548388a05527b92d57David Chisnall
54ea2741973acd73619da693548388a05527b92d57David Chisnall  while (len > 0 && nwc-- > 0) {
55ea2741973acd73619da693548388a05527b92d57David Chisnall    if (len > (size_t)MB_CUR_MAX_L(loc)) {
56ea2741973acd73619da693548388a05527b92d57David Chisnall      /* Enough space to translate in-place. */
57ea2741973acd73619da693548388a05527b92d57David Chisnall      if ((nb = wcrtomb_l(dst, *s, ps, loc)) == (size_t)-1) {
58ea2741973acd73619da693548388a05527b92d57David Chisnall        *src = s;
59ea2741973acd73619da693548388a05527b92d57David Chisnall        return ((size_t)-1);
60ea2741973acd73619da693548388a05527b92d57David Chisnall      }
61ea2741973acd73619da693548388a05527b92d57David Chisnall    } else {
62ea2741973acd73619da693548388a05527b92d57David Chisnall      /*
63ea2741973acd73619da693548388a05527b92d57David Chisnall       * May not be enough space; use temp. buffer.
64ea2741973acd73619da693548388a05527b92d57David Chisnall       *
65ea2741973acd73619da693548388a05527b92d57David Chisnall       * We need to save a copy of the conversion state
66ea2741973acd73619da693548388a05527b92d57David Chisnall       * here so we can restore it if the multibyte
67ea2741973acd73619da693548388a05527b92d57David Chisnall       * character is too long for the buffer.
68ea2741973acd73619da693548388a05527b92d57David Chisnall       */
69ea2741973acd73619da693548388a05527b92d57David Chisnall      mbsbak = *ps;
70ea2741973acd73619da693548388a05527b92d57David Chisnall      if ((nb = wcrtomb_l(buf, *s, ps, loc)) == (size_t)-1) {
71ea2741973acd73619da693548388a05527b92d57David Chisnall        *src = s;
72ea2741973acd73619da693548388a05527b92d57David Chisnall        return ((size_t)-1);
73ea2741973acd73619da693548388a05527b92d57David Chisnall      }
74ea2741973acd73619da693548388a05527b92d57David Chisnall      if (nb > (int)len) {
75ea2741973acd73619da693548388a05527b92d57David Chisnall        /* MB sequence for character won't fit. */
76ea2741973acd73619da693548388a05527b92d57David Chisnall        *ps = mbsbak;
77ea2741973acd73619da693548388a05527b92d57David Chisnall        break;
78ea2741973acd73619da693548388a05527b92d57David Chisnall      }
79ea2741973acd73619da693548388a05527b92d57David Chisnall      memcpy(dst, buf, nb);
80ea2741973acd73619da693548388a05527b92d57David Chisnall    }
81ea2741973acd73619da693548388a05527b92d57David Chisnall    if (*s == L'\0') {
82ea2741973acd73619da693548388a05527b92d57David Chisnall      *src = NULL;
83ea2741973acd73619da693548388a05527b92d57David Chisnall      return (nbytes + nb - 1);
84ea2741973acd73619da693548388a05527b92d57David Chisnall    }
85ea2741973acd73619da693548388a05527b92d57David Chisnall    s++;
86ea2741973acd73619da693548388a05527b92d57David Chisnall    dst += nb;
87ea2741973acd73619da693548388a05527b92d57David Chisnall    len -= nb;
88ea2741973acd73619da693548388a05527b92d57David Chisnall    nbytes += nb;
89ea2741973acd73619da693548388a05527b92d57David Chisnall  }
90ea2741973acd73619da693548388a05527b92d57David Chisnall  *src = s;
91ea2741973acd73619da693548388a05527b92d57David Chisnall  return (nbytes);
92ea2741973acd73619da693548388a05527b92d57David Chisnall}
93ea2741973acd73619da693548388a05527b92d57David Chisnall
94