xprintf.c revision 178287
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.c 178287 2008-04-17 22:17:54Z jhb $ 34153486Sphk */ 35153486Sphk 36153486Sphk#include <namespace.h> 37153486Sphk#include <err.h> 38153486Sphk#include <sys/types.h> 39153486Sphk#include <stdio.h> 40153486Sphk#include <stddef.h> 41153486Sphk#include <stdlib.h> 42153486Sphk#include <locale.h> 43153486Sphk#include <stdint.h> 44153486Sphk#include <assert.h> 45153486Sphk#include <stdarg.h> 46153486Sphk#include <namespace.h> 47153486Sphk#include <string.h> 48153486Sphk#include <wchar.h> 49153486Sphk#include <un-namespace.h> 50153486Sphk 51153486Sphk#include "printf.h" 52153486Sphk#include "fvwrite.h" 53153486Sphk 54153486Sphkint __use_xprintf = -1; 55153486Sphk 56153486Sphk/* private stuff -----------------------------------------------------*/ 57153486Sphk 58153486Sphkunion arg { 59153486Sphk int intarg; 60153486Sphk long longarg; 61153486Sphk intmax_t intmaxarg; 62153486Sphk#ifndef NO_FLOATING_POINT 63153486Sphk double doublearg; 64153486Sphk long double longdoublearg; 65153486Sphk#endif 66153486Sphk wint_t wintarg; 67153486Sphk char *pchararg; 68153486Sphk wchar_t *pwchararg; 69153486Sphk void *pvoidarg; 70153486Sphk}; 71153486Sphk 72153486Sphk/* 73153486Sphk * Macros for converting digits to letters and vice versa 74153486Sphk */ 75153486Sphk#define to_digit(c) ((c) - '0') 76153486Sphk#define is_digit(c) (((unsigned)to_digit(c)) <= 9) 77153486Sphk 78153486Sphk/* various globals ---------------------------------------------------*/ 79153486Sphk 80153486Sphkconst char __lowercase_hex[17] = "0123456789abcdef?"; /*lint !e784 */ 81153486Sphkconst char __uppercase_hex[17] = "0123456789ABCDEF?"; /*lint !e784 */ 82153486Sphk 83153486Sphk#define PADSIZE 16 84153486Sphkstatic char blanks[PADSIZE] = 85153486Sphk {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 86153486Sphkstatic char zeroes[PADSIZE] = 87153486Sphk {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 88153486Sphk 89153486Sphk/* printing and padding functions ------------------------------------*/ 90153486Sphk 91153486Sphk#define NIOV 8 92153486Sphk 93153486Sphkstruct __printf_io { 94153486Sphk FILE *fp; 95153486Sphk struct __suio uio; 96153486Sphk struct __siov iov[NIOV]; 97153486Sphk struct __siov *iovp; 98153486Sphk}; 99153486Sphk 100153486Sphkstatic void 101153486Sphk__printf_init(struct __printf_io *io) 102153486Sphk{ 103153486Sphk 104153486Sphk io->uio.uio_iov = io->iovp = &io->iov[0]; 105153486Sphk io->uio.uio_resid = 0; 106153486Sphk io->uio.uio_iovcnt = 0; 107153486Sphk} 108153486Sphk 109153486Sphkvoid 110153486Sphk__printf_flush(struct __printf_io *io) 111153486Sphk{ 112153486Sphk 113153486Sphk __sfvwrite(io->fp, &io->uio); 114153486Sphk __printf_init(io); 115153486Sphk} 116153486Sphk 117153486Sphkint 118153486Sphk__printf_puts(struct __printf_io *io, const void *ptr, int len) 119153486Sphk{ 120153486Sphk 121153486Sphk 122153486Sphk if (io->fp->_flags & __SERR) 123153486Sphk return (0); 124153486Sphk if (len == 0) 125153486Sphk return (0); 126153486Sphk io->iovp->iov_base = __DECONST(void *, ptr); 127153486Sphk io->iovp->iov_len = len; 128153486Sphk io->uio.uio_resid += len; 129153486Sphk io->iovp++; 130153486Sphk io->uio.uio_iovcnt++; 131153486Sphk if (io->uio.uio_iovcnt >= NIOV) 132153486Sphk __printf_flush(io); 133153486Sphk return (len); 134153486Sphk} 135153486Sphk 136153486Sphkint 137153486Sphk__printf_pad(struct __printf_io *io, int howmany, int zero) 138153486Sphk{ 139153486Sphk int n; 140153486Sphk const char *with; 141153486Sphk int ret = 0; 142153486Sphk 143153486Sphk if (zero) 144153486Sphk with = zeroes; 145153486Sphk else 146153486Sphk with = blanks; 147153486Sphk 148153486Sphk if ((n = (howmany)) > 0) { 149153486Sphk while (n > PADSIZE) { 150153486Sphk ret += __printf_puts(io, with, PADSIZE); 151153486Sphk n -= PADSIZE; 152153486Sphk } 153153486Sphk ret += __printf_puts(io, with, n); 154153486Sphk } 155153486Sphk return (ret); 156153486Sphk} 157153486Sphk 158153486Sphkint 159153486Sphk__printf_out(struct __printf_io *io, const struct printf_info *pi, const void *ptr, int len) 160153486Sphk{ 161153486Sphk int ret = 0; 162153486Sphk 163153486Sphk if ((!pi->left) && pi->width > len) 164153486Sphk ret += __printf_pad(io, pi->width - len, pi->pad == '0'); 165153486Sphk ret += __printf_puts(io, ptr, len); 166153486Sphk if (pi->left && pi->width > len) 167153486Sphk ret += __printf_pad(io, pi->width - len, pi->pad == '0'); 168153486Sphk return (ret); 169153486Sphk} 170153486Sphk 171153486Sphk 172153486Sphk/* percent handling -------------------------------------------------*/ 173153486Sphk 174153486Sphkstatic int 175153486Sphk__printf_arginfo_pct(const struct printf_info *pi __unused, size_t n __unused, int *argt __unused) 176153486Sphk{ 177153486Sphk 178153486Sphk return (0); 179153486Sphk} 180153486Sphk 181153486Sphkstatic int 182153486Sphk__printf_render_pct(struct __printf_io *io, const struct printf_info *pi __unused, const void *const *arg __unused) 183153486Sphk{ 184153486Sphk 185153486Sphk return (__printf_puts(io, "%", 1)); 186153486Sphk} 187153486Sphk 188153486Sphk/* 'n' ---------------------------------------------------------------*/ 189153486Sphk 190153486Sphkstatic int 191153486Sphk__printf_arginfo_n(const struct printf_info *pi, size_t n, int *argt) 192153486Sphk{ 193153486Sphk 194153486Sphk assert(n >= 1); 195153486Sphk argt[0] = PA_POINTER; 196153486Sphk return (1); 197153486Sphk} 198153486Sphk 199153486Sphk/* 200153486Sphk * This is a printf_render so that all output has been flushed before it 201153486Sphk * gets called. 202153486Sphk */ 203153486Sphk 204153486Sphkstatic int 205153486Sphk__printf_render_n(FILE *io __unused, const struct printf_info *pi, const void *const *arg) 206153486Sphk{ 207153486Sphk 208153486Sphk if (pi->is_char) 209153486Sphk **((signed char **)arg[0]) = (signed char)pi->sofar; 210153486Sphk else if (pi->is_short) 211153486Sphk **((short **)arg[0]) = (short)pi->sofar; 212153486Sphk else if (pi->is_long) 213153486Sphk **((long **)arg[0]) = pi->sofar; 214153486Sphk else if (pi->is_long_double) 215153486Sphk **((long long **)arg[0]) = pi->sofar; 216153486Sphk else if (pi->is_intmax) 217153486Sphk **((intmax_t **)arg[0]) = pi->sofar; 218153486Sphk else if (pi->is_ptrdiff) 219153486Sphk **((ptrdiff_t **)arg[0]) = pi->sofar; 220153486Sphk else if (pi->is_quad) 221153486Sphk **((quad_t **)arg[0]) = pi->sofar; 222153486Sphk else if (pi->is_size) 223153486Sphk **((size_t **)arg[0]) = pi->sofar; 224153486Sphk else 225153486Sphk **((int **)arg[0]) = pi->sofar; 226153486Sphk 227153486Sphk return (0); 228153486Sphk} 229153486Sphk 230153486Sphk/* table -------------------------------------------------------------*/ 231153486Sphk 232153486Sphk/*lint -esym(785, printf_tbl) */ 233153486Sphkstatic struct { 234153486Sphk printf_arginfo_function *arginfo; 235153486Sphk printf_function *gnurender; 236153486Sphk printf_render *render; 237153486Sphk} printf_tbl[256] = { 238153486Sphk ['%'] = { __printf_arginfo_pct, NULL, __printf_render_pct }, 239153486Sphk ['A'] = { __printf_arginfo_float, NULL, __printf_render_float }, 240153486Sphk ['C'] = { __printf_arginfo_chr, NULL, __printf_render_chr }, 241153486Sphk ['E'] = { __printf_arginfo_float, NULL, __printf_render_float }, 242153486Sphk ['F'] = { __printf_arginfo_float, NULL, __printf_render_float }, 243153486Sphk ['G'] = { __printf_arginfo_float, NULL, __printf_render_float }, 244153486Sphk ['S'] = { __printf_arginfo_str, NULL, __printf_render_str }, 245153486Sphk ['X'] = { __printf_arginfo_int, NULL, __printf_render_int }, 246153486Sphk ['a'] = { __printf_arginfo_float, NULL, __printf_render_float }, 247153486Sphk ['c'] = { __printf_arginfo_chr, NULL, __printf_render_chr }, 248153486Sphk ['d'] = { __printf_arginfo_int, NULL, __printf_render_int }, 249153486Sphk ['e'] = { __printf_arginfo_float, NULL, __printf_render_float }, 250153486Sphk ['f'] = { __printf_arginfo_float, NULL, __printf_render_float }, 251153486Sphk ['g'] = { __printf_arginfo_float, NULL, __printf_render_float }, 252153486Sphk ['i'] = { __printf_arginfo_int, NULL, __printf_render_int }, 253153486Sphk ['n'] = { __printf_arginfo_n, __printf_render_n, NULL }, 254153486Sphk ['o'] = { __printf_arginfo_int, NULL, __printf_render_int }, 255153486Sphk ['p'] = { __printf_arginfo_ptr, NULL, __printf_render_ptr }, 256153486Sphk ['q'] = { __printf_arginfo_int, NULL, __printf_render_int }, 257153486Sphk ['s'] = { __printf_arginfo_str, NULL, __printf_render_str }, 258153486Sphk ['u'] = { __printf_arginfo_int, NULL, __printf_render_int }, 259153486Sphk ['x'] = { __printf_arginfo_int, NULL, __printf_render_int }, 260153486Sphk}; 261153486Sphk 262153486Sphk 263153486Sphkstatic int 264163624Skib__v2printf(FILE *fp, const char *fmt0, unsigned pct, va_list ap) 265153486Sphk{ 266153486Sphk struct printf_info *pi, *pil; 267153486Sphk const char *fmt; 268153486Sphk int ch; 269153486Sphk struct printf_info pia[pct + 10]; 270153486Sphk int argt[pct + 10]; 271153486Sphk union arg args[pct + 10]; 272153486Sphk int nextarg; 273153486Sphk int maxarg; 274153486Sphk int ret = 0; 275153486Sphk int n; 276153486Sphk struct __printf_io io; 277153486Sphk 278153486Sphk __printf_init(&io); 279153486Sphk io.fp = fp; 280153486Sphk 281153486Sphk fmt = fmt0; 282153486Sphk maxarg = 0; 283153486Sphk nextarg = 1; 284153486Sphk memset(argt, 0, sizeof argt); 285153486Sphk for (pi = pia; ; pi++) { 286153486Sphk memset(pi, 0, sizeof *pi); 287153486Sphk pil = pi; 288153486Sphk if (*fmt == '\0') 289153486Sphk break; 290153486Sphk pil = pi + 1; 291153486Sphk pi->prec = -1; 292153486Sphk pi->pad = ' '; 293153486Sphk pi->begin = pi->end = fmt; 294153486Sphk while (*fmt != '\0' && *fmt != '%') 295153486Sphk pi->end = ++fmt; 296153486Sphk if (*fmt == '\0') 297153486Sphk break; 298153486Sphk fmt++; 299153486Sphk for (;;) { 300153486Sphk pi->spec = *fmt; 301153486Sphk switch (pi->spec) { 302153486Sphk case ' ': 303153486Sphk /*- 304153486Sphk * ``If the space and + flags both appear, the space 305153486Sphk * flag will be ignored.'' 306153486Sphk * -- ANSI X3J11 307153486Sphk */ 308153486Sphk if (pi->showsign == 0) 309153486Sphk pi->showsign = ' '; 310153486Sphk fmt++; 311153486Sphk continue; 312153486Sphk case '#': 313153486Sphk pi->alt = 1; 314153486Sphk fmt++; 315153486Sphk continue; 316153486Sphk case '.': 317153486Sphk pi->prec = 0; 318153486Sphk fmt++; 319153486Sphk if (*fmt == '*') { 320153486Sphk fmt++; 321153486Sphk pi->get_prec = nextarg; 322153486Sphk argt[nextarg++] = PA_INT; 323153486Sphk continue; 324153486Sphk } 325153486Sphk while (*fmt != '\0' && is_digit(*fmt)) { 326153486Sphk pi->prec *= 10; 327153486Sphk pi->prec += to_digit(*fmt); 328153486Sphk fmt++; 329153486Sphk } 330153486Sphk continue; 331153486Sphk case '-': 332153486Sphk pi->left = 1; 333153486Sphk fmt++; 334153486Sphk continue; 335153486Sphk case '+': 336153486Sphk pi->showsign = '+'; 337153486Sphk fmt++; 338153486Sphk continue; 339153486Sphk case '*': 340153486Sphk fmt++; 341153486Sphk pi->get_width = nextarg; 342153486Sphk argt[nextarg++] = PA_INT; 343153486Sphk continue; 344153486Sphk case '%': 345153486Sphk fmt++; 346153486Sphk break; 347153486Sphk case '\'': 348153486Sphk pi->group = 1; 349153486Sphk fmt++; 350153486Sphk continue; 351153486Sphk case '0': 352153486Sphk /*- 353153486Sphk * ``Note that 0 is taken as a flag, not as the 354153486Sphk * beginning of a field width.'' 355153486Sphk * -- ANSI X3J11 356153486Sphk */ 357153486Sphk pi->pad = '0'; 358153486Sphk fmt++; 359153486Sphk continue; 360153486Sphk case '1': case '2': case '3': 361153486Sphk case '4': case '5': case '6': 362153486Sphk case '7': case '8': case '9': 363153486Sphk n = 0; 364153486Sphk while (*fmt != '\0' && is_digit(*fmt)) { 365153486Sphk n *= 10; 366153486Sphk n += to_digit(*fmt); 367153486Sphk fmt++; 368153486Sphk } 369153486Sphk if (*fmt == '$') { 370153486Sphk if (nextarg > maxarg) 371153486Sphk maxarg = nextarg; 372153486Sphk nextarg = n; 373153486Sphk fmt++; 374153486Sphk } else 375153486Sphk pi->width = n; 376153486Sphk continue; 377153486Sphk case 'D': 378153486Sphk case 'O': 379153486Sphk case 'U': 380153486Sphk pi->spec += ('a' - 'A'); 381153486Sphk pi->is_intmax = 0; 382153486Sphk if (pi->is_long_double || pi->is_quad) { 383153486Sphk pi->is_long = 0; 384153486Sphk pi->is_long_double = 1; 385153486Sphk } else { 386153486Sphk pi->is_long = 1; 387153486Sphk pi->is_long_double = 0; 388153486Sphk } 389153486Sphk fmt++; 390153486Sphk break; 391153486Sphk case 'j': 392153486Sphk pi->is_intmax = 1; 393153486Sphk fmt++; 394153486Sphk continue; 395153486Sphk case 'q': 396153486Sphk pi->is_long = 0; 397153486Sphk pi->is_quad = 1; 398153486Sphk fmt++; 399153486Sphk continue; 400153486Sphk case 'L': 401153486Sphk pi->is_long_double = 1; 402153486Sphk fmt++; 403153486Sphk continue; 404153486Sphk case 'h': 405153486Sphk fmt++; 406153486Sphk if (*fmt == 'h') { 407153486Sphk fmt++; 408153486Sphk pi->is_char = 1; 409153486Sphk } else { 410153486Sphk pi->is_short = 1; 411153486Sphk } 412153486Sphk continue; 413153486Sphk case 'l': 414153486Sphk fmt++; 415153486Sphk if (*fmt == 'l') { 416153486Sphk fmt++; 417153486Sphk pi->is_long_double = 1; 418153486Sphk pi->is_quad = 0; 419153486Sphk } else { 420153486Sphk pi->is_quad = 0; 421153486Sphk pi->is_long = 1; 422153486Sphk } 423153486Sphk continue; 424153486Sphk case 't': 425153486Sphk pi->is_ptrdiff = 1; 426153486Sphk fmt++; 427153486Sphk continue; 428153486Sphk case 'z': 429153486Sphk pi->is_size = 1; 430153486Sphk fmt++; 431153486Sphk continue; 432153486Sphk default: 433153486Sphk fmt++; 434153486Sphk break; 435153486Sphk } 436153486Sphk if (printf_tbl[pi->spec].arginfo == NULL) 437153486Sphk errx(1, "arginfo[%c] = NULL", pi->spec); 438153486Sphk ch = printf_tbl[pi->spec].arginfo( 439153486Sphk pi, __PRINTFMAXARG, &argt[nextarg]); 440153486Sphk if (ch > 0) 441153486Sphk pi->arg[0] = &args[nextarg]; 442153486Sphk if (ch > 1) 443153486Sphk pi->arg[1] = &args[nextarg + 1]; 444153486Sphk nextarg += ch; 445153486Sphk break; 446153486Sphk } 447153486Sphk } 448153486Sphk if (nextarg > maxarg) 449153486Sphk maxarg = nextarg; 450153486Sphk#if 0 451153486Sphk fprintf(stderr, "fmt0 <%s>\n", fmt0); 452153486Sphk fprintf(stderr, "pil %p\n", pil); 453153486Sphk#endif 454153486Sphk for (ch = 1; ch < maxarg; ch++) { 455153486Sphk#if 0 456153486Sphk fprintf(stderr, "arg %d %x\n", ch, argt[ch]); 457153486Sphk#endif 458153486Sphk switch(argt[ch]) { 459153486Sphk case PA_CHAR: 460153486Sphk args[ch].intarg = (char)va_arg (ap, int); 461153486Sphk break; 462153486Sphk case PA_INT: 463153486Sphk args[ch].intarg = va_arg (ap, int); 464153486Sphk break; 465153486Sphk case PA_INT | PA_FLAG_SHORT: 466153486Sphk args[ch].intarg = (short)va_arg (ap, int); 467153486Sphk break; 468153486Sphk case PA_INT | PA_FLAG_LONG: 469153486Sphk args[ch].longarg = va_arg (ap, long); 470153486Sphk break; 471153486Sphk case PA_INT | PA_FLAG_INTMAX: 472153486Sphk args[ch].intmaxarg = va_arg (ap, intmax_t); 473153486Sphk break; 474153486Sphk case PA_INT | PA_FLAG_QUAD: 475153486Sphk args[ch].intmaxarg = va_arg (ap, quad_t); 476153486Sphk break; 477153486Sphk case PA_INT | PA_FLAG_LONG_LONG: 478153486Sphk args[ch].intmaxarg = va_arg (ap, long long); 479153486Sphk break; 480153486Sphk case PA_INT | PA_FLAG_SIZE: 481153486Sphk args[ch].intmaxarg = va_arg (ap, size_t); 482153486Sphk break; 483153486Sphk case PA_INT | PA_FLAG_PTRDIFF: 484153486Sphk args[ch].intmaxarg = va_arg (ap, ptrdiff_t); 485153486Sphk break; 486153486Sphk case PA_WCHAR: 487153486Sphk args[ch].wintarg = va_arg (ap, wint_t); 488153486Sphk break; 489153486Sphk case PA_POINTER: 490153486Sphk args[ch].pvoidarg = va_arg (ap, void *); 491153486Sphk break; 492153486Sphk case PA_STRING: 493153486Sphk args[ch].pchararg = va_arg (ap, char *); 494153486Sphk break; 495153486Sphk case PA_WSTRING: 496153486Sphk args[ch].pwchararg = va_arg (ap, wchar_t *); 497153486Sphk break; 498153486Sphk case PA_DOUBLE: 499157381Sphk#ifndef NO_FLOATING_POINT 500153486Sphk args[ch].doublearg = va_arg (ap, double); 501157381Sphk#endif 502153486Sphk break; 503153486Sphk case PA_DOUBLE | PA_FLAG_LONG_DOUBLE: 504157381Sphk#ifndef NO_FLOATING_POINT 505153486Sphk args[ch].longdoublearg = va_arg (ap, long double); 506157381Sphk#endif 507153486Sphk break; 508153486Sphk default: 509153486Sphk errx(1, "argtype = %x (fmt = \"%s\")\n", 510153486Sphk argt[ch], fmt0); 511153486Sphk } 512153486Sphk } 513153486Sphk for (pi = pia; pi < pil; pi++) { 514153486Sphk#if 0 515153486Sphk fprintf(stderr, "pi %p", pi); 516153486Sphk fprintf(stderr, " spec '%c'", pi->spec); 517153486Sphk fprintf(stderr, " args %d", 518153486Sphk ((uintptr_t)pi->arg[0] - (uintptr_t)args) / sizeof args[0]); 519153486Sphk if (pi->width) fprintf(stderr, " width %d", pi->width); 520153486Sphk if (pi->pad) fprintf(stderr, " pad 0x%x", pi->pad); 521153486Sphk if (pi->left) fprintf(stderr, " left"); 522153486Sphk if (pi->showsign) fprintf(stderr, " showsign"); 523153486Sphk if (pi->prec != -1) fprintf(stderr, " prec %d", pi->prec); 524153486Sphk if (pi->is_char) fprintf(stderr, " char"); 525153486Sphk if (pi->is_short) fprintf(stderr, " short"); 526153486Sphk if (pi->is_long) fprintf(stderr, " long"); 527153486Sphk if (pi->is_long_double) fprintf(stderr, " long_double"); 528153486Sphk fprintf(stderr, "\n"); 529153486Sphk fprintf(stderr, "\t\"%.*s\"\n", pi->end - pi->begin, pi->begin); 530153486Sphk#endif 531153486Sphk if (pi->get_width) { 532153486Sphk pi->width = args[pi->get_width].intarg; 533153486Sphk /*- 534153486Sphk * ``A negative field width argument is taken as a 535153486Sphk * - flag followed by a positive field width.'' 536153486Sphk * -- ANSI X3J11 537153486Sphk * They don't exclude field widths read from args. 538153486Sphk */ 539153486Sphk if (pi->width < 0) { 540153486Sphk pi->left = 1; 541153486Sphk pi->width = -pi->width; 542153486Sphk } 543153486Sphk } 544153486Sphk if (pi->get_prec) 545153486Sphk pi->prec = args[pi->get_prec].intarg; 546153486Sphk ret += __printf_puts(&io, pi->begin, pi->end - pi->begin); 547153486Sphk if (printf_tbl[pi->spec].gnurender != NULL) { 548153486Sphk __printf_flush(&io); 549153486Sphk pi->sofar = ret; 550153486Sphk ret += printf_tbl[pi->spec].gnurender( 551153486Sphk fp, pi, (const void *)pi->arg); 552153486Sphk } else if (printf_tbl[pi->spec].render != NULL) { 553153486Sphk pi->sofar = ret; 554153486Sphk n = printf_tbl[pi->spec].render( 555153486Sphk &io, pi, (const void *)pi->arg); 556153486Sphk if (n < 0) 557153486Sphk io.fp->_flags |= __SERR; 558153486Sphk else 559153486Sphk ret += n; 560153486Sphk } else if (pi->begin == pi->end) 561153486Sphk errx(1, "render[%c] = NULL", *fmt); 562153486Sphk } 563153486Sphk __printf_flush(&io); 564153486Sphk return (ret); 565153486Sphk} 566153486Sphk 567153486Sphkextern int __fflush(FILE *fp); 568153486Sphk 569153486Sphk/* 570153486Sphk * Helper function for `fprintf to unbuffered unix file': creates a 571153486Sphk * temporary buffer. We only work on write-only files; this avoids 572153486Sphk * worries about ungetc buffers and so forth. 573153486Sphk */ 574153486Sphkstatic int 575153486Sphk__v3printf(FILE *fp, const char *fmt, int pct, va_list ap) 576153486Sphk{ 577153486Sphk int ret; 578153486Sphk FILE fake; 579153486Sphk unsigned char buf[BUFSIZ]; 580153486Sphk 581153486Sphk /* copy the important variables */ 582153486Sphk fake._flags = fp->_flags & ~__SNBF; 583153486Sphk fake._file = fp->_file; 584153486Sphk fake._cookie = fp->_cookie; 585153486Sphk fake._write = fp->_write; 586178287Sjhb fake._orientation = fp->_orientation; 587178287Sjhb fake._mbstate = fp->_mbstate; 588153486Sphk 589153486Sphk /* set up the buffer */ 590153486Sphk fake._bf._base = fake._p = buf; 591153486Sphk fake._bf._size = fake._w = sizeof(buf); 592153486Sphk fake._lbfsize = 0; /* not actually used, but Just In Case */ 593153486Sphk 594153486Sphk /* do the work, then copy any error status */ 595153486Sphk ret = __v2printf(&fake, fmt, pct, ap); 596153486Sphk if (ret >= 0 && __fflush(&fake)) 597153486Sphk ret = EOF; 598153486Sphk if (fake._flags & __SERR) 599153486Sphk fp->_flags |= __SERR; 600153486Sphk return (ret); 601153486Sphk} 602153486Sphk 603153486Sphkint 604153486Sphk__xvprintf(FILE *fp, const char *fmt0, va_list ap) 605153486Sphk{ 606153486Sphk unsigned u; 607153486Sphk const char *p; 608153486Sphk 609153486Sphk /* Count number of '%' signs handling double '%' signs */ 610153486Sphk for (p = fmt0, u = 0; *p; p++) { 611153486Sphk if (*p != '%') 612153486Sphk continue; 613153486Sphk u++; 614153486Sphk if (p[1] == '%') 615153486Sphk p++; 616153486Sphk } 617153486Sphk 618153486Sphk /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 619153486Sphk if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 620153486Sphk fp->_file >= 0) 621153486Sphk return (__v3printf(fp, fmt0, u, ap)); 622153486Sphk else 623153486Sphk return (__v2printf(fp, fmt0, u, ap)); 624153486Sphk} 625153486Sphk 626153486Sphk/* extending ---------------------------------------------------------*/ 627153486Sphk 628153486Sphkint 629153486Sphkregister_printf_function(int spec, printf_function *render, printf_arginfo_function *arginfo) 630153486Sphk{ 631153486Sphk 632153486Sphk if (spec > 255 || spec < 0) 633153486Sphk return (-1); 634153486Sphk printf_tbl[spec].gnurender = render; 635153486Sphk printf_tbl[spec].arginfo = arginfo; 636153486Sphk __use_xprintf = 1; 637153486Sphk return (0); 638153486Sphk} 639153486Sphk 640153486Sphkint 641153486Sphkregister_printf_render(int spec, printf_render *render, printf_arginfo_function *arginfo) 642153486Sphk{ 643153486Sphk 644153486Sphk if (spec > 255 || spec < 0) 645153486Sphk return (-1); 646153486Sphk printf_tbl[spec].render = render; 647153486Sphk printf_tbl[spec].arginfo = arginfo; 648153486Sphk __use_xprintf = 1; 649153486Sphk return (0); 650153486Sphk} 651153486Sphk 652153486Sphkint 653153486Sphkregister_printf_render_std(const unsigned char *specs) 654153486Sphk{ 655153486Sphk 656153486Sphk for (; *specs != '\0'; specs++) { 657153486Sphk switch (*specs) { 658153486Sphk case 'H': 659153486Sphk register_printf_render(*specs, 660153486Sphk __printf_render_hexdump, 661153486Sphk __printf_arginfo_hexdump); 662153486Sphk break; 663154815Sphk case 'M': 664154815Sphk register_printf_render(*specs, 665154815Sphk __printf_render_errno, 666154815Sphk __printf_arginfo_errno); 667154815Sphk break; 668154815Sphk case 'Q': 669154815Sphk register_printf_render(*specs, 670154815Sphk __printf_render_quote, 671154815Sphk __printf_arginfo_quote); 672154815Sphk break; 673153486Sphk case 'T': 674153486Sphk register_printf_render(*specs, 675153486Sphk __printf_render_time, 676153486Sphk __printf_arginfo_time); 677153486Sphk break; 678153486Sphk case 'V': 679153486Sphk register_printf_render(*specs, 680153486Sphk __printf_render_vis, 681153486Sphk __printf_arginfo_vis); 682153486Sphk break; 683153486Sphk default: 684153486Sphk return (-1); 685153486Sphk } 686153486Sphk } 687153486Sphk return (0); 688153486Sphk} 689153486Sphk 690