2 * Copyright (c) 2005 Poul-Henning Kamp
3 * Copyright (c) 1990, 1993
4 * The Regents of the University of California. All rights reserved.
6 * This code is derived from software contributed to Berkeley by
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
33 * $FreeBSD: src/lib/libc/stdio/xprintf.c,v 1.8 2008/05/05 16:03:52 jhb Exp $
36 #include "namespace.h"
38 #include <sys/types.h>
46 #include <namespace.h>
49 #include "un-namespace.h"
52 #include "priv_stdio.h"
54 int __use_xprintf = -1;
56 /* private stuff -----------------------------------------------------*/
62 #ifndef NO_FLOATING_POINT
64 long double longdoublearg;
73 * Macros for converting digits to letters and vice versa
75 #define to_digit(c) ((c) - '0')
76 #define is_digit(c) (((unsigned)to_digit(c)) <= 9)
78 /* various globals ---------------------------------------------------*/
80 const char __lowercase_hex[17] = "0123456789abcdef?"; /*lint !e784 */
81 const char __uppercase_hex[17] = "0123456789ABCDEF?"; /*lint !e784 */
84 static char blanks[PADSIZE] =
85 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
86 static char zeroes[PADSIZE] =
87 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
89 /* printing and padding functions ------------------------------------*/
96 struct __siov iov[NIOV];
101 __printf_init(struct __printf_io *io)
104 io->uio.uio_iov = io->iovp = &io->iov[0];
105 io->uio.uio_resid = 0;
106 io->uio.uio_iovcnt = 0;
110 __printf_flush(struct __printf_io *io)
113 __sfvwrite(io->fp, &io->uio);
118 __printf_puts(struct __printf_io *io, const void *ptr, int len)
121 if (io->fp->pub._flags & __SERR)
125 io->iovp->iov_base = __DECONST(void *, ptr);
126 io->iovp->iov_len = len;
127 io->uio.uio_resid += len;
129 io->uio.uio_iovcnt++;
130 if (io->uio.uio_iovcnt >= NIOV)
136 __printf_pad(struct __printf_io *io, int howmany, int zero)
147 if ((n = (howmany)) > 0) {
148 while (n > PADSIZE) {
149 ret += __printf_puts(io, with, PADSIZE);
152 ret += __printf_puts(io, with, n);
158 __printf_out(struct __printf_io *io, const struct printf_info *pi,
159 const void *ptr, int len)
163 if ((!pi->left) && pi->width > len)
164 ret += __printf_pad(io, pi->width - len, pi->pad == '0');
165 ret += __printf_puts(io, ptr, len);
166 if (pi->left && pi->width > len)
167 ret += __printf_pad(io, pi->width - len, pi->pad == '0');
172 /* percent handling -------------------------------------------------*/
175 __printf_arginfo_pct(const struct printf_info *pi __unused, size_t n __unused,
183 __printf_render_pct(struct __printf_io *io,
184 const struct printf_info *pi __unused,
185 const void *const *arg __unused)
188 return (__printf_puts(io, "%", 1));
191 /* 'n' ---------------------------------------------------------------*/
194 __printf_arginfo_n(const struct printf_info *pi, size_t n, int *argt)
198 argt[0] = PA_POINTER;
203 * This is a printf_render so that all output has been flushed before it
208 __printf_render_n(FILE *io __unused, const struct printf_info *pi,
209 const void *const *arg)
213 **((signed char **)arg[0]) = (signed char)pi->sofar;
214 else if (pi->is_short)
215 **((short **)arg[0]) = (short)pi->sofar;
216 else if (pi->is_long)
217 **((long **)arg[0]) = pi->sofar;
218 else if (pi->is_long_double)
219 **((long long **)arg[0]) = pi->sofar;
220 else if (pi->is_intmax)
221 **((intmax_t **)arg[0]) = pi->sofar;
222 else if (pi->is_ptrdiff)
223 **((ptrdiff_t **)arg[0]) = pi->sofar;
224 else if (pi->is_quad)
225 **((quad_t **)arg[0]) = pi->sofar;
226 else if (pi->is_size)
227 **((size_t **)arg[0]) = pi->sofar;
229 **((int **)arg[0]) = pi->sofar;
234 /* table -------------------------------------------------------------*/
236 /*lint -esym(785, printf_tbl) */
238 printf_arginfo_function *arginfo;
239 printf_function *gnurender;
240 printf_render *render;
241 } printf_tbl[256] = {
242 ['%'] = { __printf_arginfo_pct, NULL, __printf_render_pct },
243 ['A'] = { __printf_arginfo_float, NULL, __printf_render_float },
244 ['C'] = { __printf_arginfo_chr, NULL, __printf_render_chr },
245 ['E'] = { __printf_arginfo_float, NULL, __printf_render_float },
246 ['F'] = { __printf_arginfo_float, NULL, __printf_render_float },
247 ['G'] = { __printf_arginfo_float, NULL, __printf_render_float },
248 ['S'] = { __printf_arginfo_str, NULL, __printf_render_str },
249 ['X'] = { __printf_arginfo_int, NULL, __printf_render_int },
250 ['a'] = { __printf_arginfo_float, NULL, __printf_render_float },
251 ['c'] = { __printf_arginfo_chr, NULL, __printf_render_chr },
252 ['d'] = { __printf_arginfo_int, NULL, __printf_render_int },
253 ['e'] = { __printf_arginfo_float, NULL, __printf_render_float },
254 ['f'] = { __printf_arginfo_float, NULL, __printf_render_float },
255 ['g'] = { __printf_arginfo_float, NULL, __printf_render_float },
256 ['i'] = { __printf_arginfo_int, NULL, __printf_render_int },
257 ['n'] = { __printf_arginfo_n, __printf_render_n, NULL },
258 ['o'] = { __printf_arginfo_int, NULL, __printf_render_int },
259 ['p'] = { __printf_arginfo_ptr, NULL, __printf_render_ptr },
260 ['q'] = { __printf_arginfo_int, NULL, __printf_render_int },
261 ['s'] = { __printf_arginfo_str, NULL, __printf_render_str },
262 ['u'] = { __printf_arginfo_int, NULL, __printf_render_int },
263 ['x'] = { __printf_arginfo_int, NULL, __printf_render_int },
268 __v2printf(FILE *fp, const char *fmt0, unsigned pct, va_list ap)
270 struct printf_info *pi, *pil;
273 struct printf_info pia[pct + 10];
275 union arg args[pct + 10];
280 struct __printf_io io;
288 memset(argt, 0, sizeof argt);
289 for (pi = pia; ; pi++) {
290 memset(pi, 0, sizeof *pi);
297 pi->begin = pi->end = fmt;
298 while (*fmt != '\0' && *fmt != '%')
308 * ``If the space and + flags both appear, the space
309 * flag will be ignored.''
312 if (pi->showsign == 0)
325 pi->get_prec = nextarg;
326 argt[nextarg++] = PA_INT;
329 while (*fmt != '\0' && is_digit(*fmt)) {
331 pi->prec += to_digit(*fmt);
345 pi->get_width = nextarg;
346 argt[nextarg++] = PA_INT;
357 * ``Note that 0 is taken as a flag, not as the
358 * beginning of a field width.''
364 case '1': case '2': case '3':
365 case '4': case '5': case '6':
366 case '7': case '8': case '9':
368 while (*fmt != '\0' && is_digit(*fmt)) {
374 if (nextarg > maxarg)
385 pi->spec += ('a' - 'A');
387 if (pi->is_long_double || pi->is_quad) {
389 pi->is_long_double = 1;
392 pi->is_long_double = 0;
406 pi->is_long_double = 1;
422 pi->is_long_double = 1;
441 if (printf_tbl[pi->spec].arginfo == NULL)
442 errx(1, "arginfo[%c] = NULL", pi->spec);
443 ch = printf_tbl[pi->spec].arginfo(
444 pi, __PRINTFMAXARG, &argt[nextarg]);
446 pi->arg[0] = &args[nextarg];
448 pi->arg[1] = &args[nextarg + 1];
453 if (nextarg > maxarg)
456 fprintf(stderr, "fmt0 <%s>\n", fmt0);
457 fprintf(stderr, "pil %p\n", pil);
459 for (ch = 1; ch < maxarg; ch++) {
461 fprintf(stderr, "arg %d %x\n", ch, argt[ch]);
465 args[ch].intarg = (char)va_arg(ap, int);
468 args[ch].intarg = va_arg(ap, int);
470 case PA_INT | PA_FLAG_SHORT:
471 args[ch].intarg = (short)va_arg(ap, int);
473 case PA_INT | PA_FLAG_LONG:
474 args[ch].longarg = va_arg(ap, long);
476 case PA_INT | PA_FLAG_INTMAX:
477 args[ch].intmaxarg = va_arg(ap, intmax_t);
479 case PA_INT | PA_FLAG_QUAD:
480 args[ch].intmaxarg = va_arg(ap, quad_t);
482 case PA_INT | PA_FLAG_LONG_LONG:
483 args[ch].intmaxarg = va_arg(ap, long long);
485 case PA_INT | PA_FLAG_SIZE:
486 args[ch].intmaxarg = va_arg(ap, size_t);
488 case PA_INT | PA_FLAG_PTRDIFF:
489 args[ch].intmaxarg = va_arg(ap, ptrdiff_t);
492 args[ch].wintarg = va_arg(ap, wint_t);
495 args[ch].pvoidarg = va_arg(ap, void *);
498 args[ch].pchararg = va_arg(ap, char *);
501 args[ch].pwchararg = va_arg(ap, wchar_t *);
504 #ifndef NO_FLOATING_POINT
505 args[ch].doublearg = va_arg(ap, double);
508 case PA_DOUBLE | PA_FLAG_LONG_DOUBLE:
509 #ifndef NO_FLOATING_POINT
510 args[ch].longdoublearg = va_arg(ap, long double);
514 errx(1, "argtype = %x (fmt = \"%s\")\n",
518 for (pi = pia; pi < pil; pi++) {
520 fprintf(stderr, "pi %p", pi);
521 fprintf(stderr, " spec '%c'", pi->spec);
522 fprintf(stderr, " args %d",
523 ((uintptr_t)pi->arg[0] - (uintptr_t)args) / sizeof args[0]);
524 if (pi->width) fprintf(stderr, " width %d", pi->width);
525 if (pi->pad) fprintf(stderr, " pad 0x%x", pi->pad);
526 if (pi->left) fprintf(stderr, " left");
527 if (pi->showsign) fprintf(stderr, " showsign");
528 if (pi->prec != -1) fprintf(stderr, " prec %d", pi->prec);
529 if (pi->is_char) fprintf(stderr, " char");
530 if (pi->is_short) fprintf(stderr, " short");
531 if (pi->is_long) fprintf(stderr, " long");
532 if (pi->is_long_double) fprintf(stderr, " long_double");
533 fprintf(stderr, "\n");
534 fprintf(stderr, "\t\"%.*s\"\n", pi->end - pi->begin, pi->begin);
537 pi->width = args[pi->get_width].intarg;
539 * ``A negative field width argument is taken as a
540 * - flag followed by a positive field width.''
542 * They don't exclude field widths read from args.
546 pi->width = -pi->width;
550 pi->prec = args[pi->get_prec].intarg;
551 ret += __printf_puts(&io, pi->begin, pi->end - pi->begin);
552 if (printf_tbl[pi->spec].gnurender != NULL) {
555 ret += printf_tbl[pi->spec].gnurender(
556 fp, pi, (const void *)pi->arg);
557 } else if (printf_tbl[pi->spec].render != NULL) {
559 n = printf_tbl[pi->spec].render(
560 &io, pi, (const void *)pi->arg);
562 io.fp->pub._flags |= __SERR;
565 } else if (pi->begin == pi->end)
566 errx(1, "render[%c] = NULL", *fmt);
572 extern int __fflush(FILE *fp);
575 * Helper function for `fprintf to unbuffered unix file': creates a
576 * temporary buffer. We only work on write-only files; this avoids
577 * worries about ungetc buffers and so forth.
580 __v3printf(FILE *fp, const char *fmt, int pct, va_list ap)
584 unsigned char buf[BUFSIZ];
586 /* copy the important variables */
587 fake.pub._flags = fp->pub._flags & ~__SNBF;
588 fake.pub._fileno = fp->pub._fileno;
589 fake._cookie = fp->_cookie;
590 fake._write = fp->_write;
591 memcpy(WCIO_GET(&fake), WCIO_GET(fp), sizeof(struct wchar_io_data));
593 /* set up the buffer */
594 fake._bf._base = fake.pub._p = buf;
595 fake._bf._size = fake.pub._w = sizeof(buf);
596 fake.pub._lbfsize = 0; /* not actually used, but Just In Case */
598 /* do the work, then copy any error status */
599 ret = __v2printf(&fake, fmt, pct, ap);
600 if (ret >= 0 && __fflush(&fake))
602 if (fake.pub._flags & __SERR)
603 fp->pub._flags |= __SERR;
608 __xvprintf(FILE *fp, const char *fmt0, va_list ap)
613 /* Count number of '%' signs handling double '%' signs */
614 for (p = fmt0, u = 0; *p; p++) {
622 /* optimise fprintf(stderr) (and other unbuffered Unix files) */
623 if ((fp->pub._flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
624 fp->pub._fileno >= 0)
625 return (__v3printf(fp, fmt0, u, ap));
627 return (__v2printf(fp, fmt0, u, ap));
630 /* extending ---------------------------------------------------------*/
633 register_printf_function(int spec, printf_function *render,
634 printf_arginfo_function *arginfo)
637 if (spec > 255 || spec < 0)
639 printf_tbl[spec].gnurender = render;
640 printf_tbl[spec].arginfo = arginfo;
646 register_printf_render(int spec, printf_render *render,
647 printf_arginfo_function *arginfo)
650 if (spec > 255 || spec < 0)
652 printf_tbl[spec].render = render;
653 printf_tbl[spec].arginfo = arginfo;
659 register_printf_render_std(const unsigned char *specs)
662 for (; *specs != '\0'; specs++) {
665 register_printf_render(*specs,
666 __printf_render_hexdump,
667 __printf_arginfo_hexdump);
670 register_printf_render(*specs,
671 __printf_render_errno,
672 __printf_arginfo_errno);
675 register_printf_render(*specs,
676 __printf_render_quote,
677 __printf_arginfo_quote);
680 register_printf_render(*specs,
681 __printf_render_time,
682 __printf_arginfo_time);
685 register_printf_render(*specs,
687 __printf_arginfo_vis);