1103739Stjr/*	$OpenBSD: vasprintf.c,v 1.4 1998/06/21 22:13:47 millert Exp $	*/
2103739Stjr
3103739Stjr/*
4103739Stjr * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
5103739Stjr * All rights reserved.
6103739Stjr *
7227753Stheraven * Copyright (c) 2011 The FreeBSD Foundation
8227753Stheraven * All rights reserved.
9227753Stheraven * Portions of this software were developed by David Chisnall
10227753Stheraven * under sponsorship from the FreeBSD Foundation.
11227753Stheraven *
12103739Stjr * Redistribution and use in source and binary forms, with or without
13103739Stjr * modification, are permitted provided that the following conditions
14103739Stjr * are met:
15103739Stjr * 1. Redistributions of source code must retain the above copyright
16103739Stjr *    notice, this list of conditions and the following disclaimer.
17103739Stjr * 2. Redistributions in binary form must reproduce the above copyright
18103739Stjr *    notice, this list of conditions and the following disclaimer in the
19103739Stjr *    documentation and/or other materials provided with the distribution.
20103739Stjr * 3. The name of the author may not be used to endorse or promote products
21103739Stjr *    derived from this software without specific prior written permission.
22103739Stjr *
23103739Stjr * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24103739Stjr * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
25103739Stjr * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
26103739Stjr * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27103739Stjr * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28103739Stjr * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29103739Stjr * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30103739Stjr * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31103739Stjr * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32103739Stjr * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33103739Stjr */
34103739Stjr
35103739Stjr#include <sys/cdefs.h>
36103739Stjr#if 0
37103739Stjr__FBSDID("FreeBSD: src/lib/libc/stdio/vasprintf.c,v 1.16 2002/08/21 16:19:57 mike Exp ");
38103739Stjr#endif
39103739Stjr__FBSDID("$FreeBSD$");
40103739Stjr
41103739Stjr#include <errno.h>
42234531Sdas#include <limits.h>
43103739Stjr#include <stdio.h>
44103739Stjr#include <stdlib.h>
45103739Stjr#include <wchar.h>
46103739Stjr#include "local.h"
47227753Stheraven#include "xlocale_private.h"
48103739Stjr
49103739Stjrint
50227753Stheravenvswprintf_l(wchar_t * __restrict s, size_t n, locale_t locale,
51227753Stheraven		const wchar_t * __restrict fmt, __va_list ap)
52103739Stjr{
53128002Stjr	static const mbstate_t initial;
54128002Stjr	mbstate_t mbs;
55205021Sjhb	FILE f = FAKE_FILE;
56103739Stjr	char *mbp;
57103997Stjr	int ret, sverrno;
58142183Sfjoe	size_t nwc;
59227753Stheraven	FIX_LOCALE(locale);
60103739Stjr
61103739Stjr	if (n == 0) {
62103739Stjr		errno = EINVAL;
63103739Stjr		return (-1);
64103739Stjr	}
65234531Sdas	if (n - 1 > INT_MAX) {
66234531Sdas		errno = EOVERFLOW;
67234531Sdas		*s = L'\0';
68234531Sdas		return (-1);
69234531Sdas	}
70103739Stjr
71103739Stjr	f._flags = __SWR | __SSTR | __SALC;
72103739Stjr	f._bf._base = f._p = (unsigned char *)malloc(128);
73103739Stjr	if (f._bf._base == NULL) {
74103739Stjr		errno = ENOMEM;
75234529Sdas		*s = L'\0';
76103739Stjr		return (-1);
77103739Stjr	}
78103739Stjr	f._bf._size = f._w = 127;		/* Leave room for the NUL */
79227753Stheraven	ret = __vfwprintf(&f, locale, fmt, ap);
80103997Stjr	if (ret < 0) {
81103997Stjr		sverrno = errno;
82103997Stjr		free(f._bf._base);
83103997Stjr		errno = sverrno;
84234529Sdas		*s = L'\0';
85103997Stjr		return (-1);
86103997Stjr	}
87103739Stjr	*f._p = '\0';
88103739Stjr	mbp = f._bf._base;
89103739Stjr	/*
90103739Stjr	 * XXX Undo the conversion from wide characters to multibyte that
91103739Stjr	 * fputwc() did in __vfwprintf().
92103739Stjr	 */
93128002Stjr	mbs = initial;
94227753Stheraven	nwc = mbsrtowcs_l(s, (const char **)&mbp, n, &mbs, locale);
95142183Sfjoe	free(f._bf._base);
96142183Sfjoe	if (nwc == (size_t)-1) {
97103739Stjr		errno = EILSEQ;
98234529Sdas		*s = L'\0';
99103739Stjr		return (-1);
100103739Stjr	}
101142183Sfjoe	if (nwc == n) {
102103739Stjr		s[n - 1] = L'\0';
103103739Stjr		errno = EOVERFLOW;
104103739Stjr		return (-1);
105103739Stjr	}
106103739Stjr
107103739Stjr	return (ret);
108103739Stjr}
109227753Stheravenint
110227753Stheravenvswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt,
111227753Stheraven    __va_list ap)
112227753Stheraven{
113227753Stheraven	return vswprintf_l(s, n, __get_locale(), fmt, ap);
114227753Stheraven}
115