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