wcsrtombs.c revision 129154
1185029Spjd/*-
2185029Spjd * Copyright (c) 2002-2004 Tim J. Robbins.
3185029Spjd * All rights reserved.
4185029Spjd *
5185029Spjd * Redistribution and use in source and binary forms, with or without
6185029Spjd * modification, are permitted provided that the following conditions
7185029Spjd * are met:
8185029Spjd * 1. Redistributions of source code must retain the above copyright
9185029Spjd *    notice, this list of conditions and the following disclaimer.
10185029Spjd * 2. Redistributions in binary form must reproduce the above copyright
11185029Spjd *    notice, this list of conditions and the following disclaimer in the
12185029Spjd *    documentation and/or other materials provided with the distribution.
13185029Spjd *
14185029Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15185029Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16185029Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17185029Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18185029Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19185029Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20185029Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21185029Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22185096Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23185096Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24185096Sdfr * SUCH DAMAGE.
25185029Spjd */
26185029Spjd
27185029Spjd#include <sys/cdefs.h>
28185029Spjd__FBSDID("$FreeBSD: head/lib/libc/locale/wcsrtombs.c 129154 2004-05-12 14:26:54Z tjr $");
29185029Spjd
30185029Spjd#include <limits.h>
31185029Spjd#include <stdlib.h>
32185029Spjd#include <string.h>
33185029Spjd#include <wchar.h>
34185029Spjd#include "mblocal.h"
35185029Spjd
36185029Spjdsize_t
37185029Spjdwcsrtombs(char * __restrict dst, const wchar_t ** __restrict src, size_t len,
38185096Sdfr    mbstate_t * __restrict ps)
39185029Spjd{
40185096Sdfr	static mbstate_t mbs;
41185029Spjd	mbstate_t mbsbak;
42185029Spjd	char buf[MB_LEN_MAX];
43185029Spjd	const wchar_t *s;
44185029Spjd	size_t nbytes;
45185029Spjd	int nb;
46185029Spjd
47185029Spjd	s = *src;
48185029Spjd	nbytes = 0;
49185029Spjd
50185029Spjd	if (ps == NULL)
51185029Spjd		ps = &mbs;
52185029Spjd	if (dst == NULL) {
53185029Spjd		for (;;) {
54185029Spjd			if ((nb = (int)__wcrtomb(buf, *s, ps)) < 0)
55185029Spjd				/* Invalid character - wcrtomb() sets errno. */
56185029Spjd				return ((size_t)-1);
57185029Spjd			else if (*s == L'\0')
58185029Spjd				return (nbytes + nb - 1);
59185029Spjd			s++;
60185029Spjd			nbytes += nb;
61185029Spjd		}
62185029Spjd		/*NOTREACHED*/
63185029Spjd	}
64185029Spjd
65185029Spjd	while (len > 0) {
66185029Spjd		if (len > (size_t)MB_CUR_MAX) {
67185029Spjd			/* Enough space to translate in-place. */
68185029Spjd			if ((nb = (int)__wcrtomb(dst, *s, ps)) < 0) {
69185029Spjd				*src = s;
70185029Spjd				return ((size_t)-1);
71185029Spjd			}
72185029Spjd		} else {
73185029Spjd			/*
74185029Spjd			 * May not be enough space; use temp. buffer.
75185029Spjd			 *
76185029Spjd			 * We need to save a copy of the conversion state
77185029Spjd			 * here so we can restore it if the multibyte
78185029Spjd			 * character is too long for the buffer.
79185029Spjd			 */
80185029Spjd			mbsbak = *ps;
81185029Spjd			if ((nb = (int)__wcrtomb(buf, *s, ps)) < 0) {
82185029Spjd				*src = s;
83185029Spjd				return ((size_t)-1);
84185029Spjd			}
85185029Spjd			if (nb > (int)len) {
86185029Spjd				/* MB sequence for character won't fit. */
87185029Spjd				*ps = mbsbak;
88185029Spjd				break;
89185029Spjd			}
90185029Spjd			memcpy(dst, buf, nb);
91185029Spjd		}
92185029Spjd		if (*s == L'\0') {
93185029Spjd			*src = NULL;
94185029Spjd			return (nbytes + nb - 1);
95185029Spjd		}
96185029Spjd		s++;
97185029Spjd		dst += nb;
98185029Spjd		len -= nb;
99185029Spjd		nbytes += nb;
100185029Spjd	}
101185029Spjd	*src = s;
102185029Spjd	return (nbytes);
103185029Spjd}
104185029Spjd