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