xref: /freebsd/lib/libc/stdio/xprintf.c (revision 576ee62dd2e5e0454a5316eb9207f4ebaa543171)
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
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
109 __printf_flush(struct __printf_io *io)
110 {
111 
112 	__sfvwrite(io->fp, &io->uio);
113 	__printf_init(io);
114 }
115 
116 int
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
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
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
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
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
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
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
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
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
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
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
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
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