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 "un-namespace.h" 45 #include "printf.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 */ 53 static char * 54 __wcsconv(wchar_t *wcsarg, int prec) 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(NULL, (const wchar_t **)&p, 0, &mbs); 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(buf, *p++, &mbs); 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(convbuf, (const wchar_t **)&p, 98 nbytes, &mbs)) == (size_t)-1) { 99 free(convbuf); 100 return (NULL); 101 } 102 convbuf[nbytes] = '\0'; 103 return (convbuf); 104 } 105 106 107 /* 's' ---------------------------------------------------------------*/ 108 109 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 int 122 __printf_render_str(struct __printf_io *io, const struct printf_info *pi, 123 const void *const *arg) 124 { 125 const char *p; 126 wchar_t *wcp; 127 char *convbuf; 128 int l; 129 130 if (pi->is_long || pi->spec == 'S') { 131 wcp = *((wint_t **)arg[0]); 132 if (wcp == NULL) 133 return (__printf_out(io, pi, "(null)", 6)); 134 convbuf = __wcsconv(wcp, pi->prec); 135 if (convbuf == NULL) 136 return (-1); 137 l = __printf_out(io, pi, convbuf, strlen(convbuf)); 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 int 153 __printf_arginfo_chr(const struct printf_info *pi, size_t n, int *argt) 154 { 155 156 assert (n > 0); 157 if (pi->is_long || pi->spec == 'C') 158 argt[0] = PA_WCHAR; 159 else 160 argt[0] = PA_INT; 161 return (1); 162 } 163 164 int 165 __printf_render_chr(struct __printf_io *io, const struct printf_info *pi, 166 const void *const *arg) 167 { 168 int i; 169 wint_t ii; 170 unsigned char c; 171 static const mbstate_t initial; /* XXX: this is bogus! */ 172 mbstate_t mbs; 173 size_t mbseqlen; 174 char buf[MB_CUR_MAX]; 175 176 if (pi->is_long || pi->spec == 'C') { 177 ii = *((wint_t *)arg[0]); 178 179 mbs = initial; 180 mbseqlen = wcrtomb(buf, (wchar_t)ii, &mbs); 181 if (mbseqlen == (size_t) -1) 182 return (-1); 183 return (__printf_out(io, pi, buf, mbseqlen)); 184 } 185 i = *((int *)arg[0]); 186 c = i; 187 i = __printf_out(io, pi, &c, 1); 188 __printf_flush(io); 189 return (i); 190 } 191