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
57int __use_xprintf = -1;
58
59/* private stuff -----------------------------------------------------*/
60
61union 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
83const char __lowercase_hex[17] = "0123456789abcdef?";	/*lint !e784 */
84const char __uppercase_hex[17] = "0123456789ABCDEF?";	/*lint !e784 */
85
86#define PADSIZE 16
87static char blanks[PADSIZE] =
88	 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
89static 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
96struct __printf_io {
97	FILE		*fp;
98	struct __suio	uio;
99	struct __siov	iov[NIOV];
100	struct __siov	*iovp;
101};
102
103static void
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
112void
113__printf_flush(struct __printf_io *io)
114{
115
116	__sfvwrite(io->fp, &io->uio);
117	__printf_init(io);
118}
119
120int
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
139int
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
161int
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
177static int
178__printf_arginfo_pct(const struct printf_info *pi __unused, size_t n __unused, int *argt __unused)
179{
180
181	return (0);
182}
183
184static int
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
193static int
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
207static int
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) */
236static 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
266static int
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
570extern 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 */
577static int
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
606int
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
631int
632register_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
643int
644register_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
655int
656register_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