wcsnrtombs.c revision 132497
1203288Srnoland/*-
2203288Srnoland * Copyright (c) 2002-2004 Tim J. Robbins.
3203288Srnoland * All rights reserved.
4203288Srnoland *
5203288Srnoland * Redistribution and use in source and binary forms, with or without
6203288Srnoland * modification, are permitted provided that the following conditions
7203288Srnoland * are met:
8203288Srnoland * 1. Redistributions of source code must retain the above copyright
9203288Srnoland *    notice, this list of conditions and the following disclaimer.
10203288Srnoland * 2. Redistributions in binary form must reproduce the above copyright
11203288Srnoland *    notice, this list of conditions and the following disclaimer in the
12203288Srnoland *    documentation and/or other materials provided with the distribution.
13203288Srnoland *
14203288Srnoland * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15203288Srnoland * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16203288Srnoland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17203288Srnoland * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18203288Srnoland * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19203288Srnoland * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20203288Srnoland * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21203288Srnoland * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22203288Srnoland * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23203288Srnoland * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24203288Srnoland * SUCH DAMAGE.
25203288Srnoland */
26203288Srnoland
27203288Srnoland#include <sys/cdefs.h>
28203288Srnoland__FBSDID("$FreeBSD: head/lib/libc/locale/wcsnrtombs.c 132497 2004-07-21 10:54:57Z tjr $");
29203288Srnoland
30203288Srnoland#include <limits.h>
31203288Srnoland#include <stdlib.h>
32203288Srnoland#include <string.h>
33203288Srnoland#include <wchar.h>
34203288Srnoland#include "mblocal.h"
35203288Srnoland
36203288Srnolandsize_t
37203288Srnolandwcsnrtombs(char * __restrict dst, const wchar_t ** __restrict src, size_t nwc,
38203288Srnoland    size_t len, mbstate_t * __restrict ps)
39203288Srnoland{
40203288Srnoland	static mbstate_t mbs;
41203288Srnoland
42203288Srnoland	if (ps == NULL)
43203288Srnoland		ps = &mbs;
44203288Srnoland	return (__wcsnrtombs(dst, src, nwc, len, ps));
45203288Srnoland}
46203288Srnoland
47203288Srnolandsize_t
48203288Srnoland__wcsnrtombs_std(char * __restrict dst, const wchar_t ** __restrict src,
49203288Srnoland    size_t nwc, size_t len, mbstate_t * __restrict ps)
50203288Srnoland{
51203288Srnoland	mbstate_t mbsbak;
52203288Srnoland	char buf[MB_LEN_MAX];
53203288Srnoland	const wchar_t *s;
54203288Srnoland	size_t nbytes;
55203288Srnoland	size_t nb;
56203288Srnoland
57203288Srnoland	s = *src;
58203288Srnoland	nbytes = 0;
59203288Srnoland
60203288Srnoland	if (dst == NULL) {
61203288Srnoland		while (nwc-- > 0) {
62203288Srnoland			if ((nb = __wcrtomb(buf, *s, ps)) == (size_t)-1)
63203288Srnoland				/* Invalid character - wcrtomb() sets errno. */
64203288Srnoland				return ((size_t)-1);
65203288Srnoland			else if (*s == L'\0')
66203288Srnoland				break;
67203288Srnoland			s++;
68203288Srnoland			nbytes += nb;
69203288Srnoland		}
70203288Srnoland		return (nbytes + nb - 1);
71203288Srnoland	}
72203288Srnoland
73203288Srnoland	while (len > 0 && nwc-- > 0) {
74203288Srnoland		if (len > (size_t)MB_CUR_MAX) {
75203288Srnoland			/* Enough space to translate in-place. */
76203288Srnoland			if ((nb = (int)__wcrtomb(dst, *s, ps)) < 0) {
77203288Srnoland				*src = s;
78203288Srnoland				return ((size_t)-1);
79203288Srnoland			}
80203288Srnoland		} else {
81203288Srnoland			/*
82203288Srnoland			 * May not be enough space; use temp. buffer.
83203288Srnoland			 *
84203288Srnoland			 * We need to save a copy of the conversion state
85203288Srnoland			 * here so we can restore it if the multibyte
86203288Srnoland			 * character is too long for the buffer.
87203288Srnoland			 */
88203288Srnoland			mbsbak = *ps;
89203288Srnoland			if ((nb = (int)__wcrtomb(buf, *s, ps)) < 0) {
90203288Srnoland				*src = s;
91203288Srnoland				return ((size_t)-1);
92203288Srnoland			}
93203288Srnoland			if (nb > (int)len) {
94203288Srnoland				/* MB sequence for character won't fit. */
95203288Srnoland				*ps = mbsbak;
96203288Srnoland				break;
97203288Srnoland			}
98203288Srnoland			memcpy(dst, buf, nb);
99203288Srnoland		}
100203288Srnoland		if (*s == L'\0') {
101203288Srnoland			*src = NULL;
102203288Srnoland			return (nbytes + nb - 1);
103203288Srnoland		}
104203288Srnoland		s++;
105203288Srnoland		dst += nb;
106203288Srnoland		len -= nb;
107203288Srnoland		nbytes += nb;
108203288Srnoland	}
109203288Srnoland	*src = s;
110203288Srnoland	return (nbytes);
111203288Srnoland}
112203288Srnoland