xref: /freebsd/lib/libc/stdio/vswprintf.c (revision 9fc0ff9d85b1497b45a4c6d74e0bc7eea9dcf37b)
1c5604d0aSTim J. Robbins /*	$OpenBSD: vasprintf.c,v 1.4 1998/06/21 22:13:47 millert Exp $	*/
2c5604d0aSTim J. Robbins 
3d915a14eSPedro F. Giffuni /*-
4d915a14eSPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
5d915a14eSPedro F. Giffuni  *
6c5604d0aSTim J. Robbins  * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
7c5604d0aSTim J. Robbins  * All rights reserved.
8c5604d0aSTim J. Robbins  *
93c87aa1dSDavid Chisnall  * Copyright (c) 2011 The FreeBSD Foundation
10*5b5fa75aSEd Maste  *
113c87aa1dSDavid Chisnall  * Portions of this software were developed by David Chisnall
123c87aa1dSDavid Chisnall  * under sponsorship from the FreeBSD Foundation.
133c87aa1dSDavid Chisnall  *
14c5604d0aSTim J. Robbins  * Redistribution and use in source and binary forms, with or without
15c5604d0aSTim J. Robbins  * modification, are permitted provided that the following conditions
16c5604d0aSTim J. Robbins  * are met:
17c5604d0aSTim J. Robbins  * 1. Redistributions of source code must retain the above copyright
18c5604d0aSTim J. Robbins  *    notice, this list of conditions and the following disclaimer.
19c5604d0aSTim J. Robbins  * 2. Redistributions in binary form must reproduce the above copyright
20c5604d0aSTim J. Robbins  *    notice, this list of conditions and the following disclaimer in the
21c5604d0aSTim J. Robbins  *    documentation and/or other materials provided with the distribution.
22c5604d0aSTim J. Robbins  * 3. The name of the author may not be used to endorse or promote products
23c5604d0aSTim J. Robbins  *    derived from this software without specific prior written permission.
24c5604d0aSTim J. Robbins  *
25c5604d0aSTim J. Robbins  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
26c5604d0aSTim J. Robbins  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27c5604d0aSTim J. Robbins  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
28c5604d0aSTim J. Robbins  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29c5604d0aSTim J. Robbins  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30c5604d0aSTim J. Robbins  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
31c5604d0aSTim J. Robbins  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32c5604d0aSTim J. Robbins  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
33c5604d0aSTim J. Robbins  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
34c5604d0aSTim J. Robbins  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35c5604d0aSTim J. Robbins  */
36c5604d0aSTim J. Robbins 
37c5604d0aSTim J. Robbins #include <errno.h>
38666d00d3SDavid Schultz #include <limits.h>
39c5604d0aSTim J. Robbins #include <stdio.h>
40c5604d0aSTim J. Robbins #include <stdlib.h>
41c5604d0aSTim J. Robbins #include <wchar.h>
42c5604d0aSTim J. Robbins #include "local.h"
433c87aa1dSDavid Chisnall #include "xlocale_private.h"
44c5604d0aSTim J. Robbins 
45c5604d0aSTim J. Robbins int
vswprintf_l(wchar_t * __restrict s,size_t n,locale_t locale,const wchar_t * __restrict fmt,__va_list ap)463c87aa1dSDavid Chisnall vswprintf_l(wchar_t * __restrict s, size_t n, locale_t locale,
473c87aa1dSDavid Chisnall 		const wchar_t * __restrict fmt, __va_list ap)
48c5604d0aSTim J. Robbins {
4993996f6dSTim J. Robbins 	static const mbstate_t initial;
5093996f6dSTim J. Robbins 	mbstate_t mbs;
511b0181dfSJohn Baldwin 	FILE f = FAKE_FILE;
52c5604d0aSTim J. Robbins 	char *mbp;
5323b6f790STim J. Robbins 	int ret, sverrno;
54f1defde9SMax Khon 	size_t nwc;
553c87aa1dSDavid Chisnall 	FIX_LOCALE(locale);
56c5604d0aSTim J. Robbins 
57c5604d0aSTim J. Robbins 	if (n == 0) {
58c5604d0aSTim J. Robbins 		errno = EINVAL;
59c5604d0aSTim J. Robbins 		return (-1);
60c5604d0aSTim J. Robbins 	}
61666d00d3SDavid Schultz 	if (n - 1 > INT_MAX) {
62666d00d3SDavid Schultz 		errno = EOVERFLOW;
63666d00d3SDavid Schultz 		*s = L'\0';
64666d00d3SDavid Schultz 		return (-1);
65666d00d3SDavid Schultz 	}
66c5604d0aSTim J. Robbins 
67c5604d0aSTim J. Robbins 	f._flags = __SWR | __SSTR | __SALC;
68c5604d0aSTim J. Robbins 	f._bf._base = f._p = (unsigned char *)malloc(128);
69c5604d0aSTim J. Robbins 	if (f._bf._base == NULL) {
70c5604d0aSTim J. Robbins 		errno = ENOMEM;
7104acf365SDavid Schultz 		*s = L'\0';
72c5604d0aSTim J. Robbins 		return (-1);
73c5604d0aSTim J. Robbins 	}
74c5604d0aSTim J. Robbins 	f._bf._size = f._w = 127;		/* Leave room for the NUL */
753c87aa1dSDavid Chisnall 	ret = __vfwprintf(&f, locale, fmt, ap);
7623b6f790STim J. Robbins 	if (ret < 0) {
7723b6f790STim J. Robbins 		sverrno = errno;
7823b6f790STim J. Robbins 		free(f._bf._base);
7923b6f790STim J. Robbins 		errno = sverrno;
8004acf365SDavid Schultz 		*s = L'\0';
8123b6f790STim J. Robbins 		return (-1);
8223b6f790STim J. Robbins 	}
83c5604d0aSTim J. Robbins 	*f._p = '\0';
84c5604d0aSTim J. Robbins 	mbp = f._bf._base;
85c5604d0aSTim J. Robbins 	/*
86c5604d0aSTim J. Robbins 	 * XXX Undo the conversion from wide characters to multibyte that
87c5604d0aSTim J. Robbins 	 * fputwc() did in __vfwprintf().
88c5604d0aSTim J. Robbins 	 */
8993996f6dSTim J. Robbins 	mbs = initial;
903c87aa1dSDavid Chisnall 	nwc = mbsrtowcs_l(s, (const char **)&mbp, n, &mbs, locale);
91c5604d0aSTim J. Robbins 	free(f._bf._base);
92f1defde9SMax Khon 	if (nwc == (size_t)-1) {
93c5604d0aSTim J. Robbins 		errno = EILSEQ;
9404acf365SDavid Schultz 		*s = L'\0';
95c5604d0aSTim J. Robbins 		return (-1);
96c5604d0aSTim J. Robbins 	}
97f1defde9SMax Khon 	if (nwc == n) {
98c5604d0aSTim J. Robbins 		s[n - 1] = L'\0';
99c5604d0aSTim J. Robbins 		errno = EOVERFLOW;
100c5604d0aSTim J. Robbins 		return (-1);
101c5604d0aSTim J. Robbins 	}
102c5604d0aSTim J. Robbins 
103c5604d0aSTim J. Robbins 	return (ret);
104c5604d0aSTim J. Robbins }
1053c87aa1dSDavid Chisnall int
vswprintf(wchar_t * __restrict s,size_t n,const wchar_t * __restrict fmt,__va_list ap)1063c87aa1dSDavid Chisnall vswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt,
1073c87aa1dSDavid Chisnall     __va_list ap)
1083c87aa1dSDavid Chisnall {
1093c87aa1dSDavid Chisnall 	return vswprintf_l(s, n, __get_locale(), fmt, ap);
1103c87aa1dSDavid Chisnall }
111