1153486Sphk/*-
2153486Sphk * Copyright (c) 2005 Poul-Henning Kamp
3153486Sphk * Copyright (c) 1990, 1993
4153486Sphk *	The Regents of the University of California.  All rights reserved.
5153486Sphk *
6153486Sphk * This code is derived from software contributed to Berkeley by
7153486Sphk * Chris Torek.
8153486Sphk *
9153486Sphk * Redistribution and use in source and binary forms, with or without
10153486Sphk * modification, are permitted provided that the following conditions
11153486Sphk * are met:
12153486Sphk * 1. Redistributions of source code must retain the above copyright
13153486Sphk *    notice, this list of conditions and the following disclaimer.
14153486Sphk * 2. Redistributions in binary form must reproduce the above copyright
15153486Sphk *    notice, this list of conditions and the following disclaimer in the
16153486Sphk *    documentation and/or other materials provided with the distribution.
17153486Sphk * 3. Neither the name of the University nor the names of its contributors
18153486Sphk *    may be used to endorse or promote products derived from this software
19153486Sphk *    without specific prior written permission.
20153486Sphk *
21153486Sphk * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22153486Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23153486Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24153486Sphk * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25153486Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26153486Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27153486Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28153486Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29153486Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30153486Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31153486Sphk * SUCH DAMAGE.
32153486Sphk *
33153486Sphk * $FreeBSD$
34153486Sphk */
35153486Sphk
36153486Sphk#include <namespace.h>
37153486Sphk#include <stdio.h>
38153486Sphk#include <stdlib.h>
39153486Sphk#include <string.h>
40153486Sphk#include <limits.h>
41153486Sphk#include <stdint.h>
42153486Sphk#include <assert.h>
43153486Sphk#include <wchar.h>
44153486Sphk#include "printf.h"
45153486Sphk
46153486Sphk/*
47153486Sphk * Convert a wide character string argument for the %ls format to a multibyte
48153486Sphk * string representation. If not -1, prec specifies the maximum number of
49153486Sphk * bytes to output, and also means that we can't assume that the wide char.
50153486Sphk * string ends is null-terminated.
51153486Sphk */
52153486Sphkstatic char *
53153486Sphk__wcsconv(wchar_t *wcsarg, int prec)
54153486Sphk{
55153486Sphk	static const mbstate_t initial;
56153486Sphk	mbstate_t mbs;
57153486Sphk	char buf[MB_LEN_MAX];
58153486Sphk	wchar_t *p;
59153486Sphk	char *convbuf;
60153486Sphk	size_t clen, nbytes;
61153486Sphk
62153486Sphk	/* Allocate space for the maximum number of bytes we could output. */
63153486Sphk	if (prec < 0) {
64153486Sphk		p = wcsarg;
65153486Sphk		mbs = initial;
66153486Sphk		nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs);
67153486Sphk		if (nbytes == (size_t)-1)
68153486Sphk			return (NULL);
69153486Sphk	} else {
70153486Sphk		/*
71153486Sphk		 * Optimisation: if the output precision is small enough,
72153486Sphk		 * just allocate enough memory for the maximum instead of
73153486Sphk		 * scanning the string.
74153486Sphk		 */
75153486Sphk		if (prec < 128)
76153486Sphk			nbytes = prec;
77153486Sphk		else {
78153486Sphk			nbytes = 0;
79153486Sphk			p = wcsarg;
80153486Sphk			mbs = initial;
81153486Sphk			for (;;) {
82153486Sphk				clen = wcrtomb(buf, *p++, &mbs);
83153486Sphk				if (clen == 0 || clen == (size_t)-1 ||
84153486Sphk				    (int)(nbytes + clen) > prec)
85153486Sphk					break;
86153486Sphk				nbytes += clen;
87153486Sphk			}
88153486Sphk		}
89153486Sphk	}
90153486Sphk	if ((convbuf = malloc(nbytes + 1)) == NULL)
91153486Sphk		return (NULL);
92153486Sphk
93153486Sphk	/* Fill the output buffer. */
94153486Sphk	p = wcsarg;
95153486Sphk	mbs = initial;
96153486Sphk	if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p,
97153486Sphk	    nbytes, &mbs)) == (size_t)-1) {
98153486Sphk		free(convbuf);
99153486Sphk		return (NULL);
100153486Sphk	}
101153486Sphk	convbuf[nbytes] = '\0';
102153486Sphk	return (convbuf);
103153486Sphk}
104153486Sphk
105153486Sphk
106153486Sphk/* 's' ---------------------------------------------------------------*/
107153486Sphk
108153486Sphkint
109153486Sphk__printf_arginfo_str(const struct printf_info *pi, size_t n, int *argt)
110153486Sphk{
111153486Sphk
112153486Sphk	assert (n > 0);
113153486Sphk	if (pi->is_long || pi->spec == 'C')
114153486Sphk		argt[0] = PA_WSTRING;
115153486Sphk	else
116153486Sphk		argt[0] = PA_STRING;
117153486Sphk	return (1);
118153486Sphk}
119153486Sphk
120153486Sphkint
121153486Sphk__printf_render_str(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
122153486Sphk{
123153486Sphk	const char *p;
124153486Sphk	wchar_t *wcp;
125153486Sphk	char *convbuf;
126153486Sphk	int l;
127153486Sphk
128153486Sphk	if (pi->is_long || pi->spec == 'S') {
129153486Sphk		wcp = *((wint_t **)arg[0]);
130153486Sphk		if (wcp == NULL)
131153486Sphk			return (__printf_out(io, pi, "(null)", 6));
132153486Sphk		convbuf = __wcsconv(wcp, pi->prec);
133153486Sphk		if (convbuf == NULL)
134153486Sphk			return (-1);
135153486Sphk		l = __printf_out(io, pi, convbuf, strlen(convbuf));
136153486Sphk		free(convbuf);
137153486Sphk		return (l);
138153486Sphk	}
139153486Sphk	p = *((char **)arg[0]);
140153486Sphk	if (p == NULL)
141153486Sphk		return (__printf_out(io, pi, "(null)", 6));
142153486Sphk	l = strlen(p);
143153486Sphk	if (pi->prec >= 0 && pi->prec < l)
144153486Sphk		l = pi->prec;
145153486Sphk	return (__printf_out(io, pi, p, l));
146153486Sphk}
147153486Sphk
148153486Sphk/* 'c' ---------------------------------------------------------------*/
149153486Sphk
150153486Sphkint
151153486Sphk__printf_arginfo_chr(const struct printf_info *pi, size_t n, int *argt)
152153486Sphk{
153153486Sphk
154153486Sphk	assert (n > 0);
155153486Sphk	if (pi->is_long || pi->spec == 'C')
156153486Sphk		argt[0] = PA_WCHAR;
157153486Sphk	else
158153486Sphk		argt[0] = PA_INT;
159153486Sphk	return (1);
160153486Sphk}
161153486Sphk
162153486Sphkint
163153486Sphk__printf_render_chr(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
164153486Sphk{
165153486Sphk	int i;
166153486Sphk	wint_t ii;
167153486Sphk	unsigned char c;
168153486Sphk	static const mbstate_t initial;		/* XXX: this is bogus! */
169153486Sphk	mbstate_t mbs;
170153486Sphk	size_t mbseqlen;
171153486Sphk	char buf[MB_CUR_MAX];
172153486Sphk
173153486Sphk	if (pi->is_long || pi->spec == 'C') {
174153486Sphk		ii = *((wint_t *)arg[0]);
175153486Sphk
176153486Sphk		mbs = initial;
177153486Sphk		mbseqlen = wcrtomb(buf, (wchar_t)ii, &mbs);
178153486Sphk		if (mbseqlen == (size_t) -1)
179153486Sphk			return (-1);
180153486Sphk		return (__printf_out(io, pi, buf, mbseqlen));
181153486Sphk	}
182153486Sphk	i = *((int *)arg[0]);
183153486Sphk	c = i;
184153486Sphk	i = __printf_out(io, pi, &c, 1);
185153486Sphk	__printf_flush(io);
186153486Sphk	return (i);
187153486Sphk}
188