175067f4fSPoul-Henning Kamp /*- 275067f4fSPoul-Henning Kamp * Copyright (c) 2005 Poul-Henning Kamp 375067f4fSPoul-Henning Kamp * Copyright (c) 1990, 1993 475067f4fSPoul-Henning Kamp * The Regents of the University of California. All rights reserved. 575067f4fSPoul-Henning Kamp * 675067f4fSPoul-Henning Kamp * This code is derived from software contributed to Berkeley by 775067f4fSPoul-Henning Kamp * Chris Torek. 875067f4fSPoul-Henning Kamp * 975067f4fSPoul-Henning Kamp * Redistribution and use in source and binary forms, with or without 1075067f4fSPoul-Henning Kamp * modification, are permitted provided that the following conditions 1175067f4fSPoul-Henning Kamp * are met: 1275067f4fSPoul-Henning Kamp * 1. Redistributions of source code must retain the above copyright 1375067f4fSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer. 1475067f4fSPoul-Henning Kamp * 2. Redistributions in binary form must reproduce the above copyright 1575067f4fSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer in the 1675067f4fSPoul-Henning Kamp * documentation and/or other materials provided with the distribution. 1775067f4fSPoul-Henning Kamp * 3. Neither the name of the University nor the names of its contributors 1875067f4fSPoul-Henning Kamp * may be used to endorse or promote products derived from this software 1975067f4fSPoul-Henning Kamp * without specific prior written permission. 2075067f4fSPoul-Henning Kamp * 2175067f4fSPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2275067f4fSPoul-Henning Kamp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2375067f4fSPoul-Henning Kamp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2475067f4fSPoul-Henning Kamp * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2575067f4fSPoul-Henning Kamp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2675067f4fSPoul-Henning Kamp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2775067f4fSPoul-Henning Kamp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2875067f4fSPoul-Henning Kamp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2975067f4fSPoul-Henning Kamp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3075067f4fSPoul-Henning Kamp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3175067f4fSPoul-Henning Kamp * SUCH DAMAGE. 3275067f4fSPoul-Henning Kamp * 3375067f4fSPoul-Henning Kamp * $FreeBSD$ 3475067f4fSPoul-Henning Kamp */ 3575067f4fSPoul-Henning Kamp 3675067f4fSPoul-Henning Kamp #include <namespace.h> 3775067f4fSPoul-Henning Kamp #include <stdio.h> 3875067f4fSPoul-Henning Kamp #include <stdlib.h> 3975067f4fSPoul-Henning Kamp #include <string.h> 4075067f4fSPoul-Henning Kamp #include <limits.h> 4175067f4fSPoul-Henning Kamp #include <stdint.h> 4275067f4fSPoul-Henning Kamp #include <assert.h> 4375067f4fSPoul-Henning Kamp #include <wchar.h> 4475067f4fSPoul-Henning Kamp #include "printf.h" 4575067f4fSPoul-Henning Kamp 4675067f4fSPoul-Henning Kamp /* 4775067f4fSPoul-Henning Kamp * Convert a wide character string argument for the %ls format to a multibyte 4875067f4fSPoul-Henning Kamp * string representation. If not -1, prec specifies the maximum number of 4975067f4fSPoul-Henning Kamp * bytes to output, and also means that we can't assume that the wide char. 5075067f4fSPoul-Henning Kamp * string ends is null-terminated. 5175067f4fSPoul-Henning Kamp */ 5275067f4fSPoul-Henning Kamp static char * 5375067f4fSPoul-Henning Kamp __wcsconv(wchar_t *wcsarg, int prec) 5475067f4fSPoul-Henning Kamp { 5575067f4fSPoul-Henning Kamp static const mbstate_t initial; 5675067f4fSPoul-Henning Kamp mbstate_t mbs; 5775067f4fSPoul-Henning Kamp char buf[MB_LEN_MAX]; 5875067f4fSPoul-Henning Kamp wchar_t *p; 5975067f4fSPoul-Henning Kamp char *convbuf; 6075067f4fSPoul-Henning Kamp size_t clen, nbytes; 6175067f4fSPoul-Henning Kamp 6275067f4fSPoul-Henning Kamp /* Allocate space for the maximum number of bytes we could output. */ 6375067f4fSPoul-Henning Kamp if (prec < 0) { 6475067f4fSPoul-Henning Kamp p = wcsarg; 6575067f4fSPoul-Henning Kamp mbs = initial; 6675067f4fSPoul-Henning Kamp nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs); 6775067f4fSPoul-Henning Kamp if (nbytes == (size_t)-1) 6875067f4fSPoul-Henning Kamp return (NULL); 6975067f4fSPoul-Henning Kamp } else { 7075067f4fSPoul-Henning Kamp /* 7175067f4fSPoul-Henning Kamp * Optimisation: if the output precision is small enough, 7275067f4fSPoul-Henning Kamp * just allocate enough memory for the maximum instead of 7375067f4fSPoul-Henning Kamp * scanning the string. 7475067f4fSPoul-Henning Kamp */ 7575067f4fSPoul-Henning Kamp if (prec < 128) 7675067f4fSPoul-Henning Kamp nbytes = prec; 7775067f4fSPoul-Henning Kamp else { 7875067f4fSPoul-Henning Kamp nbytes = 0; 7975067f4fSPoul-Henning Kamp p = wcsarg; 8075067f4fSPoul-Henning Kamp mbs = initial; 8175067f4fSPoul-Henning Kamp for (;;) { 8275067f4fSPoul-Henning Kamp clen = wcrtomb(buf, *p++, &mbs); 8375067f4fSPoul-Henning Kamp if (clen == 0 || clen == (size_t)-1 || 8475067f4fSPoul-Henning Kamp (int)(nbytes + clen) > prec) 8575067f4fSPoul-Henning Kamp break; 8675067f4fSPoul-Henning Kamp nbytes += clen; 8775067f4fSPoul-Henning Kamp } 8875067f4fSPoul-Henning Kamp } 8975067f4fSPoul-Henning Kamp } 9075067f4fSPoul-Henning Kamp if ((convbuf = malloc(nbytes + 1)) == NULL) 9175067f4fSPoul-Henning Kamp return (NULL); 9275067f4fSPoul-Henning Kamp 9375067f4fSPoul-Henning Kamp /* Fill the output buffer. */ 9475067f4fSPoul-Henning Kamp p = wcsarg; 9575067f4fSPoul-Henning Kamp mbs = initial; 9675067f4fSPoul-Henning Kamp if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p, 9775067f4fSPoul-Henning Kamp nbytes, &mbs)) == (size_t)-1) { 9875067f4fSPoul-Henning Kamp free(convbuf); 9975067f4fSPoul-Henning Kamp return (NULL); 10075067f4fSPoul-Henning Kamp } 10175067f4fSPoul-Henning Kamp convbuf[nbytes] = '\0'; 10275067f4fSPoul-Henning Kamp return (convbuf); 10375067f4fSPoul-Henning Kamp } 10475067f4fSPoul-Henning Kamp 10575067f4fSPoul-Henning Kamp 10675067f4fSPoul-Henning Kamp /* 's' ---------------------------------------------------------------*/ 10775067f4fSPoul-Henning Kamp 10875067f4fSPoul-Henning Kamp int 10975067f4fSPoul-Henning Kamp __printf_arginfo_str(const struct printf_info *pi, size_t n, int *argt) 11075067f4fSPoul-Henning Kamp { 11175067f4fSPoul-Henning Kamp 11275067f4fSPoul-Henning Kamp assert (n > 0); 11375067f4fSPoul-Henning Kamp if (pi->is_long || pi->spec == 'C') 11475067f4fSPoul-Henning Kamp argt[0] = PA_WSTRING; 11575067f4fSPoul-Henning Kamp else 11675067f4fSPoul-Henning Kamp argt[0] = PA_STRING; 11775067f4fSPoul-Henning Kamp return (1); 11875067f4fSPoul-Henning Kamp } 11975067f4fSPoul-Henning Kamp 12075067f4fSPoul-Henning Kamp int 12175067f4fSPoul-Henning Kamp __printf_render_str(struct __printf_io *io, const struct printf_info *pi, const void *const *arg) 12275067f4fSPoul-Henning Kamp { 12375067f4fSPoul-Henning Kamp const char *p; 12475067f4fSPoul-Henning Kamp wchar_t *wcp; 12575067f4fSPoul-Henning Kamp char *convbuf; 12675067f4fSPoul-Henning Kamp int l; 12775067f4fSPoul-Henning Kamp 12875067f4fSPoul-Henning Kamp if (pi->is_long || pi->spec == 'S') { 12975067f4fSPoul-Henning Kamp wcp = *((wint_t **)arg[0]); 13075067f4fSPoul-Henning Kamp if (wcp == NULL) 13175067f4fSPoul-Henning Kamp return (__printf_out(io, pi, "(null)", 6)); 13275067f4fSPoul-Henning Kamp convbuf = __wcsconv(wcp, pi->prec); 13375067f4fSPoul-Henning Kamp if (convbuf == NULL) 13475067f4fSPoul-Henning Kamp return (-1); 13575067f4fSPoul-Henning Kamp l = __printf_out(io, pi, convbuf, strlen(convbuf)); 13675067f4fSPoul-Henning Kamp free(convbuf); 13775067f4fSPoul-Henning Kamp return (l); 13875067f4fSPoul-Henning Kamp } 13975067f4fSPoul-Henning Kamp p = *((char **)arg[0]); 14075067f4fSPoul-Henning Kamp if (p == NULL) 14175067f4fSPoul-Henning Kamp return (__printf_out(io, pi, "(null)", 6)); 14275067f4fSPoul-Henning Kamp l = strlen(p); 14375067f4fSPoul-Henning Kamp if (pi->prec >= 0 && pi->prec < l) 14475067f4fSPoul-Henning Kamp l = pi->prec; 14575067f4fSPoul-Henning Kamp return (__printf_out(io, pi, p, l)); 14675067f4fSPoul-Henning Kamp } 14775067f4fSPoul-Henning Kamp 14875067f4fSPoul-Henning Kamp /* 'c' ---------------------------------------------------------------*/ 14975067f4fSPoul-Henning Kamp 15075067f4fSPoul-Henning Kamp int 15175067f4fSPoul-Henning Kamp __printf_arginfo_chr(const struct printf_info *pi, size_t n, int *argt) 15275067f4fSPoul-Henning Kamp { 15375067f4fSPoul-Henning Kamp 15475067f4fSPoul-Henning Kamp assert (n > 0); 15575067f4fSPoul-Henning Kamp if (pi->is_long || pi->spec == 'C') 15675067f4fSPoul-Henning Kamp argt[0] = PA_WCHAR; 15775067f4fSPoul-Henning Kamp else 15875067f4fSPoul-Henning Kamp argt[0] = PA_INT; 15975067f4fSPoul-Henning Kamp return (1); 16075067f4fSPoul-Henning Kamp } 16175067f4fSPoul-Henning Kamp 16275067f4fSPoul-Henning Kamp int 16375067f4fSPoul-Henning Kamp __printf_render_chr(struct __printf_io *io, const struct printf_info *pi, const void *const *arg) 16475067f4fSPoul-Henning Kamp { 16575067f4fSPoul-Henning Kamp int i; 16675067f4fSPoul-Henning Kamp wint_t ii; 16775067f4fSPoul-Henning Kamp unsigned char c; 16875067f4fSPoul-Henning Kamp static const mbstate_t initial; /* XXX: this is bogus! */ 16975067f4fSPoul-Henning Kamp mbstate_t mbs; 17075067f4fSPoul-Henning Kamp size_t mbseqlen; 17175067f4fSPoul-Henning Kamp char buf[MB_CUR_MAX]; 17275067f4fSPoul-Henning Kamp 17375067f4fSPoul-Henning Kamp if (pi->is_long || pi->spec == 'C') { 17475067f4fSPoul-Henning Kamp ii = *((wint_t *)arg[0]); 17575067f4fSPoul-Henning Kamp 17675067f4fSPoul-Henning Kamp mbs = initial; 17775067f4fSPoul-Henning Kamp mbseqlen = wcrtomb(buf, (wchar_t)ii, &mbs); 17875067f4fSPoul-Henning Kamp if (mbseqlen == (size_t) -1) 17975067f4fSPoul-Henning Kamp return (-1); 18075067f4fSPoul-Henning Kamp return (__printf_out(io, pi, buf, mbseqlen)); 18175067f4fSPoul-Henning Kamp } 18275067f4fSPoul-Henning Kamp i = *((int *)arg[0]); 18375067f4fSPoul-Henning Kamp c = i; 18475067f4fSPoul-Henning Kamp i = __printf_out(io, pi, &c, 1); 18575067f4fSPoul-Henning Kamp __printf_flush(io); 18675067f4fSPoul-Henning Kamp return (i); 18775067f4fSPoul-Henning Kamp } 188