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$
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
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 = FAKE_FILE;
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 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
691