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: src/lib/libc/stdio/xprintf.c,v 1.9 2010/03/11 17:03:32 jhb Exp $
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 <errno.h>
50#include "un-namespace.h"
51
52//#define MACHTIME
53#ifdef MACHTIME
54#include <mach/mach_time.h>
55#endif // MACHTIME
56
57#ifdef XPRINTF_PERF
58#include <libkern/OSAtomic.h>
59#endif /* XPRINTF_PERF */
60
61#include "local.h"
62#include "xprintf_private.h"
63#include "xprintf_domain.h"
64#include "fvwrite.h"
65
66/*
67 * Defining XPRINTF_DEBUG allows the __private_extern__ variable __use_xprintf
68 * to be set so that regular printf variants will use the extensible printf
69 * code path.  This is normally off, and is only used to test the extensible
70 * printf code in the conformance tests.
71 */
72#ifdef XPRINTF_DEBUG
73#include <unistd.h>
74int __use_xprintf = 0;
75#endif
76
77/* private stuff -----------------------------------------------------*/
78
79union arg {
80	int			intarg;
81	long			longarg;
82	intmax_t 		intmaxarg;
83#ifndef NO_FLOATING_POINT
84	double			doublearg;
85	long double 		longdoublearg;
86#endif
87	wint_t			wintarg;
88	char			*pchararg;
89	wchar_t			*pwchararg;
90	void			*pvoidarg;
91#ifdef VECTORS
92	VECTORTYPE		vectorarg;
93	unsigned char		vuchararg[16];
94	signed char		vchararg[16];
95	unsigned short		vushortarg[8];
96	signed short		vshortarg[8];
97	unsigned int		vuintarg[4];
98	signed int		vintarg[4];
99	float			vfloatarg[4];
100#ifdef V64TYPE
101	double			vdoublearg[2];
102	unsigned long long	vulonglongarg[2];
103	long long		vlonglongarg[2];
104#endif /* V64TYPE */
105#endif /* VECTORS */
106};
107
108/*
109 * Macros for converting digits to letters and vice versa
110 */
111#define	to_digit(c)	((c) - '0')
112#define is_digit(c)	(((unsigned)to_digit(c)) <= 9)
113
114/* various globals ---------------------------------------------------*/
115
116__private_extern__ const char __lowercase_hex[17] = "0123456789abcdef?";	/*lint !e784 */
117__private_extern__ const char __uppercase_hex[17] = "0123456789ABCDEF?";	/*lint !e784 */
118
119#define PADSIZE 16
120static char blanks[PADSIZE] =
121	 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
122static char zeroes[PADSIZE] =
123	 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
124
125/* printing and padding functions ------------------------------------*/
126
127#define NIOV 8
128
129struct __printf_io {
130	FILE		*fp;
131	struct __suio	uio;
132	struct __siov	iov[NIOV];
133	struct __siov	*iovp;
134};
135
136static void
137__printf_init(struct __printf_io *io)
138{
139
140	io->uio.uio_iov = io->iovp = &io->iov[0];
141	io->uio.uio_resid = 0;
142	io->uio.uio_iovcnt = 0;
143}
144
145__private_extern__ void
146__printf_flush(struct __printf_io *io)
147{
148
149	__sfvwrite(io->fp, &io->uio);
150	__printf_init(io);
151}
152
153__private_extern__ int
154__printf_puts(struct __printf_io *io, const void *ptr, int len)
155{
156
157
158#if 0
159	if (io->fp->_flags & __SERR)
160		return (0);
161#endif
162	if (len == 0)
163		return (0);
164	io->iovp->iov_base = __DECONST(void *, ptr);
165	io->iovp->iov_len = len;
166	io->uio.uio_resid += len;
167	io->iovp++;
168	io->uio.uio_iovcnt++;
169	if (io->uio.uio_iovcnt >= NIOV)
170		__printf_flush(io);
171	return (len);
172}
173
174__private_extern__ int
175__printf_pad(struct __printf_io *io, int howmany, int zero)
176{
177	int n;
178	const char *with;
179	int ret = 0;
180
181	if (zero)
182		with = zeroes;
183	else
184		with = blanks;
185
186	if ((n = (howmany)) > 0) {
187		while (n > PADSIZE) {
188			ret += __printf_puts(io, with, PADSIZE);
189			n -= PADSIZE;
190		}
191		ret += __printf_puts(io, with, n);
192	}
193	return (ret);
194}
195
196__private_extern__ int
197__printf_out(struct __printf_io *io, const struct printf_info *pi, const void *ptr, int len)
198{
199	int ret = 0;
200
201	if ((!pi->left) && pi->width > len)
202		ret += __printf_pad(io, pi->width - len, pi->pad == '0');
203	ret += __printf_puts(io, ptr, len);
204	if (pi->left && pi->width > len)
205		ret += __printf_pad(io, pi->width - len, pi->pad == '0');
206	return (ret);
207}
208
209
210/* percent handling  -------------------------------------------------*/
211
212__private_extern__ int
213__printf_arginfo_pct(const struct printf_info *pi __unused, size_t n __unused, int *argt __unused)
214{
215
216	return (0);
217}
218
219__private_extern__ int
220__printf_render_pct(struct __printf_io *io, const struct printf_info *pi __unused, const void *const *arg __unused)
221{
222
223	return (__printf_puts(io, "%", 1));
224}
225
226/* 'n' ---------------------------------------------------------------*/
227
228__private_extern__ int
229__printf_arginfo_n(const struct printf_info *pi, size_t n, int *argt)
230{
231
232	assert(n >= 1);
233	argt[0] = PA_POINTER;
234	return (1);
235}
236
237/*
238 * This is a printf_render so that all output has been flushed before it
239 * gets called.
240 */
241
242__private_extern__ int
243__printf_render_n(FILE *io __unused, const struct printf_info *pi, const void *const *arg)
244{
245
246	if (pi->is_char)
247		**((signed char **)arg[0]) = (signed char)pi->sofar;
248	else if (pi->is_short)
249		**((short **)arg[0]) = (short)pi->sofar;
250	else if (pi->is_long)
251		**((long **)arg[0]) = pi->sofar;
252	else if (pi->is_long_double)
253		**((long long **)arg[0]) = pi->sofar;
254	else if (pi->is_intmax)
255		**((intmax_t **)arg[0]) = pi->sofar;
256	else if (pi->is_ptrdiff)
257		**((ptrdiff_t **)arg[0]) = pi->sofar;
258	else if (pi->is_quad)
259		**((quad_t **)arg[0]) = pi->sofar;
260	else if (pi->is_size)
261		**((size_t **)arg[0]) = pi->sofar;
262	else
263		**((int **)arg[0]) = pi->sofar;
264
265	return (0);
266}
267
268/* dynamic array handling  -------------------------------------------------*/
269#define ARRAYDELTA 8
270
271struct array {
272#ifdef XPRINTF_PERF
273	struct array *next;
274#endif /* XPRINTF_PERF */
275	void *data;
276	int itemsize;
277	int max;
278};
279
280#ifdef XPRINTF_PERF
281__private_extern__
282#else /* !XPRINTF_PERF */
283static
284#endif /* !XPRINTF_PERF */
285void
286arrayfree(struct array *a)
287{
288	if(a) free(a->data);
289}
290
291static void *
292arrayget(struct array *a, int i)
293{
294	if (i >= a->max) {
295		int oldsize = a->max * a->itemsize;
296		int newmax = i + ARRAYDELTA;
297		int newsize = newmax * a->itemsize;
298		void *newdata = realloc(a->data, newsize);
299		if(!newdata) return NULL;
300		bzero(newdata + oldsize, newsize - oldsize);
301		a->data = newdata;
302		a->max = newmax;
303	}
304	return a->data + i * a->itemsize;
305}
306
307static struct array *
308arrayinit(struct array *a, int itemsize)
309{
310	a->data = CALLOC(ARRAYDELTA, itemsize);
311	if(!a->data) return NULL;
312	a->itemsize = itemsize;
313	a->max = ARRAYDELTA;
314	return a;
315}
316
317/* dynamic array caching  -------------------------------------------------*/
318/*
319 * Normally, dynamic array structures are created on the stack, and array
320 * itself is freshly allocated, and then freed when no longer needed.  When
321 * the XPRINTF_PERF macro is defined, the dynamic array structures associated
322 * with all-in-one printf variants are not freed, but store in a cache for
323 * later use (dynamic array structures used for compile/execute continue to
324 * be freed after they are no longer needed).  This means there should be
325 * at most one structure in the cached per thread that actually used the
326 * all-in-one printf variant.
327 *
328 * The amount of memory that is cached is fairly small, totally about 1K
329 * for three structures used by a format string using ten conversion
330 * specifiers.  This is too small for purgeable memory.
331 *
332 * However, we do flush these caches in case we every are unable to allocate
333 * memory, and retry the allocation, just in case.
334 */
335#ifdef XPRINTF_PERF
336static OSQueueHead arg_type_queue = OS_ATOMIC_QUEUE_INIT;
337static OSQueueHead printf_info_queue = OS_ATOMIC_QUEUE_INIT;
338static OSQueueHead union_arg_queue = OS_ATOMIC_QUEUE_INIT;
339
340#define DEFINE_DEQUEUE(which, type) \
341static struct array * \
342which ## _dequeue(void) \
343{ \
344	struct array *a = (struct array *)OSAtomicDequeue(&which ## _queue, offsetof(struct array, next)); \
345 \
346	if (a) { \
347		bzero(a->data, a->max * a->itemsize); \
348		return a; \
349	} \
350	a = (struct array *)MALLOC(sizeof(*a)); \
351	if (!a) return NULL; \
352	if (!arrayinit(a, sizeof(type))) { \
353		free(a); \
354		return NULL; \
355	} \
356	return a; \
357}
358
359#define DEFINE_ENQUEUE(which) \
360__private_extern__ void \
361which ## _enqueue(struct array *a) \
362{ \
363	if (!a) return; \
364	OSAtomicEnqueue(&which ## _queue, a, offsetof(struct array, next)); \
365}
366
367#define DEFINE_FLUSH(which) \
368static void \
369which ## _flush(void) \
370{ \
371	struct array *a; \
372	while((a = (struct array *)OSAtomicDequeue(&which ## _queue, offsetof(struct array, next))) != NULL) { \
373		arrayfree(a); \
374		free(a); \
375	} \
376}
377
378DEFINE_DEQUEUE(arg_type, int)
379DEFINE_ENQUEUE(arg_type)
380DEFINE_FLUSH(arg_type)
381DEFINE_DEQUEUE(printf_info, struct printf_info)
382DEFINE_ENQUEUE(printf_info)
383DEFINE_FLUSH(printf_info)
384DEFINE_DEQUEUE(union_arg, union arg)
385DEFINE_ENQUEUE(union_arg)
386DEFINE_FLUSH(union_arg)
387
388static void
389flush_queues(void)
390{
391    arg_type_flush();
392    printf_info_flush();
393    union_arg_flush();
394}
395
396__private_extern__ void *
397xprintf_calloc(size_t count, size_t size)
398{
399    void *x = calloc(count, size);
400    if(!x) {
401	flush_queues();
402	x = calloc(count, size);
403    }
404    return x;
405}
406
407__private_extern__ void *
408xprintf_malloc(size_t size)
409{
410    void *x = malloc(size);
411    if(!x) {
412	flush_queues();
413	x = malloc(size);
414    }
415    return x;
416}
417
418#if 0
419void
420show_queues(void)
421{
422    struct array *a;
423    printf("arg_type:");
424    while((a = (struct array *)OSAtomicDequeue(&arg_type_queue, offsetof(struct array, next))) != NULL) printf("\n%p", a);
425    printf("\nprintf_info:");
426    while((a = (struct array *)OSAtomicDequeue(&printf_info_queue, offsetof(struct array, next))) != NULL) printf("\n%p", a);
427    printf("\nunion_arg:");
428    while((a = (struct array *)OSAtomicDequeue(&union_arg_queue, offsetof(struct array, next))) != NULL) printf("\n%p", a);
429    printf("\n");
430}
431#endif
432#endif /* XPRINTF_PERF */
433
434/* -------------------------------------------------------------------------*/
435
436__private_extern__ int
437__printf_comp(printf_comp_t restrict pc, printf_domain_t restrict domain)
438{
439	struct printf_info	*pi, *pil;
440	const char		*fmt;
441	int			ch, pii;
442	int			*argt;
443	int			nextarg;
444	int			maxarg;
445	int			ret = 0;
446	int			n;
447#ifndef XPRINTF_PERF
448	struct array		piarr, argtarr;
449#endif /* XPRINTF_PERF */
450	struct array		*pa, *aa;
451
452	fmt = pc->fmt;
453	maxarg = 0;
454	nextarg = 1;
455#ifdef XPRINTF_PERF
456	pa = printf_info_dequeue();
457#else /* !XPRINTF_PERF */
458	pa = arrayinit(&piarr, sizeof(*pi));
459#endif /* !XPRINTF_PERF */
460	if (!pa) {
461#ifdef XPRINTF_PERF
462	    flush_queues();
463#endif /* XPRINTF_PERF */
464	    return EOF;
465	}
466#ifdef XPRINTF_PERF
467	pc->pa = pa;
468	aa = arg_type_dequeue();
469#else /* !XPRINTF_PERF */
470	aa = arrayinit(&argtarr, sizeof(*argt));
471#endif /* !XPRINTF_PERF */
472	if (!aa) {
473		arrayfree(pa);
474#ifdef XPRINTF_PERF
475		free(pa);
476		flush_queues();
477#endif /* XPRINTF_PERF */
478		return EOF;
479	}
480#ifdef XPRINTF_PERF
481	pc->aa = aa;
482#endif /* XPRINTF_PERF */
483	for (pii = 0; ; pii++) {
484		pi = arrayget(pa, pii);
485		if (!pi) {
486			ret = EOF;
487			goto error;
488		}
489		pil = pi;
490		if (*fmt == '\0')
491			break;
492		pil = pi + 1;
493		pi->prec = -1;
494		pi->pad = ' ';
495#ifdef VECTORS
496		pi->vsep = 'X'; /* Illegal value, changed to defaults later. */
497#endif /* VECTORS */
498		pi->begin = pi->end = fmt;
499		while (*fmt != '\0' && *fmt != '%')
500			pi->end = ++fmt;
501		if (*fmt == '\0')
502			break;
503		fmt++;
504		for (;;) {
505			pi->spec = *fmt;
506			switch (pi->spec) {
507			case ' ':
508				/*-
509				 * ``If the space and + flags both appear, the space
510				 * flag will be ignored.''
511				 *      -- ANSI X3J11
512				 */
513				if (pi->showsign == 0) {
514					pi->space = 1;
515					pi->signchar = ' ';
516				}
517				fmt++;
518				continue;
519			case '#':
520				pi->alt = 1;
521				fmt++;
522				continue;
523#ifdef VECTORS
524			case ',': case ';': case ':': case '_':
525				pi->vsep = pi->spec;
526				fmt++;
527				continue;
528#endif /* VECTORS */
529			case '.':
530				pi->prec = 0;
531				fmt++;
532				if (*fmt == '*') {
533					fmt++;
534					/* Look for *nn$ and deal with it */
535					n = 0;
536					while (*fmt != '\0' && is_digit(*fmt)) {
537						n *= 10;
538						n += to_digit(*fmt);
539						fmt++;
540					}
541					if (*fmt == '$') {
542						if ((n + 1) > maxarg)
543							maxarg = (n + 1);
544						fmt++;
545					} else n = nextarg++;
546					pi->get_prec = n;
547					argt = (int *)arrayget(aa, n);
548					if (!argt) {
549						ret = EOF;
550						goto error;
551					}
552					*argt = PA_INT;
553					continue;
554				}
555				while (*fmt != '\0' && is_digit(*fmt)) {
556					pi->prec *= 10;
557					pi->prec += to_digit(*fmt);
558					fmt++;
559				}
560				continue;
561			case '-':
562				pi->left = 1;
563				fmt++;
564				continue;
565			case '+':
566				pi->showsign = 1;
567				pi->signchar = '+';
568				fmt++;
569				continue;
570			case '*':
571				fmt++;
572				/* Look for *nn$ and deal with it */
573				n = 0;
574				while (*fmt != '\0' && is_digit(*fmt)) {
575					n *= 10;
576					n += to_digit(*fmt);
577					fmt++;
578				}
579				if (*fmt == '$') {
580					if ((n + 1) > maxarg)
581						maxarg = (n + 1);
582					fmt++;
583				} else n = nextarg++;
584				pi->get_width = n;
585				argt = (int *)arrayget(aa, n);
586				if (!argt) {
587					ret = EOF;
588					goto error;
589				}
590				*argt = PA_INT;
591				continue;
592			case '%':
593				fmt++;
594				break;
595			case '\'':
596				pi->group = 1;
597				fmt++;
598				continue;
599			case '0':
600				/*-
601				 * ``Note that 0 is taken as a flag, not as the
602				 * beginning of a field width.''
603				 *      -- ANSI X3J11
604				 */
605				pi->pad = '0';
606				fmt++;
607				continue;
608			case '1': case '2': case '3':
609			case '4': case '5': case '6':
610			case '7': case '8': case '9':
611				n = 0;
612				while (*fmt != '\0' && is_digit(*fmt)) {
613					n *= 10;
614					n += to_digit(*fmt);
615					fmt++;
616				}
617				if (*fmt == '$') {
618					if (nextarg > maxarg)
619						maxarg = nextarg;
620					nextarg = n;
621					fmt++;
622				} else
623					pi->width = n;
624				continue;
625#if 0
626			case 'D':
627			case 'O':
628			case 'U':
629				pi->spec += ('a' - 'A');
630				pi->is_intmax = 0;
631				if (pi->is_long_double || pi->is_quad) {
632					pi->is_long = 0;
633					pi->is_long_double = 1;
634				} else {
635					pi->is_long = 1;
636					pi->is_long_double = 0;
637				}
638				fmt++;
639				break;
640#endif
641			case 'j':
642				pi->is_intmax = 1;
643				fmt++;
644				continue;
645			case 'q':
646				pi->is_long = 0;
647				pi->is_quad = 1;
648				fmt++;
649				continue;
650			case 'L':
651				pi->is_long_double = 1;
652				fmt++;
653				continue;
654			case 'h':
655				fmt++;
656				if (*fmt == 'h') {
657					fmt++;
658					pi->is_char = 1;
659				} else {
660					pi->is_short = 1;
661				}
662				continue;
663			case 'l':
664				fmt++;
665				if (*fmt == 'l') {
666					fmt++;
667					pi->is_long_double = 1;
668					pi->is_quad = 0;
669				} else {
670					pi->is_quad = 0;
671					pi->is_long = 1;
672				}
673				continue;
674			case 't':
675				pi->is_ptrdiff = 1;
676				fmt++;
677				continue;
678			case 'v':
679#ifdef VECTORS
680				pi->is_vec = 1;
681#endif /* VECTORS */
682				fmt++;
683				continue;
684			case 'z':
685				pi->is_size = 1;
686				fmt++;
687				continue;
688			default:
689				fmt++;
690				break;
691			}
692			if (printf_tbl_in_range(pi->spec)) {
693				switch(domain->type[printf_tbl_index(pi->spec)]) {
694				/* ignore PRINTF_DOMAIN_UNUSED until later */
695				case PRINTF_DOMAIN_FLAG:
696					errx(1, "Unexpected flag: %c", pi->spec);
697				case PRINTF_DOMAIN_GLIBC_API:
698				case PRINTF_DOMAIN_FBSD_API:
699					/*
700					 * Insure that there are always
701					 * __PRINTFMAXARG available.
702					 */
703					if (!arrayget(aa, nextarg + __PRINTFMAXARG - 1)) {
704						ret = EOF;
705						goto error;
706					}
707					pi->context = domain->tbl[printf_tbl_index(pi->spec)].context;
708					pi->loc = pc->loc;
709					ch = domain->tbl[printf_tbl_index(pi->spec)].arginfo(
710					    pi, __PRINTFMAXARG, arrayget(aa, nextarg));
711					if (ch > 0)
712						pi->arg[0] = (void *)(long)nextarg;
713					if (ch > 1)
714						pi->arg[1] = (void *)(long)(nextarg + 1);
715					nextarg += ch;
716					break;
717				}
718			}
719			break;
720		}
721	}
722	if (nextarg > maxarg)
723		maxarg = nextarg;
724	pc->argt = aa->data;
725	pc->pi = pa->data;
726	pc->pil = pil;
727	pc->maxarg = ch = maxarg;
728	if (ch < 1) ch = 1;
729#ifdef XPRINTF_PERF
730	pc->ua = union_arg_dequeue();
731	if (!pc->ua) {
732	    ret = EOF;
733	    goto error;
734	}
735	if (!arrayget(pc->ua, ch)) {
736	    union_arg_enqueue(pc->ua);
737	    ret = EOF;
738	    goto error;
739	}
740	pc->args = pc->ua->data;
741#else /* !XPRINTF_PERF */
742	pc->args = (union arg *)malloc(ch * sizeof(*pc->args));
743	if (!pc->args) {
744		ret = EOF;
745		goto error;
746	}
747#endif /* !XPRINTF_PERF */
748	for (pi = pc->pi; pi < pil; pi++) {
749		if (pi->arg[0]) pi->arg[0] = &pc->args[(long)pi->arg[0]];
750		if (pi->arg[1]) pi->arg[1] = &pc->args[(long)pi->arg[1]];
751	}
752#if 0
753	fprintf(stderr, "fmt0 <%s>\n", fmt0);
754	fprintf(stderr, "pil %p\n", pil);
755#endif
756	pc->domain = domain;
757
758	return (ret);
759error:
760	arrayfree(pa);
761	arrayfree(aa);
762#ifdef XPRINTF_PERF
763	free(pa);
764	free(aa);
765	flush_queues();
766#endif /* XPRINTF_PERF */
767	return (ret);
768}
769
770__private_extern__ int
771__printf_exec(printf_comp_t restrict pc, FILE * restrict fp, va_list ap)
772{
773	struct printf_info	*pi;
774	int			ch;
775	int			ret = 0;
776	int			n;
777	struct __printf_io	io;
778
779	__printf_init(&io);
780	io.fp = fp;
781
782	for (ch = 1; ch < pc->maxarg; ch++) {
783#if 0
784		fprintf(stderr, "arg %d %x\n", ch, pc->argt[ch]);
785#endif
786		switch(pc->argt[ch]) {
787		case PA_CHAR:
788			pc->args[ch].intarg = (char)va_arg (ap, int);
789			break;
790		case PA_INT:
791			pc->args[ch].intarg = va_arg (ap, int);
792			break;
793		case PA_INT | PA_FLAG_SHORT:
794			pc->args[ch].intarg = (short)va_arg (ap, int);
795			break;
796		case PA_INT | PA_FLAG_LONG:
797			pc->args[ch].longarg = va_arg (ap, long);
798			break;
799		case PA_INT | PA_FLAG_INTMAX:
800			pc->args[ch].intmaxarg = va_arg (ap, intmax_t);
801			break;
802		case PA_INT | PA_FLAG_QUAD:
803			pc->args[ch].intmaxarg = va_arg (ap, quad_t);
804			break;
805		case PA_INT | PA_FLAG_LONG_LONG:
806			pc->args[ch].intmaxarg = va_arg (ap, long long);
807			break;
808		case PA_INT | PA_FLAG_SIZE:
809			pc->args[ch].intmaxarg = va_arg (ap, size_t);
810			break;
811		case PA_INT | PA_FLAG_PTRDIFF:
812			pc->args[ch].intmaxarg = (unsigned long)va_arg (ap, ptrdiff_t);
813			break;
814		case PA_WCHAR:
815			pc->args[ch].wintarg = va_arg (ap, wint_t);
816			break;
817		case PA_POINTER:
818			pc->args[ch].pvoidarg = va_arg (ap, void *);
819			break;
820		case PA_STRING:
821			pc->args[ch].pchararg = va_arg (ap, char *);
822			break;
823		case PA_WSTRING:
824			pc->args[ch].pwchararg = va_arg (ap, wchar_t *);
825			break;
826		case PA_DOUBLE:
827#ifndef NO_FLOATING_POINT
828			pc->args[ch].doublearg = va_arg (ap, double);
829#endif
830			break;
831		case PA_DOUBLE | PA_FLAG_LONG_DOUBLE:
832#ifndef NO_FLOATING_POINT
833			pc->args[ch].longdoublearg = va_arg (ap, long double);
834#endif
835			break;
836#ifdef VECTORS
837		case PA_VECTOR:
838			pc->args[ch].vectorarg = va_arg (ap, VECTORTYPE);
839			break;
840#endif /* VECTORS */
841		default:
842			errx(1, "argtype = %x (fmt = \"%s\")\n",
843			    pc->argt[ch], pc->fmt);
844		}
845	}
846	for (pi = pc->pi; pi < pc->pil; pi++) {
847#if 0
848		fprintf(stderr, "pi %p", pi);
849		fprintf(stderr, " spec '%c'", pi->spec);
850		fprintf(stderr, " args %d",
851		    ((uintptr_t)pi->arg[0] - (uintptr_t)pc->args) / sizeof pc->args[0]);
852		if (pi->width) fprintf(stderr, " width %d", pi->width);
853		if (pi->pad) fprintf(stderr, " pad 0x%x", pi->pad);
854		if (pi->left) fprintf(stderr, " left");
855		if (pi->showsign) fprintf(stderr, " showsign");
856		if (pi->signchar) fprintf(stderr, " signchar 0x%x", pi->signchar);
857		if (pi->prec != -1) fprintf(stderr, " prec %d", pi->prec);
858		if (pi->is_char) fprintf(stderr, " char");
859		if (pi->is_short) fprintf(stderr, " short");
860		if (pi->is_long) fprintf(stderr, " long");
861		if (pi->is_long_double) fprintf(stderr, " long_double");
862		fprintf(stderr, "\n");
863		fprintf(stderr, "\t\"%.*s\"\n", pi->end - pi->begin, pi->begin);
864#endif
865		if (pi->get_width) {
866			pi->width = pc->args[pi->get_width].intarg;
867			/*-
868			 * ``A negative field width argument is taken as a
869			 * - flag followed by a positive field width.''
870			 *      -- ANSI X3J11
871			 * They don't exclude field widths read from args.
872			 */
873			if (pi->width < 0) {
874				pi->left = 1;
875				pi->width = -pi->width;
876			}
877		}
878		if (pi->get_prec)
879			pi->prec = pc->args[pi->get_prec].intarg;
880		ret += __printf_puts(&io, pi->begin, pi->end - pi->begin);
881		if (pi->spec) {
882			if (!printf_tbl_in_range(pi->spec)) goto unused;
883			switch(pc->domain->type[printf_tbl_index(pi->spec)]) {
884			case PRINTF_DOMAIN_UNUSED:
885		unused:
886			{
887				char unknown = pi->spec;
888				ret += __printf_out(&io, pi, &unknown, 1);
889				break;
890			}
891			case PRINTF_DOMAIN_GLIBC_API:
892				__printf_flush(&io);
893				pi->sofar = ret;
894				ret += ((printf_function *)pc->domain->tbl[printf_tbl_index(pi->spec)].render)(
895				    fp, pi, (const void *)pi->arg);
896				break;
897			case PRINTF_DOMAIN_FBSD_API:
898				pi->sofar = ret;
899				n = ((printf_render *)pc->domain->tbl[printf_tbl_index(pi->spec)].render)(
900				    &io, pi, (const void *)pi->arg);
901				if (n < 0)
902					io.fp->_flags |= __SERR;
903				else
904					ret += n;
905				break;
906			}
907		}
908	}
909	__printf_flush(&io);
910	return (ret);
911}
912
913__private_extern__ int
914__v2printf(printf_comp_t restrict pc, printf_domain_t restrict domain, FILE * restrict fp, locale_t restrict loc, const char * restrict fmt, va_list ap)
915{
916	struct _printf_compiled spc;
917	int ret, saverrno;
918
919	/*
920	 * All the printf family (including extensible printf variants) funnel
921	 * down to this point.  So we can do common work here, and then fork
922	 * out to the appropriate handler.
923	 */
924	/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
925	if (prepwrite(fp) != 0) {
926		errno = EBADF;
927		return (EOF);
928	}
929	ORIENT(fp, -1);
930
931	if (pc == XPRINTF_PLAIN) {
932		NORMALIZE_LOCALE(loc);
933#ifdef XPRINTF_DEBUG
934		if (!__use_xprintf)
935#endif
936				    return __vfprintf(fp, loc, fmt, ap);
937#ifdef XPRINTF_DEBUG
938		xprintf_domain_init();
939		domain = xprintf_domain_global;
940#endif
941	} else if (pc) {
942	    pthread_mutex_lock(&pc->mutex);
943	    pthread_rwlock_rdlock(&pc->domain->rwlock);
944	    ret = __printf_exec(pc, fp, ap);
945	    saverrno = errno;
946	    pthread_rwlock_unlock(&pc->domain->rwlock);
947	    pthread_mutex_unlock(&pc->mutex);
948	    errno = saverrno;
949	    return ret;
950	}
951	if (!domain) {
952		errno = EINVAL;
953		return EOF;
954	}
955	xprintf_domain_init();
956	bzero(&spc, sizeof(spc));
957	spc.fmt = fmt;
958	DEFAULT_CURRENT_LOCALE(loc);
959	XL_RETAIN(loc);
960	spc.loc = loc;
961	/*
962	 * We don't need to lock the printf_comp_t mutex, since the
963	 * printf_comp_t was just created on the stack, and is private.
964	 */
965	pthread_rwlock_rdlock(&domain->rwlock);
966	if (__printf_comp(&spc, domain) < 0) {
967	    saverrno = errno;
968	    pthread_rwlock_unlock(&domain->rwlock);
969	    XL_RELEASE(loc);
970	    errno = saverrno;
971	    return EOF;
972	}
973	ret = __printf_exec(&spc, fp, ap);
974	saverrno = errno;
975	pthread_rwlock_unlock(&domain->rwlock);
976	XL_RELEASE(loc);
977
978#ifdef XPRINTF_PERF
979	printf_info_enqueue(spc.pa);
980	arg_type_enqueue(spc.aa);
981	union_arg_enqueue(spc.ua);
982#else /* !XPRINTF_PERF */
983	free(spc.pi);
984	free(spc.argt);
985	free(spc.args);
986#endif /* !XPRINTF_PERF */
987	errno = saverrno;
988	return ret;
989}
990
991extern int      __fflush(FILE *fp);
992
993/*
994 * Helper function for `fprintf to unbuffered unix file': creates a
995 * temporary buffer.  We only work on write-only files; this avoids
996 * worries about ungetc buffers and so forth.
997 */
998static int
999__v3printf(printf_comp_t restrict pc, printf_domain_t restrict domain, FILE * restrict fp, locale_t restrict loc, const char * restrict fmt, va_list ap)
1000{
1001	int ret;
1002	FILE fake;
1003	struct __sFILEX extra;
1004	unsigned char buf[BUFSIZ];
1005
1006	fake._extra = &extra;
1007	INITEXTRA(&fake);
1008
1009	/* copy the important variables */
1010	fake._flags = fp->_flags & ~__SNBF;
1011	fake._file = fp->_file;
1012	fake._cookie = fp->_cookie;
1013	fake._write = fp->_write;
1014	fake._orientation = fp->_orientation;
1015	fake._mbstate = fp->_mbstate;
1016
1017	/* set up the buffer */
1018	fake._bf._base = fake._p = buf;
1019	fake._bf._size = fake._w = sizeof(buf);
1020	fake._lbfsize = 0;	/* not actually used, but Just In Case */
1021
1022	/* do the work, then copy any error status */
1023	ret = __v2printf(pc, domain, &fake, loc, fmt, ap);
1024	if (ret >= 0 && __fflush(&fake))
1025		ret = EOF;
1026	if (fake._flags & __SERR)
1027		fp->_flags |= __SERR;
1028	return (ret);
1029}
1030
1031__private_extern__ int
1032__xvprintf(printf_comp_t restrict pc, printf_domain_t restrict domain, FILE * restrict fp, locale_t restrict loc, const char * restrict fmt0, va_list ap)
1033{
1034	int ret;
1035
1036	/* optimise fprintf(stderr) (and other unbuffered Unix files) */
1037	if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
1038	    fp->_file >= 0)
1039		ret = __v3printf(pc, domain, fp, loc, fmt0, ap);
1040	else
1041		ret = __v2printf(pc, domain, fp, loc, fmt0, ap);
1042	return ret;
1043}
1044
1045/* extending ---------------------------------------------------------*/
1046
1047// No global domain support
1048#if 0
1049int
1050register_printf_function(int spec, printf_function *render, printf_arginfo_function *arginfo)
1051{
1052	return register_printf_domain_function(NULL, spec, render, arginfo);
1053}
1054
1055__private_extern__ int
1056register_printf_render(int spec, printf_render *render, printf_arginfo_function *arginfo)
1057{
1058	return register_printf_domain_render(NULL, spec, render, arginfo);
1059}
1060
1061int
1062register_printf_render_std(const char *specs)
1063{
1064	return register_printf_domain_render_std(NULL, specs);
1065}
1066#endif
1067
1068#ifdef VECTORS
1069/* vector support ----------------------------------------------------*/
1070
1071#define PRINTVECTOR(_io, _pi, _arg, _cnt, _type, _elem, _render, _ret) { \
1072	int i; \
1073	_type a, *ap; \
1074	a = (_type)(_arg)->_elem[0]; \
1075	ap = &a; \
1076	(_ret) += _render((_io), (_pi), (const void *)&ap); \
1077	for(i = 1; i < (_cnt); i++) { \
1078		(_ret) += __printf_puts((_io), (_pi)->begin, (_pi)->end - (_pi)->begin); \
1079		a = (_type)(_arg)->_elem[i]; \
1080		(_ret) += _render((_io), (_pi), (const void *)&ap); \
1081	} \
1082}
1083
1084#define PRINTVECTOR_P(_io, _pi, _arg, _cnt, _elem, _render, _ret) { \
1085	int i; \
1086	void * a, *ap; \
1087	a = (void *)(uintptr_t)(_arg)->_elem[0]; \
1088	ap = &a; \
1089	(_ret) += _render((_io), (_pi), (const void *)&ap); \
1090	for(i = 1; i < (_cnt); i++) { \
1091		(_ret) += __printf_puts((_io), (_pi)->begin, (_pi)->end - (_pi)->begin); \
1092		a = (void *)(uintptr_t)(_arg)->_elem[i]; \
1093		(_ret) += _render((_io), (_pi), (const void *)&ap); \
1094	} \
1095}
1096
1097__private_extern__ int
1098__xprintf_vector(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
1099{
1100	char vsep;	/* Vector separator character. */
1101	const union arg *argp;
1102	int ret = 0;
1103	struct printf_info info = *pi;
1104
1105	argp = arg[0];
1106	vsep = pi->vsep;
1107	if (vsep == 'X') {
1108		if (pi->spec == 'c')
1109			vsep = '\0';
1110		else
1111			vsep = ' ';
1112	}
1113	info.begin = info.end = &vsep;
1114	if (vsep) info.end++;
1115	info.is_vec = 0;
1116
1117	if (pi->is_short) {
1118		if (pi->spec == 'p') {
1119			PRINTVECTOR_P(io, &info, argp, 8, vushortarg, __printf_render_ptr, ret);
1120		} else {
1121			PRINTVECTOR(io, &info, argp, 8, unsigned int, vushortarg, __printf_render_int, ret);
1122		}
1123	} else if (pi->is_long) {
1124		info.is_long = 0;
1125		if (pi->spec == 'p') {
1126			PRINTVECTOR_P(io, &info, argp, 4, vuintarg, __printf_render_ptr, ret);
1127		} else {
1128			PRINTVECTOR(io, &info, argp, 4, unsigned int, vuintarg, __printf_render_int, ret);
1129		}
1130#ifdef V64TYPE
1131	} else if (pi->is_long_double) {
1132		switch (pi->spec) {
1133		case 'a':
1134		case 'A':
1135		case 'e':
1136		case 'E':
1137		case 'f':
1138		case 'g':
1139		case 'G':
1140			info.is_long_double = 0;
1141			PRINTVECTOR(io, &info, argp, 2, double, vdoublearg, __printf_render_float, ret);
1142			break;
1143		case 'p':
1144			info.is_long_double = 0;
1145			PRINTVECTOR_P(io, &info, argp, 2, vulonglongarg, __printf_render_ptr, ret);
1146			break;
1147		case 'd':
1148		case 'i':
1149		case 'u':
1150		case 'o':
1151		case 'x':
1152		case 'X':
1153			PRINTVECTOR(io, &info, argp, 2, unsigned long long, vulonglongarg, __printf_render_int, ret);
1154			break;
1155		default:
1156			/*
1157			 * The default case should never
1158			 * happen.
1159			 */
1160		case 'c':
1161			info.is_long_double = 0;
1162			PRINTVECTOR(io, &info, argp, 16, unsigned int, vuchararg, __printf_render_chr, ret);
1163		}
1164#endif /* V64TYPE */
1165	} else {
1166		switch (pi->spec) {
1167		case 'a':
1168		case 'A':
1169		case 'e':
1170		case 'E':
1171		case 'f':
1172		case 'g':
1173		case 'G':
1174			PRINTVECTOR(io, &info, argp, 4, double, vfloatarg, __printf_render_float, ret);
1175			break;
1176		default:
1177			/*
1178			 * The default case should never
1179			 * happen.
1180			 */
1181		case 'p':
1182			PRINTVECTOR_P(io, &info, argp, 16, vuchararg, __printf_render_ptr, ret);
1183			break;
1184		case 'd':
1185		case 'i':
1186		case 'u':
1187		case 'o':
1188		case 'x':
1189		case 'X':
1190			info.is_char = 1;
1191			PRINTVECTOR(io, &info, argp, 16, unsigned int, vuchararg, __printf_render_int, ret);
1192			break;
1193		case 'c':
1194			PRINTVECTOR(io, &info, argp, 16, unsigned int, vuchararg, __printf_render_chr, ret);
1195		}
1196	}
1197	return ret;
1198}
1199#endif /* VECTORS */
1200