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