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>
48 #include "un-namespace.h"
51 #include "priv_stdio.h"
53 int __use_xprintf
= -1;
55 /* private stuff -----------------------------------------------------*/
61 #ifndef NO_FLOATING_POINT
63 long double longdoublearg
;
72 * Macros for converting digits to letters and vice versa
74 #define to_digit(c) ((c) - '0')
75 #define is_digit(c) (((unsigned)to_digit(c)) <= 9)
77 /* various globals ---------------------------------------------------*/
79 const char __lowercase_hex
[17] = "0123456789abcdef?"; /*lint !e784 */
80 const char __uppercase_hex
[17] = "0123456789ABCDEF?"; /*lint !e784 */
83 static char blanks
[PADSIZE
] =
84 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
85 static char zeroes
[PADSIZE
] =
86 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
88 /* printing and padding functions ------------------------------------*/
95 struct __siov iov
[NIOV
];
100 __printf_init(struct __printf_io
*io
)
103 io
->uio
.uio_iov
= io
->iovp
= &io
->iov
[0];
104 io
->uio
.uio_resid
= 0;
105 io
->uio
.uio_iovcnt
= 0;
109 __printf_flush(struct __printf_io
*io
)
112 __sfvwrite(io
->fp
, &io
->uio
);
117 __printf_puts(struct __printf_io
*io
, const void *ptr
, int len
)
120 if (io
->fp
->pub
._flags
& __SERR
)
124 io
->iovp
->iov_base
= __DECONST(void *, ptr
);
125 io
->iovp
->iov_len
= len
;
126 io
->uio
.uio_resid
+= len
;
128 io
->uio
.uio_iovcnt
++;
129 if (io
->uio
.uio_iovcnt
>= NIOV
)
135 __printf_pad(struct __printf_io
*io
, int howmany
, int zero
)
146 if ((n
= (howmany
)) > 0) {
147 while (n
> PADSIZE
) {
148 ret
+= __printf_puts(io
, with
, PADSIZE
);
151 ret
+= __printf_puts(io
, with
, n
);
157 __printf_out(struct __printf_io
*io
, const struct printf_info
*pi
,
158 const void *ptr
, int len
)
162 if ((!pi
->left
) && pi
->width
> len
)
163 ret
+= __printf_pad(io
, pi
->width
- len
, pi
->pad
== '0');
164 ret
+= __printf_puts(io
, ptr
, len
);
165 if (pi
->left
&& pi
->width
> len
)
166 ret
+= __printf_pad(io
, pi
->width
- len
, pi
->pad
== '0');
171 /* percent handling -------------------------------------------------*/
174 __printf_arginfo_pct(const struct printf_info
*pi __unused
, size_t n __unused
,
182 __printf_render_pct(struct __printf_io
*io
,
183 const struct printf_info
*pi __unused
,
184 const void *const *arg __unused
)
187 return (__printf_puts(io
, "%", 1));
190 /* 'n' ---------------------------------------------------------------*/
193 __printf_arginfo_n(const struct printf_info
*pi __unused
, size_t n
, int *argt
)
197 argt
[0] = PA_POINTER
;
202 * This is a printf_render so that all output has been flushed before it
207 __printf_render_n(FILE *io __unused
, const struct printf_info
*pi
,
208 const void *const *arg
)
212 **((signed char **)arg
[0]) = (signed char)pi
->sofar
;
213 else if (pi
->is_short
)
214 **((short **)arg
[0]) = (short)pi
->sofar
;
215 else if (pi
->is_long
)
216 **((long **)arg
[0]) = pi
->sofar
;
217 else if (pi
->is_long_double
)
218 **((long long **)arg
[0]) = pi
->sofar
;
219 else if (pi
->is_intmax
)
220 **((intmax_t **)arg
[0]) = pi
->sofar
;
221 else if (pi
->is_ptrdiff
)
222 **((ptrdiff_t **)arg
[0]) = pi
->sofar
;
223 else if (pi
->is_quad
)
224 **((quad_t
**)arg
[0]) = pi
->sofar
;
225 else if (pi
->is_size
)
226 **((size_t **)arg
[0]) = pi
->sofar
;
228 **((int **)arg
[0]) = pi
->sofar
;
233 /* table -------------------------------------------------------------*/
235 /*lint -esym(785, printf_tbl) */
237 printf_arginfo_function
*arginfo
;
238 printf_function
*gnurender
;
239 printf_render
*render
;
240 } printf_tbl
[256] = {
241 ['%'] = { __printf_arginfo_pct
, NULL
, __printf_render_pct
},
242 ['A'] = { __printf_arginfo_float
, NULL
, __printf_render_float
},
243 ['C'] = { __printf_arginfo_chr
, NULL
, __printf_render_chr
},
244 ['E'] = { __printf_arginfo_float
, NULL
, __printf_render_float
},
245 ['F'] = { __printf_arginfo_float
, NULL
, __printf_render_float
},
246 ['G'] = { __printf_arginfo_float
, NULL
, __printf_render_float
},
247 ['S'] = { __printf_arginfo_str
, NULL
, __printf_render_str
},
248 ['X'] = { __printf_arginfo_int
, NULL
, __printf_render_int
},
249 ['a'] = { __printf_arginfo_float
, NULL
, __printf_render_float
},
250 ['c'] = { __printf_arginfo_chr
, NULL
, __printf_render_chr
},
251 ['d'] = { __printf_arginfo_int
, NULL
, __printf_render_int
},
252 ['e'] = { __printf_arginfo_float
, NULL
, __printf_render_float
},
253 ['f'] = { __printf_arginfo_float
, NULL
, __printf_render_float
},
254 ['g'] = { __printf_arginfo_float
, NULL
, __printf_render_float
},
255 ['i'] = { __printf_arginfo_int
, NULL
, __printf_render_int
},
256 ['n'] = { __printf_arginfo_n
, __printf_render_n
, NULL
},
257 ['o'] = { __printf_arginfo_int
, NULL
, __printf_render_int
},
258 ['p'] = { __printf_arginfo_ptr
, NULL
, __printf_render_ptr
},
259 ['q'] = { __printf_arginfo_int
, NULL
, __printf_render_int
},
260 ['s'] = { __printf_arginfo_str
, NULL
, __printf_render_str
},
261 ['u'] = { __printf_arginfo_int
, NULL
, __printf_render_int
},
262 ['x'] = { __printf_arginfo_int
, NULL
, __printf_render_int
},
267 __v2printf(FILE *fp
, const char *fmt0
, unsigned pct
, va_list ap
)
269 struct printf_info
*pi
, *pil
;
272 struct printf_info pia
[pct
+ 10];
274 union arg args
[pct
+ 10];
279 struct __printf_io io
;
287 memset(argt
, 0, sizeof argt
);
288 for (pi
= pia
; ; pi
++) {
289 memset(pi
, 0, sizeof *pi
);
296 pi
->begin
= pi
->end
= fmt
;
297 while (*fmt
!= '\0' && *fmt
!= '%')
307 * ``If the space and + flags both appear, the space
308 * flag will be ignored.''
311 if (pi
->showsign
== 0)
324 pi
->get_prec
= nextarg
;
325 argt
[nextarg
++] = PA_INT
;
328 while (*fmt
!= '\0' && is_digit(*fmt
)) {
330 pi
->prec
+= to_digit(*fmt
);
344 pi
->get_width
= nextarg
;
345 argt
[nextarg
++] = PA_INT
;
356 * ``Note that 0 is taken as a flag, not as the
357 * beginning of a field width.''
363 case '1': case '2': case '3':
364 case '4': case '5': case '6':
365 case '7': case '8': case '9':
367 while (*fmt
!= '\0' && is_digit(*fmt
)) {
373 if (nextarg
> maxarg
)
384 pi
->spec
+= ('a' - 'A');
386 if (pi
->is_long_double
|| pi
->is_quad
) {
388 pi
->is_long_double
= 1;
391 pi
->is_long_double
= 0;
405 pi
->is_long_double
= 1;
421 pi
->is_long_double
= 1;
440 if (printf_tbl
[pi
->spec
].arginfo
== NULL
)
441 errx(1, "arginfo[%c] = NULL", pi
->spec
);
442 ch
= printf_tbl
[pi
->spec
].arginfo(
443 pi
, __PRINTFMAXARG
, &argt
[nextarg
]);
445 pi
->arg
[0] = &args
[nextarg
];
447 pi
->arg
[1] = &args
[nextarg
+ 1];
452 if (nextarg
> maxarg
)
455 fprintf(stderr
, "fmt0 <%s>\n", fmt0
);
456 fprintf(stderr
, "pil %p\n", pil
);
458 for (ch
= 1; ch
< maxarg
; ch
++) {
460 fprintf(stderr
, "arg %d %x\n", ch
, argt
[ch
]);
464 args
[ch
].intarg
= (char)va_arg(ap
, int);
467 args
[ch
].intarg
= va_arg(ap
, int);
469 case PA_INT
| PA_FLAG_SHORT
:
470 args
[ch
].intarg
= (short)va_arg(ap
, int);
472 case PA_INT
| PA_FLAG_LONG
:
473 args
[ch
].longarg
= va_arg(ap
, long);
475 case PA_INT
| PA_FLAG_INTMAX
:
476 args
[ch
].intmaxarg
= va_arg(ap
, intmax_t);
478 case PA_INT
| PA_FLAG_QUAD
:
479 args
[ch
].intmaxarg
= va_arg(ap
, quad_t
);
481 case PA_INT
| PA_FLAG_LONG_LONG
:
482 args
[ch
].intmaxarg
= va_arg(ap
, long long);
484 case PA_INT
| PA_FLAG_SIZE
:
485 args
[ch
].intmaxarg
= va_arg(ap
, size_t);
487 case PA_INT
| PA_FLAG_PTRDIFF
:
488 args
[ch
].intmaxarg
= va_arg(ap
, ptrdiff_t);
491 args
[ch
].wintarg
= va_arg(ap
, wint_t);
494 args
[ch
].pvoidarg
= va_arg(ap
, void *);
497 args
[ch
].pchararg
= va_arg(ap
, char *);
500 args
[ch
].pwchararg
= va_arg(ap
, wchar_t *);
503 #ifndef NO_FLOATING_POINT
504 args
[ch
].doublearg
= va_arg(ap
, double);
507 case PA_DOUBLE
| PA_FLAG_LONG_DOUBLE
:
508 #ifndef NO_FLOATING_POINT
509 args
[ch
].longdoublearg
= va_arg(ap
, long double);
513 errx(1, "argtype = %x (fmt = \"%s\")\n",
517 for (pi
= pia
; pi
< pil
; pi
++) {
519 fprintf(stderr
, "pi %p", pi
);
520 fprintf(stderr
, " spec '%c'", pi
->spec
);
521 fprintf(stderr
, " args %d",
522 ((uintptr_t)pi
->arg
[0] - (uintptr_t)args
) / sizeof args
[0]);
523 if (pi
->width
) fprintf(stderr
, " width %d", pi
->width
);
524 if (pi
->pad
) fprintf(stderr
, " pad 0x%x", pi
->pad
);
525 if (pi
->left
) fprintf(stderr
, " left");
526 if (pi
->showsign
) fprintf(stderr
, " showsign");
527 if (pi
->prec
!= -1) fprintf(stderr
, " prec %d", pi
->prec
);
528 if (pi
->is_char
) fprintf(stderr
, " char");
529 if (pi
->is_short
) fprintf(stderr
, " short");
530 if (pi
->is_long
) fprintf(stderr
, " long");
531 if (pi
->is_long_double
) fprintf(stderr
, " long_double");
532 fprintf(stderr
, "\n");
533 fprintf(stderr
, "\t\"%.*s\"\n", pi
->end
- pi
->begin
, pi
->begin
);
536 pi
->width
= args
[pi
->get_width
].intarg
;
538 * ``A negative field width argument is taken as a
539 * - flag followed by a positive field width.''
541 * They don't exclude field widths read from args.
545 pi
->width
= -pi
->width
;
549 pi
->prec
= args
[pi
->get_prec
].intarg
;
550 ret
+= __printf_puts(&io
, pi
->begin
, pi
->end
- pi
->begin
);
551 if (printf_tbl
[pi
->spec
].gnurender
!= NULL
) {
554 ret
+= printf_tbl
[pi
->spec
].gnurender(
555 fp
, pi
, (const void *)pi
->arg
);
556 } else if (printf_tbl
[pi
->spec
].render
!= NULL
) {
558 n
= printf_tbl
[pi
->spec
].render(
559 &io
, pi
, (const void *)pi
->arg
);
561 io
.fp
->pub
._flags
|= __SERR
;
564 } else if (pi
->begin
== pi
->end
)
565 errx(1, "render[%c] = NULL", *fmt
);
571 extern int __fflush(FILE *fp
);
574 * Helper function for `fprintf to unbuffered unix file': creates a
575 * temporary buffer. We only work on write-only files; this avoids
576 * worries about ungetc buffers and so forth.
579 __v3printf(FILE *fp
, const char *fmt
, int pct
, va_list ap
)
583 unsigned char buf
[BUFSIZ
];
585 /* copy the important variables */
586 fake
.pub
._flags
= fp
->pub
._flags
& ~__SNBF
;
587 fake
.pub
._fileno
= fp
->pub
._fileno
;
588 fake
._cookie
= fp
->_cookie
;
589 fake
._write
= fp
->_write
;
590 memcpy(WCIO_GET(&fake
), WCIO_GET(fp
), sizeof(struct wchar_io_data
));
592 /* set up the buffer */
593 fake
._bf
._base
= fake
.pub
._p
= buf
;
594 fake
._bf
._size
= fake
.pub
._w
= sizeof(buf
);
595 fake
.pub
._lbfsize
= 0; /* not actually used, but Just In Case */
597 /* do the work, then copy any error status */
598 ret
= __v2printf(&fake
, fmt
, pct
, ap
);
599 if (ret
>= 0 && __fflush(&fake
))
601 if (fake
.pub
._flags
& __SERR
)
602 fp
->pub
._flags
|= __SERR
;
607 __xvprintf(FILE *fp
, const char *fmt0
, va_list ap
)
612 /* Count number of '%' signs handling double '%' signs */
613 for (p
= fmt0
, u
= 0; *p
; p
++) {
621 /* optimise fprintf(stderr) (and other unbuffered Unix files) */
622 if ((fp
->pub
._flags
& (__SNBF
|__SWR
|__SRW
)) == (__SNBF
|__SWR
) &&
623 fp
->pub
._fileno
>= 0)
624 return (__v3printf(fp
, fmt0
, u
, ap
));
626 return (__v2printf(fp
, fmt0
, u
, ap
));
629 /* extending ---------------------------------------------------------*/
632 register_printf_function(int spec
, printf_function
*render
,
633 printf_arginfo_function
*arginfo
)
636 if (spec
> 255 || spec
< 0)
638 printf_tbl
[spec
].gnurender
= render
;
639 printf_tbl
[spec
].arginfo
= arginfo
;
645 register_printf_render(int spec
, printf_render
*render
,
646 printf_arginfo_function
*arginfo
)
649 if (spec
> 255 || spec
< 0)
651 printf_tbl
[spec
].render
= render
;
652 printf_tbl
[spec
].arginfo
= arginfo
;
658 register_printf_render_std(const unsigned char *specs
)
661 for (; *specs
!= '\0'; specs
++) {
664 register_printf_render(*specs
,
665 __printf_render_hexdump
,
666 __printf_arginfo_hexdump
);
669 register_printf_render(*specs
,
670 __printf_render_errno
,
671 __printf_arginfo_errno
);
674 register_printf_render(*specs
,
675 __printf_render_quote
,
676 __printf_arginfo_quote
);
679 register_printf_render(*specs
,
680 __printf_render_time
,
681 __printf_arginfo_time
);
684 register_printf_render(*specs
,
686 __printf_arginfo_vis
);