xprintf_str.c revision 153486
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: head/lib/libc/stdio/xprintf_str.c 153486 2005-12-16 18:56:39Z phk $ 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