1/*- 2 * Copyright (c) 2005 Poul-Henning Kamp 3 * Copyright (c) 1990, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * Chris Torek. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * $FreeBSD: src/lib/libc/stdio/xprintf_str.c,v 1.1 2005/12/16 18:56:38 phk Exp $ 34 */ 35 36#include <namespace.h> 37#include <stdio.h> 38#include <stdlib.h> 39#include <string.h> 40#include <limits.h> 41#include <stdint.h> 42#include <assert.h> 43#include <wchar.h> 44#include "printf.h" 45#include "xprintf_private.h" 46 47/* 48 * Convert a wide character string argument for the %ls format to a multibyte 49 * string representation. If not -1, prec specifies the maximum number of 50 * bytes to output, and also means that we can't assume that the wide char. 51 * string ends is null-terminated. 52 */ 53static char * 54__wcsconv(wchar_t *wcsarg, int prec, locale_t loc) 55{ 56 static const mbstate_t initial; 57 mbstate_t mbs; 58 char buf[MB_LEN_MAX]; 59 wchar_t *p; 60 char *convbuf; 61 size_t clen, nbytes; 62 63 /* Allocate space for the maximum number of bytes we could output. */ 64 if (prec < 0) { 65 p = wcsarg; 66 mbs = initial; 67 nbytes = wcsrtombs_l(NULL, (const wchar_t **)&p, 0, &mbs, loc); 68 if (nbytes == (size_t)-1) 69 return (NULL); 70 } else { 71 /* 72 * Optimisation: if the output precision is small enough, 73 * just allocate enough memory for the maximum instead of 74 * scanning the string. 75 */ 76 if (prec < 128) 77 nbytes = prec; 78 else { 79 nbytes = 0; 80 p = wcsarg; 81 mbs = initial; 82 for (;;) { 83 clen = wcrtomb_l(buf, *p++, &mbs, loc); 84 if (clen == 0 || clen == (size_t)-1 || 85 (int)(nbytes + clen) > prec) 86 break; 87 nbytes += clen; 88 } 89 } 90 } 91 if ((convbuf = MALLOC(nbytes + 1)) == NULL) 92 return (NULL); 93 94 /* Fill the output buffer. */ 95 p = wcsarg; 96 mbs = initial; 97 if ((nbytes = wcsrtombs_l(convbuf, (const wchar_t **)&p, 98 nbytes, &mbs, loc)) == (size_t)-1) { 99 free(convbuf); 100 return (NULL); 101 } 102 convbuf[nbytes] = '\0'; 103 return (convbuf); 104} 105 106 107/* 's' ---------------------------------------------------------------*/ 108 109__private_extern__ int 110__printf_arginfo_str(const struct printf_info *pi, size_t n, int *argt) 111{ 112 113 assert (n > 0); 114 if (pi->is_long || pi->spec == 'C') 115 argt[0] = PA_WSTRING; 116 else 117 argt[0] = PA_STRING; 118 return (1); 119} 120 121__private_extern__ int 122__printf_render_str(struct __printf_io *io, const struct printf_info *pi, const void *const *arg) 123{ 124 const char *p; 125 wchar_t *wcp; 126 char *convbuf; 127 int l; 128 129 if (pi->is_long || pi->spec == 'S') { 130 wcp = *((wint_t **)arg[0]); 131 if (wcp == NULL) 132 return (__printf_out(io, pi, "(null)", 6)); 133 convbuf = __wcsconv(wcp, pi->prec, pi->loc); 134 if (convbuf == NULL) 135 return (-1); 136 l = __printf_out(io, pi, convbuf, strlen(convbuf)); 137 __printf_flush(io); 138 free(convbuf); 139 return (l); 140 } 141 p = *((char **)arg[0]); 142 if (p == NULL) 143 return (__printf_out(io, pi, "(null)", 6)); 144 l = strlen(p); 145 if (pi->prec >= 0 && pi->prec < l) 146 l = pi->prec; 147 return (__printf_out(io, pi, p, l)); 148} 149 150/* 'c' ---------------------------------------------------------------*/ 151 152__private_extern__ int 153__printf_arginfo_chr(const struct printf_info *pi, size_t n, int *argt) 154{ 155 156 assert (n > 0); 157#ifdef VECTORS 158 if (pi->is_vec) 159 argt[0] = PA_VECTOR; 160 else 161#endif /* VECTORS */ 162 if (pi->is_long || pi->spec == 'C') 163 argt[0] = PA_WCHAR; 164 else 165 argt[0] = PA_INT; 166 return (1); 167} 168 169__private_extern__ int 170__printf_render_chr(struct __printf_io *io, const struct printf_info *pi, const void *const *arg) 171{ 172 int i; 173 wint_t ii; 174 unsigned char c; 175 static const mbstate_t initial; /* XXX: this is bogus! */ 176 mbstate_t mbs; 177 size_t mbseqlen; 178 char buf[MB_CUR_MAX_L(pi->loc)]; 179 180#ifdef VECTORS 181 if (pi->is_vec) return __xprintf_vector(io, pi, arg); 182#endif /* VECTORS */ 183 184 if (pi->is_long || pi->spec == 'C') { 185 int ret; 186 ii = *((wint_t *)arg[0]); 187 188 mbs = initial; 189 mbseqlen = wcrtomb_l(buf, (wchar_t)ii, &mbs, pi->loc); 190 if (mbseqlen == (size_t) -1) 191 return (-1); 192 ret = __printf_out(io, pi, buf, mbseqlen); 193 __printf_flush(io); 194 return ret; 195 } 196 i = *((int *)arg[0]); 197 c = i; 198 i = __printf_out(io, pi, &c, 1); 199 __printf_flush(io); 200 return (i); 201} 202