Deleted Added
full compact
xprintf.c (178287) xprintf.c (178721)
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 *
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: head/lib/libc/stdio/xprintf.c 178287 2008-04-17 22:17:54Z jhb $
33 * $FreeBSD: head/lib/libc/stdio/xprintf.c 178721 2008-05-02 15:25:07Z jhb $
34 */
35
34 */
35
36#include <namespace.h>
36#include "namespace.h"
37#include <err.h>
38#include <sys/types.h>
39#include <stdio.h>
40#include <stddef.h>
41#include <stdlib.h>
42#include <locale.h>
43#include <stdint.h>
44#include <assert.h>
45#include <stdarg.h>
46#include <namespace.h>
47#include <string.h>
48#include <wchar.h>
37#include <err.h>
38#include <sys/types.h>
39#include <stdio.h>
40#include <stddef.h>
41#include <stdlib.h>
42#include <locale.h>
43#include <stdint.h>
44#include <assert.h>
45#include <stdarg.h>
46#include <namespace.h>
47#include <string.h>
48#include <wchar.h>
49#include <un-namespace.h>
49#include "un-namespace.h"
50#include "local.h"
50
51#include "printf.h"
52#include "fvwrite.h"
53
54int __use_xprintf = -1;
55
56/* private stuff -----------------------------------------------------*/
57
58union arg {
59 int intarg;
60 long longarg;
61 intmax_t intmaxarg;
62#ifndef NO_FLOATING_POINT
63 double doublearg;
64 long double longdoublearg;
65#endif
66 wint_t wintarg;
67 char *pchararg;
68 wchar_t *pwchararg;
69 void *pvoidarg;
70};
71
72/*
73 * Macros for converting digits to letters and vice versa
74 */
75#define to_digit(c) ((c) - '0')
76#define is_digit(c) (((unsigned)to_digit(c)) <= 9)
77
78/* various globals ---------------------------------------------------*/
79
80const char __lowercase_hex[17] = "0123456789abcdef?"; /*lint !e784 */
81const char __uppercase_hex[17] = "0123456789ABCDEF?"; /*lint !e784 */
82
83#define PADSIZE 16
84static char blanks[PADSIZE] =
85 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
86static char zeroes[PADSIZE] =
87 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
88
89/* printing and padding functions ------------------------------------*/
90
91#define NIOV 8
92
93struct __printf_io {
94 FILE *fp;
95 struct __suio uio;
96 struct __siov iov[NIOV];
97 struct __siov *iovp;
98};
99
100static void
101__printf_init(struct __printf_io *io)
102{
103
104 io->uio.uio_iov = io->iovp = &io->iov[0];
105 io->uio.uio_resid = 0;
106 io->uio.uio_iovcnt = 0;
107}
108
109void
110__printf_flush(struct __printf_io *io)
111{
112
113 __sfvwrite(io->fp, &io->uio);
114 __printf_init(io);
115}
116
117int
118__printf_puts(struct __printf_io *io, const void *ptr, int len)
119{
120
121
122 if (io->fp->_flags & __SERR)
123 return (0);
124 if (len == 0)
125 return (0);
126 io->iovp->iov_base = __DECONST(void *, ptr);
127 io->iovp->iov_len = len;
128 io->uio.uio_resid += len;
129 io->iovp++;
130 io->uio.uio_iovcnt++;
131 if (io->uio.uio_iovcnt >= NIOV)
132 __printf_flush(io);
133 return (len);
134}
135
136int
137__printf_pad(struct __printf_io *io, int howmany, int zero)
138{
139 int n;
140 const char *with;
141 int ret = 0;
142
143 if (zero)
144 with = zeroes;
145 else
146 with = blanks;
147
148 if ((n = (howmany)) > 0) {
149 while (n > PADSIZE) {
150 ret += __printf_puts(io, with, PADSIZE);
151 n -= PADSIZE;
152 }
153 ret += __printf_puts(io, with, n);
154 }
155 return (ret);
156}
157
158int
159__printf_out(struct __printf_io *io, const struct printf_info *pi, const void *ptr, int len)
160{
161 int ret = 0;
162
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');
168 return (ret);
169}
170
171
172/* percent handling -------------------------------------------------*/
173
174static int
175__printf_arginfo_pct(const struct printf_info *pi __unused, size_t n __unused, int *argt __unused)
176{
177
178 return (0);
179}
180
181static int
182__printf_render_pct(struct __printf_io *io, const struct printf_info *pi __unused, const void *const *arg __unused)
183{
184
185 return (__printf_puts(io, "%", 1));
186}
187
188/* 'n' ---------------------------------------------------------------*/
189
190static int
191__printf_arginfo_n(const struct printf_info *pi, size_t n, int *argt)
192{
193
194 assert(n >= 1);
195 argt[0] = PA_POINTER;
196 return (1);
197}
198
199/*
200 * This is a printf_render so that all output has been flushed before it
201 * gets called.
202 */
203
204static int
205__printf_render_n(FILE *io __unused, const struct printf_info *pi, const void *const *arg)
206{
207
208 if (pi->is_char)
209 **((signed char **)arg[0]) = (signed char)pi->sofar;
210 else if (pi->is_short)
211 **((short **)arg[0]) = (short)pi->sofar;
212 else if (pi->is_long)
213 **((long **)arg[0]) = pi->sofar;
214 else if (pi->is_long_double)
215 **((long long **)arg[0]) = pi->sofar;
216 else if (pi->is_intmax)
217 **((intmax_t **)arg[0]) = pi->sofar;
218 else if (pi->is_ptrdiff)
219 **((ptrdiff_t **)arg[0]) = pi->sofar;
220 else if (pi->is_quad)
221 **((quad_t **)arg[0]) = pi->sofar;
222 else if (pi->is_size)
223 **((size_t **)arg[0]) = pi->sofar;
224 else
225 **((int **)arg[0]) = pi->sofar;
226
227 return (0);
228}
229
230/* table -------------------------------------------------------------*/
231
232/*lint -esym(785, printf_tbl) */
233static struct {
234 printf_arginfo_function *arginfo;
235 printf_function *gnurender;
236 printf_render *render;
237} printf_tbl[256] = {
238 ['%'] = { __printf_arginfo_pct, NULL, __printf_render_pct },
239 ['A'] = { __printf_arginfo_float, NULL, __printf_render_float },
240 ['C'] = { __printf_arginfo_chr, NULL, __printf_render_chr },
241 ['E'] = { __printf_arginfo_float, NULL, __printf_render_float },
242 ['F'] = { __printf_arginfo_float, NULL, __printf_render_float },
243 ['G'] = { __printf_arginfo_float, NULL, __printf_render_float },
244 ['S'] = { __printf_arginfo_str, NULL, __printf_render_str },
245 ['X'] = { __printf_arginfo_int, NULL, __printf_render_int },
246 ['a'] = { __printf_arginfo_float, NULL, __printf_render_float },
247 ['c'] = { __printf_arginfo_chr, NULL, __printf_render_chr },
248 ['d'] = { __printf_arginfo_int, NULL, __printf_render_int },
249 ['e'] = { __printf_arginfo_float, NULL, __printf_render_float },
250 ['f'] = { __printf_arginfo_float, NULL, __printf_render_float },
251 ['g'] = { __printf_arginfo_float, NULL, __printf_render_float },
252 ['i'] = { __printf_arginfo_int, NULL, __printf_render_int },
253 ['n'] = { __printf_arginfo_n, __printf_render_n, NULL },
254 ['o'] = { __printf_arginfo_int, NULL, __printf_render_int },
255 ['p'] = { __printf_arginfo_ptr, NULL, __printf_render_ptr },
256 ['q'] = { __printf_arginfo_int, NULL, __printf_render_int },
257 ['s'] = { __printf_arginfo_str, NULL, __printf_render_str },
258 ['u'] = { __printf_arginfo_int, NULL, __printf_render_int },
259 ['x'] = { __printf_arginfo_int, NULL, __printf_render_int },
260};
261
262
263static int
264__v2printf(FILE *fp, const char *fmt0, unsigned pct, va_list ap)
265{
266 struct printf_info *pi, *pil;
267 const char *fmt;
268 int ch;
269 struct printf_info pia[pct + 10];
270 int argt[pct + 10];
271 union arg args[pct + 10];
272 int nextarg;
273 int maxarg;
274 int ret = 0;
275 int n;
276 struct __printf_io io;
277
278 __printf_init(&io);
279 io.fp = fp;
280
281 fmt = fmt0;
282 maxarg = 0;
283 nextarg = 1;
284 memset(argt, 0, sizeof argt);
285 for (pi = pia; ; pi++) {
286 memset(pi, 0, sizeof *pi);
287 pil = pi;
288 if (*fmt == '\0')
289 break;
290 pil = pi + 1;
291 pi->prec = -1;
292 pi->pad = ' ';
293 pi->begin = pi->end = fmt;
294 while (*fmt != '\0' && *fmt != '%')
295 pi->end = ++fmt;
296 if (*fmt == '\0')
297 break;
298 fmt++;
299 for (;;) {
300 pi->spec = *fmt;
301 switch (pi->spec) {
302 case ' ':
303 /*-
304 * ``If the space and + flags both appear, the space
305 * flag will be ignored.''
306 * -- ANSI X3J11
307 */
308 if (pi->showsign == 0)
309 pi->showsign = ' ';
310 fmt++;
311 continue;
312 case '#':
313 pi->alt = 1;
314 fmt++;
315 continue;
316 case '.':
317 pi->prec = 0;
318 fmt++;
319 if (*fmt == '*') {
320 fmt++;
321 pi->get_prec = nextarg;
322 argt[nextarg++] = PA_INT;
323 continue;
324 }
325 while (*fmt != '\0' && is_digit(*fmt)) {
326 pi->prec *= 10;
327 pi->prec += to_digit(*fmt);
328 fmt++;
329 }
330 continue;
331 case '-':
332 pi->left = 1;
333 fmt++;
334 continue;
335 case '+':
336 pi->showsign = '+';
337 fmt++;
338 continue;
339 case '*':
340 fmt++;
341 pi->get_width = nextarg;
342 argt[nextarg++] = PA_INT;
343 continue;
344 case '%':
345 fmt++;
346 break;
347 case '\'':
348 pi->group = 1;
349 fmt++;
350 continue;
351 case '0':
352 /*-
353 * ``Note that 0 is taken as a flag, not as the
354 * beginning of a field width.''
355 * -- ANSI X3J11
356 */
357 pi->pad = '0';
358 fmt++;
359 continue;
360 case '1': case '2': case '3':
361 case '4': case '5': case '6':
362 case '7': case '8': case '9':
363 n = 0;
364 while (*fmt != '\0' && is_digit(*fmt)) {
365 n *= 10;
366 n += to_digit(*fmt);
367 fmt++;
368 }
369 if (*fmt == '$') {
370 if (nextarg > maxarg)
371 maxarg = nextarg;
372 nextarg = n;
373 fmt++;
374 } else
375 pi->width = n;
376 continue;
377 case 'D':
378 case 'O':
379 case 'U':
380 pi->spec += ('a' - 'A');
381 pi->is_intmax = 0;
382 if (pi->is_long_double || pi->is_quad) {
383 pi->is_long = 0;
384 pi->is_long_double = 1;
385 } else {
386 pi->is_long = 1;
387 pi->is_long_double = 0;
388 }
389 fmt++;
390 break;
391 case 'j':
392 pi->is_intmax = 1;
393 fmt++;
394 continue;
395 case 'q':
396 pi->is_long = 0;
397 pi->is_quad = 1;
398 fmt++;
399 continue;
400 case 'L':
401 pi->is_long_double = 1;
402 fmt++;
403 continue;
404 case 'h':
405 fmt++;
406 if (*fmt == 'h') {
407 fmt++;
408 pi->is_char = 1;
409 } else {
410 pi->is_short = 1;
411 }
412 continue;
413 case 'l':
414 fmt++;
415 if (*fmt == 'l') {
416 fmt++;
417 pi->is_long_double = 1;
418 pi->is_quad = 0;
419 } else {
420 pi->is_quad = 0;
421 pi->is_long = 1;
422 }
423 continue;
424 case 't':
425 pi->is_ptrdiff = 1;
426 fmt++;
427 continue;
428 case 'z':
429 pi->is_size = 1;
430 fmt++;
431 continue;
432 default:
433 fmt++;
434 break;
435 }
436 if (printf_tbl[pi->spec].arginfo == NULL)
437 errx(1, "arginfo[%c] = NULL", pi->spec);
438 ch = printf_tbl[pi->spec].arginfo(
439 pi, __PRINTFMAXARG, &argt[nextarg]);
440 if (ch > 0)
441 pi->arg[0] = &args[nextarg];
442 if (ch > 1)
443 pi->arg[1] = &args[nextarg + 1];
444 nextarg += ch;
445 break;
446 }
447 }
448 if (nextarg > maxarg)
449 maxarg = nextarg;
450#if 0
451 fprintf(stderr, "fmt0 <%s>\n", fmt0);
452 fprintf(stderr, "pil %p\n", pil);
453#endif
454 for (ch = 1; ch < maxarg; ch++) {
455#if 0
456 fprintf(stderr, "arg %d %x\n", ch, argt[ch]);
457#endif
458 switch(argt[ch]) {
459 case PA_CHAR:
460 args[ch].intarg = (char)va_arg (ap, int);
461 break;
462 case PA_INT:
463 args[ch].intarg = va_arg (ap, int);
464 break;
465 case PA_INT | PA_FLAG_SHORT:
466 args[ch].intarg = (short)va_arg (ap, int);
467 break;
468 case PA_INT | PA_FLAG_LONG:
469 args[ch].longarg = va_arg (ap, long);
470 break;
471 case PA_INT | PA_FLAG_INTMAX:
472 args[ch].intmaxarg = va_arg (ap, intmax_t);
473 break;
474 case PA_INT | PA_FLAG_QUAD:
475 args[ch].intmaxarg = va_arg (ap, quad_t);
476 break;
477 case PA_INT | PA_FLAG_LONG_LONG:
478 args[ch].intmaxarg = va_arg (ap, long long);
479 break;
480 case PA_INT | PA_FLAG_SIZE:
481 args[ch].intmaxarg = va_arg (ap, size_t);
482 break;
483 case PA_INT | PA_FLAG_PTRDIFF:
484 args[ch].intmaxarg = va_arg (ap, ptrdiff_t);
485 break;
486 case PA_WCHAR:
487 args[ch].wintarg = va_arg (ap, wint_t);
488 break;
489 case PA_POINTER:
490 args[ch].pvoidarg = va_arg (ap, void *);
491 break;
492 case PA_STRING:
493 args[ch].pchararg = va_arg (ap, char *);
494 break;
495 case PA_WSTRING:
496 args[ch].pwchararg = va_arg (ap, wchar_t *);
497 break;
498 case PA_DOUBLE:
499#ifndef NO_FLOATING_POINT
500 args[ch].doublearg = va_arg (ap, double);
501#endif
502 break;
503 case PA_DOUBLE | PA_FLAG_LONG_DOUBLE:
504#ifndef NO_FLOATING_POINT
505 args[ch].longdoublearg = va_arg (ap, long double);
506#endif
507 break;
508 default:
509 errx(1, "argtype = %x (fmt = \"%s\")\n",
510 argt[ch], fmt0);
511 }
512 }
513 for (pi = pia; pi < pil; pi++) {
514#if 0
515 fprintf(stderr, "pi %p", pi);
516 fprintf(stderr, " spec '%c'", pi->spec);
517 fprintf(stderr, " args %d",
518 ((uintptr_t)pi->arg[0] - (uintptr_t)args) / sizeof args[0]);
519 if (pi->width) fprintf(stderr, " width %d", pi->width);
520 if (pi->pad) fprintf(stderr, " pad 0x%x", pi->pad);
521 if (pi->left) fprintf(stderr, " left");
522 if (pi->showsign) fprintf(stderr, " showsign");
523 if (pi->prec != -1) fprintf(stderr, " prec %d", pi->prec);
524 if (pi->is_char) fprintf(stderr, " char");
525 if (pi->is_short) fprintf(stderr, " short");
526 if (pi->is_long) fprintf(stderr, " long");
527 if (pi->is_long_double) fprintf(stderr, " long_double");
528 fprintf(stderr, "\n");
529 fprintf(stderr, "\t\"%.*s\"\n", pi->end - pi->begin, pi->begin);
530#endif
531 if (pi->get_width) {
532 pi->width = args[pi->get_width].intarg;
533 /*-
534 * ``A negative field width argument is taken as a
535 * - flag followed by a positive field width.''
536 * -- ANSI X3J11
537 * They don't exclude field widths read from args.
538 */
539 if (pi->width < 0) {
540 pi->left = 1;
541 pi->width = -pi->width;
542 }
543 }
544 if (pi->get_prec)
545 pi->prec = args[pi->get_prec].intarg;
546 ret += __printf_puts(&io, pi->begin, pi->end - pi->begin);
547 if (printf_tbl[pi->spec].gnurender != NULL) {
548 __printf_flush(&io);
549 pi->sofar = ret;
550 ret += printf_tbl[pi->spec].gnurender(
551 fp, pi, (const void *)pi->arg);
552 } else if (printf_tbl[pi->spec].render != NULL) {
553 pi->sofar = ret;
554 n = printf_tbl[pi->spec].render(
555 &io, pi, (const void *)pi->arg);
556 if (n < 0)
557 io.fp->_flags |= __SERR;
558 else
559 ret += n;
560 } else if (pi->begin == pi->end)
561 errx(1, "render[%c] = NULL", *fmt);
562 }
563 __printf_flush(&io);
564 return (ret);
565}
566
567extern int __fflush(FILE *fp);
568
569/*
570 * Helper function for `fprintf to unbuffered unix file': creates a
571 * temporary buffer. We only work on write-only files; this avoids
572 * worries about ungetc buffers and so forth.
573 */
574static int
575__v3printf(FILE *fp, const char *fmt, int pct, va_list ap)
576{
577 int ret;
578 FILE fake;
579 unsigned char buf[BUFSIZ];
580
581 /* copy the important variables */
582 fake._flags = fp->_flags & ~__SNBF;
583 fake._file = fp->_file;
584 fake._cookie = fp->_cookie;
585 fake._write = fp->_write;
586 fake._orientation = fp->_orientation;
587 fake._mbstate = fp->_mbstate;
588
589 /* set up the buffer */
590 fake._bf._base = fake._p = buf;
591 fake._bf._size = fake._w = sizeof(buf);
592 fake._lbfsize = 0; /* not actually used, but Just In Case */
593
594 /* do the work, then copy any error status */
595 ret = __v2printf(&fake, fmt, pct, ap);
596 if (ret >= 0 && __fflush(&fake))
597 ret = EOF;
598 if (fake._flags & __SERR)
599 fp->_flags |= __SERR;
600 return (ret);
601}
602
603int
604__xvprintf(FILE *fp, const char *fmt0, va_list ap)
605{
606 unsigned u;
607 const char *p;
608
609 /* Count number of '%' signs handling double '%' signs */
610 for (p = fmt0, u = 0; *p; p++) {
611 if (*p != '%')
612 continue;
613 u++;
614 if (p[1] == '%')
615 p++;
616 }
617
618 /* optimise fprintf(stderr) (and other unbuffered Unix files) */
619 if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
620 fp->_file >= 0)
621 return (__v3printf(fp, fmt0, u, ap));
622 else
623 return (__v2printf(fp, fmt0, u, ap));
624}
625
626/* extending ---------------------------------------------------------*/
627
628int
629register_printf_function(int spec, printf_function *render, printf_arginfo_function *arginfo)
630{
631
632 if (spec > 255 || spec < 0)
633 return (-1);
634 printf_tbl[spec].gnurender = render;
635 printf_tbl[spec].arginfo = arginfo;
636 __use_xprintf = 1;
637 return (0);
638}
639
640int
641register_printf_render(int spec, printf_render *render, printf_arginfo_function *arginfo)
642{
643
644 if (spec > 255 || spec < 0)
645 return (-1);
646 printf_tbl[spec].render = render;
647 printf_tbl[spec].arginfo = arginfo;
648 __use_xprintf = 1;
649 return (0);
650}
651
652int
653register_printf_render_std(const unsigned char *specs)
654{
655
656 for (; *specs != '\0'; specs++) {
657 switch (*specs) {
658 case 'H':
659 register_printf_render(*specs,
660 __printf_render_hexdump,
661 __printf_arginfo_hexdump);
662 break;
663 case 'M':
664 register_printf_render(*specs,
665 __printf_render_errno,
666 __printf_arginfo_errno);
667 break;
668 case 'Q':
669 register_printf_render(*specs,
670 __printf_render_quote,
671 __printf_arginfo_quote);
672 break;
673 case 'T':
674 register_printf_render(*specs,
675 __printf_render_time,
676 __printf_arginfo_time);
677 break;
678 case 'V':
679 register_printf_render(*specs,
680 __printf_render_vis,
681 __printf_arginfo_vis);
682 break;
683 default:
684 return (-1);
685 }
686 }
687 return (0);
688}
689
51
52#include "printf.h"
53#include "fvwrite.h"
54
55int __use_xprintf = -1;
56
57/* private stuff -----------------------------------------------------*/
58
59union arg {
60 int intarg;
61 long longarg;
62 intmax_t intmaxarg;
63#ifndef NO_FLOATING_POINT
64 double doublearg;
65 long double longdoublearg;
66#endif
67 wint_t wintarg;
68 char *pchararg;
69 wchar_t *pwchararg;
70 void *pvoidarg;
71};
72
73/*
74 * Macros for converting digits to letters and vice versa
75 */
76#define to_digit(c) ((c) - '0')
77#define is_digit(c) (((unsigned)to_digit(c)) <= 9)
78
79/* various globals ---------------------------------------------------*/
80
81const char __lowercase_hex[17] = "0123456789abcdef?"; /*lint !e784 */
82const char __uppercase_hex[17] = "0123456789ABCDEF?"; /*lint !e784 */
83
84#define PADSIZE 16
85static char blanks[PADSIZE] =
86 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
87static char zeroes[PADSIZE] =
88 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
89
90/* printing and padding functions ------------------------------------*/
91
92#define NIOV 8
93
94struct __printf_io {
95 FILE *fp;
96 struct __suio uio;
97 struct __siov iov[NIOV];
98 struct __siov *iovp;
99};
100
101static void
102__printf_init(struct __printf_io *io)
103{
104
105 io->uio.uio_iov = io->iovp = &io->iov[0];
106 io->uio.uio_resid = 0;
107 io->uio.uio_iovcnt = 0;
108}
109
110void
111__printf_flush(struct __printf_io *io)
112{
113
114 __sfvwrite(io->fp, &io->uio);
115 __printf_init(io);
116}
117
118int
119__printf_puts(struct __printf_io *io, const void *ptr, int len)
120{
121
122
123 if (io->fp->_flags & __SERR)
124 return (0);
125 if (len == 0)
126 return (0);
127 io->iovp->iov_base = __DECONST(void *, ptr);
128 io->iovp->iov_len = len;
129 io->uio.uio_resid += len;
130 io->iovp++;
131 io->uio.uio_iovcnt++;
132 if (io->uio.uio_iovcnt >= NIOV)
133 __printf_flush(io);
134 return (len);
135}
136
137int
138__printf_pad(struct __printf_io *io, int howmany, int zero)
139{
140 int n;
141 const char *with;
142 int ret = 0;
143
144 if (zero)
145 with = zeroes;
146 else
147 with = blanks;
148
149 if ((n = (howmany)) > 0) {
150 while (n > PADSIZE) {
151 ret += __printf_puts(io, with, PADSIZE);
152 n -= PADSIZE;
153 }
154 ret += __printf_puts(io, with, n);
155 }
156 return (ret);
157}
158
159int
160__printf_out(struct __printf_io *io, const struct printf_info *pi, const void *ptr, int len)
161{
162 int ret = 0;
163
164 if ((!pi->left) && pi->width > len)
165 ret += __printf_pad(io, pi->width - len, pi->pad == '0');
166 ret += __printf_puts(io, ptr, len);
167 if (pi->left && pi->width > len)
168 ret += __printf_pad(io, pi->width - len, pi->pad == '0');
169 return (ret);
170}
171
172
173/* percent handling -------------------------------------------------*/
174
175static int
176__printf_arginfo_pct(const struct printf_info *pi __unused, size_t n __unused, int *argt __unused)
177{
178
179 return (0);
180}
181
182static int
183__printf_render_pct(struct __printf_io *io, const struct printf_info *pi __unused, const void *const *arg __unused)
184{
185
186 return (__printf_puts(io, "%", 1));
187}
188
189/* 'n' ---------------------------------------------------------------*/
190
191static int
192__printf_arginfo_n(const struct printf_info *pi, size_t n, int *argt)
193{
194
195 assert(n >= 1);
196 argt[0] = PA_POINTER;
197 return (1);
198}
199
200/*
201 * This is a printf_render so that all output has been flushed before it
202 * gets called.
203 */
204
205static int
206__printf_render_n(FILE *io __unused, const struct printf_info *pi, const void *const *arg)
207{
208
209 if (pi->is_char)
210 **((signed char **)arg[0]) = (signed char)pi->sofar;
211 else if (pi->is_short)
212 **((short **)arg[0]) = (short)pi->sofar;
213 else if (pi->is_long)
214 **((long **)arg[0]) = pi->sofar;
215 else if (pi->is_long_double)
216 **((long long **)arg[0]) = pi->sofar;
217 else if (pi->is_intmax)
218 **((intmax_t **)arg[0]) = pi->sofar;
219 else if (pi->is_ptrdiff)
220 **((ptrdiff_t **)arg[0]) = pi->sofar;
221 else if (pi->is_quad)
222 **((quad_t **)arg[0]) = pi->sofar;
223 else if (pi->is_size)
224 **((size_t **)arg[0]) = pi->sofar;
225 else
226 **((int **)arg[0]) = pi->sofar;
227
228 return (0);
229}
230
231/* table -------------------------------------------------------------*/
232
233/*lint -esym(785, printf_tbl) */
234static struct {
235 printf_arginfo_function *arginfo;
236 printf_function *gnurender;
237 printf_render *render;
238} printf_tbl[256] = {
239 ['%'] = { __printf_arginfo_pct, NULL, __printf_render_pct },
240 ['A'] = { __printf_arginfo_float, NULL, __printf_render_float },
241 ['C'] = { __printf_arginfo_chr, NULL, __printf_render_chr },
242 ['E'] = { __printf_arginfo_float, NULL, __printf_render_float },
243 ['F'] = { __printf_arginfo_float, NULL, __printf_render_float },
244 ['G'] = { __printf_arginfo_float, NULL, __printf_render_float },
245 ['S'] = { __printf_arginfo_str, NULL, __printf_render_str },
246 ['X'] = { __printf_arginfo_int, NULL, __printf_render_int },
247 ['a'] = { __printf_arginfo_float, NULL, __printf_render_float },
248 ['c'] = { __printf_arginfo_chr, NULL, __printf_render_chr },
249 ['d'] = { __printf_arginfo_int, NULL, __printf_render_int },
250 ['e'] = { __printf_arginfo_float, NULL, __printf_render_float },
251 ['f'] = { __printf_arginfo_float, NULL, __printf_render_float },
252 ['g'] = { __printf_arginfo_float, NULL, __printf_render_float },
253 ['i'] = { __printf_arginfo_int, NULL, __printf_render_int },
254 ['n'] = { __printf_arginfo_n, __printf_render_n, NULL },
255 ['o'] = { __printf_arginfo_int, NULL, __printf_render_int },
256 ['p'] = { __printf_arginfo_ptr, NULL, __printf_render_ptr },
257 ['q'] = { __printf_arginfo_int, NULL, __printf_render_int },
258 ['s'] = { __printf_arginfo_str, NULL, __printf_render_str },
259 ['u'] = { __printf_arginfo_int, NULL, __printf_render_int },
260 ['x'] = { __printf_arginfo_int, NULL, __printf_render_int },
261};
262
263
264static int
265__v2printf(FILE *fp, const char *fmt0, unsigned pct, va_list ap)
266{
267 struct printf_info *pi, *pil;
268 const char *fmt;
269 int ch;
270 struct printf_info pia[pct + 10];
271 int argt[pct + 10];
272 union arg args[pct + 10];
273 int nextarg;
274 int maxarg;
275 int ret = 0;
276 int n;
277 struct __printf_io io;
278
279 __printf_init(&io);
280 io.fp = fp;
281
282 fmt = fmt0;
283 maxarg = 0;
284 nextarg = 1;
285 memset(argt, 0, sizeof argt);
286 for (pi = pia; ; pi++) {
287 memset(pi, 0, sizeof *pi);
288 pil = pi;
289 if (*fmt == '\0')
290 break;
291 pil = pi + 1;
292 pi->prec = -1;
293 pi->pad = ' ';
294 pi->begin = pi->end = fmt;
295 while (*fmt != '\0' && *fmt != '%')
296 pi->end = ++fmt;
297 if (*fmt == '\0')
298 break;
299 fmt++;
300 for (;;) {
301 pi->spec = *fmt;
302 switch (pi->spec) {
303 case ' ':
304 /*-
305 * ``If the space and + flags both appear, the space
306 * flag will be ignored.''
307 * -- ANSI X3J11
308 */
309 if (pi->showsign == 0)
310 pi->showsign = ' ';
311 fmt++;
312 continue;
313 case '#':
314 pi->alt = 1;
315 fmt++;
316 continue;
317 case '.':
318 pi->prec = 0;
319 fmt++;
320 if (*fmt == '*') {
321 fmt++;
322 pi->get_prec = nextarg;
323 argt[nextarg++] = PA_INT;
324 continue;
325 }
326 while (*fmt != '\0' && is_digit(*fmt)) {
327 pi->prec *= 10;
328 pi->prec += to_digit(*fmt);
329 fmt++;
330 }
331 continue;
332 case '-':
333 pi->left = 1;
334 fmt++;
335 continue;
336 case '+':
337 pi->showsign = '+';
338 fmt++;
339 continue;
340 case '*':
341 fmt++;
342 pi->get_width = nextarg;
343 argt[nextarg++] = PA_INT;
344 continue;
345 case '%':
346 fmt++;
347 break;
348 case '\'':
349 pi->group = 1;
350 fmt++;
351 continue;
352 case '0':
353 /*-
354 * ``Note that 0 is taken as a flag, not as the
355 * beginning of a field width.''
356 * -- ANSI X3J11
357 */
358 pi->pad = '0';
359 fmt++;
360 continue;
361 case '1': case '2': case '3':
362 case '4': case '5': case '6':
363 case '7': case '8': case '9':
364 n = 0;
365 while (*fmt != '\0' && is_digit(*fmt)) {
366 n *= 10;
367 n += to_digit(*fmt);
368 fmt++;
369 }
370 if (*fmt == '$') {
371 if (nextarg > maxarg)
372 maxarg = nextarg;
373 nextarg = n;
374 fmt++;
375 } else
376 pi->width = n;
377 continue;
378 case 'D':
379 case 'O':
380 case 'U':
381 pi->spec += ('a' - 'A');
382 pi->is_intmax = 0;
383 if (pi->is_long_double || pi->is_quad) {
384 pi->is_long = 0;
385 pi->is_long_double = 1;
386 } else {
387 pi->is_long = 1;
388 pi->is_long_double = 0;
389 }
390 fmt++;
391 break;
392 case 'j':
393 pi->is_intmax = 1;
394 fmt++;
395 continue;
396 case 'q':
397 pi->is_long = 0;
398 pi->is_quad = 1;
399 fmt++;
400 continue;
401 case 'L':
402 pi->is_long_double = 1;
403 fmt++;
404 continue;
405 case 'h':
406 fmt++;
407 if (*fmt == 'h') {
408 fmt++;
409 pi->is_char = 1;
410 } else {
411 pi->is_short = 1;
412 }
413 continue;
414 case 'l':
415 fmt++;
416 if (*fmt == 'l') {
417 fmt++;
418 pi->is_long_double = 1;
419 pi->is_quad = 0;
420 } else {
421 pi->is_quad = 0;
422 pi->is_long = 1;
423 }
424 continue;
425 case 't':
426 pi->is_ptrdiff = 1;
427 fmt++;
428 continue;
429 case 'z':
430 pi->is_size = 1;
431 fmt++;
432 continue;
433 default:
434 fmt++;
435 break;
436 }
437 if (printf_tbl[pi->spec].arginfo == NULL)
438 errx(1, "arginfo[%c] = NULL", pi->spec);
439 ch = printf_tbl[pi->spec].arginfo(
440 pi, __PRINTFMAXARG, &argt[nextarg]);
441 if (ch > 0)
442 pi->arg[0] = &args[nextarg];
443 if (ch > 1)
444 pi->arg[1] = &args[nextarg + 1];
445 nextarg += ch;
446 break;
447 }
448 }
449 if (nextarg > maxarg)
450 maxarg = nextarg;
451#if 0
452 fprintf(stderr, "fmt0 <%s>\n", fmt0);
453 fprintf(stderr, "pil %p\n", pil);
454#endif
455 for (ch = 1; ch < maxarg; ch++) {
456#if 0
457 fprintf(stderr, "arg %d %x\n", ch, argt[ch]);
458#endif
459 switch(argt[ch]) {
460 case PA_CHAR:
461 args[ch].intarg = (char)va_arg (ap, int);
462 break;
463 case PA_INT:
464 args[ch].intarg = va_arg (ap, int);
465 break;
466 case PA_INT | PA_FLAG_SHORT:
467 args[ch].intarg = (short)va_arg (ap, int);
468 break;
469 case PA_INT | PA_FLAG_LONG:
470 args[ch].longarg = va_arg (ap, long);
471 break;
472 case PA_INT | PA_FLAG_INTMAX:
473 args[ch].intmaxarg = va_arg (ap, intmax_t);
474 break;
475 case PA_INT | PA_FLAG_QUAD:
476 args[ch].intmaxarg = va_arg (ap, quad_t);
477 break;
478 case PA_INT | PA_FLAG_LONG_LONG:
479 args[ch].intmaxarg = va_arg (ap, long long);
480 break;
481 case PA_INT | PA_FLAG_SIZE:
482 args[ch].intmaxarg = va_arg (ap, size_t);
483 break;
484 case PA_INT | PA_FLAG_PTRDIFF:
485 args[ch].intmaxarg = va_arg (ap, ptrdiff_t);
486 break;
487 case PA_WCHAR:
488 args[ch].wintarg = va_arg (ap, wint_t);
489 break;
490 case PA_POINTER:
491 args[ch].pvoidarg = va_arg (ap, void *);
492 break;
493 case PA_STRING:
494 args[ch].pchararg = va_arg (ap, char *);
495 break;
496 case PA_WSTRING:
497 args[ch].pwchararg = va_arg (ap, wchar_t *);
498 break;
499 case PA_DOUBLE:
500#ifndef NO_FLOATING_POINT
501 args[ch].doublearg = va_arg (ap, double);
502#endif
503 break;
504 case PA_DOUBLE | PA_FLAG_LONG_DOUBLE:
505#ifndef NO_FLOATING_POINT
506 args[ch].longdoublearg = va_arg (ap, long double);
507#endif
508 break;
509 default:
510 errx(1, "argtype = %x (fmt = \"%s\")\n",
511 argt[ch], fmt0);
512 }
513 }
514 for (pi = pia; pi < pil; pi++) {
515#if 0
516 fprintf(stderr, "pi %p", pi);
517 fprintf(stderr, " spec '%c'", pi->spec);
518 fprintf(stderr, " args %d",
519 ((uintptr_t)pi->arg[0] - (uintptr_t)args) / sizeof args[0]);
520 if (pi->width) fprintf(stderr, " width %d", pi->width);
521 if (pi->pad) fprintf(stderr, " pad 0x%x", pi->pad);
522 if (pi->left) fprintf(stderr, " left");
523 if (pi->showsign) fprintf(stderr, " showsign");
524 if (pi->prec != -1) fprintf(stderr, " prec %d", pi->prec);
525 if (pi->is_char) fprintf(stderr, " char");
526 if (pi->is_short) fprintf(stderr, " short");
527 if (pi->is_long) fprintf(stderr, " long");
528 if (pi->is_long_double) fprintf(stderr, " long_double");
529 fprintf(stderr, "\n");
530 fprintf(stderr, "\t\"%.*s\"\n", pi->end - pi->begin, pi->begin);
531#endif
532 if (pi->get_width) {
533 pi->width = args[pi->get_width].intarg;
534 /*-
535 * ``A negative field width argument is taken as a
536 * - flag followed by a positive field width.''
537 * -- ANSI X3J11
538 * They don't exclude field widths read from args.
539 */
540 if (pi->width < 0) {
541 pi->left = 1;
542 pi->width = -pi->width;
543 }
544 }
545 if (pi->get_prec)
546 pi->prec = args[pi->get_prec].intarg;
547 ret += __printf_puts(&io, pi->begin, pi->end - pi->begin);
548 if (printf_tbl[pi->spec].gnurender != NULL) {
549 __printf_flush(&io);
550 pi->sofar = ret;
551 ret += printf_tbl[pi->spec].gnurender(
552 fp, pi, (const void *)pi->arg);
553 } else if (printf_tbl[pi->spec].render != NULL) {
554 pi->sofar = ret;
555 n = printf_tbl[pi->spec].render(
556 &io, pi, (const void *)pi->arg);
557 if (n < 0)
558 io.fp->_flags |= __SERR;
559 else
560 ret += n;
561 } else if (pi->begin == pi->end)
562 errx(1, "render[%c] = NULL", *fmt);
563 }
564 __printf_flush(&io);
565 return (ret);
566}
567
568extern int __fflush(FILE *fp);
569
570/*
571 * Helper function for `fprintf to unbuffered unix file': creates a
572 * temporary buffer. We only work on write-only files; this avoids
573 * worries about ungetc buffers and so forth.
574 */
575static int
576__v3printf(FILE *fp, const char *fmt, int pct, va_list ap)
577{
578 int ret;
579 FILE fake;
580 unsigned char buf[BUFSIZ];
581
582 /* copy the important variables */
583 fake._flags = fp->_flags & ~__SNBF;
584 fake._file = fp->_file;
585 fake._cookie = fp->_cookie;
586 fake._write = fp->_write;
587 fake._orientation = fp->_orientation;
588 fake._mbstate = fp->_mbstate;
589
590 /* set up the buffer */
591 fake._bf._base = fake._p = buf;
592 fake._bf._size = fake._w = sizeof(buf);
593 fake._lbfsize = 0; /* not actually used, but Just In Case */
594
595 /* do the work, then copy any error status */
596 ret = __v2printf(&fake, fmt, pct, ap);
597 if (ret >= 0 && __fflush(&fake))
598 ret = EOF;
599 if (fake._flags & __SERR)
600 fp->_flags |= __SERR;
601 return (ret);
602}
603
604int
605__xvprintf(FILE *fp, const char *fmt0, va_list ap)
606{
607 unsigned u;
608 const char *p;
609
610 /* Count number of '%' signs handling double '%' signs */
611 for (p = fmt0, u = 0; *p; p++) {
612 if (*p != '%')
613 continue;
614 u++;
615 if (p[1] == '%')
616 p++;
617 }
618
619 /* optimise fprintf(stderr) (and other unbuffered Unix files) */
620 if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
621 fp->_file >= 0)
622 return (__v3printf(fp, fmt0, u, ap));
623 else
624 return (__v2printf(fp, fmt0, u, ap));
625}
626
627/* extending ---------------------------------------------------------*/
628
629int
630register_printf_function(int spec, printf_function *render, printf_arginfo_function *arginfo)
631{
632
633 if (spec > 255 || spec < 0)
634 return (-1);
635 printf_tbl[spec].gnurender = render;
636 printf_tbl[spec].arginfo = arginfo;
637 __use_xprintf = 1;
638 return (0);
639}
640
641int
642register_printf_render(int spec, printf_render *render, printf_arginfo_function *arginfo)
643{
644
645 if (spec > 255 || spec < 0)
646 return (-1);
647 printf_tbl[spec].render = render;
648 printf_tbl[spec].arginfo = arginfo;
649 __use_xprintf = 1;
650 return (0);
651}
652
653int
654register_printf_render_std(const unsigned char *specs)
655{
656
657 for (; *specs != '\0'; specs++) {
658 switch (*specs) {
659 case 'H':
660 register_printf_render(*specs,
661 __printf_render_hexdump,
662 __printf_arginfo_hexdump);
663 break;
664 case 'M':
665 register_printf_render(*specs,
666 __printf_render_errno,
667 __printf_arginfo_errno);
668 break;
669 case 'Q':
670 register_printf_render(*specs,
671 __printf_render_quote,
672 __printf_arginfo_quote);
673 break;
674 case 'T':
675 register_printf_render(*specs,
676 __printf_render_time,
677 __printf_arginfo_time);
678 break;
679 case 'V':
680 register_printf_render(*specs,
681 __printf_render_vis,
682 __printf_arginfo_vis);
683 break;
684 default:
685 return (-1);
686 }
687 }
688 return (0);
689}
690