]> git.saurik.com Git - apple/libc.git/blob - stdio/FreeBSD/xprintf.c
Libc-1044.1.2.tar.gz
[apple/libc.git] / stdio / FreeBSD / xprintf.c
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>
74 int __use_xprintf = 0;
75 #endif
76
77 /* private stuff -----------------------------------------------------*/
78
79 union 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
120 static char blanks[PADSIZE] =
121 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
122 static 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
129 struct __printf_io {
130 FILE *fp;
131 struct __suio uio;
132 struct __siov iov[NIOV];
133 struct __siov *iovp;
134 };
135
136 static 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
271 struct 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 */
283 static
284 #endif /* !XPRINTF_PERF */
285 void
286 arrayfree(struct array *a)
287 {
288 if(a) free(a->data);
289 }
290
291 static void *
292 arrayget(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
307 static struct array *
308 arrayinit(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
336 static OSQueueHead arg_type_queue = OS_ATOMIC_QUEUE_INIT;
337 static OSQueueHead printf_info_queue = OS_ATOMIC_QUEUE_INIT;
338 static OSQueueHead union_arg_queue = OS_ATOMIC_QUEUE_INIT;
339
340 #define DEFINE_DEQUEUE(which, type) \
341 static struct array * \
342 which ## _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 \
361 which ## _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) \
368 static void \
369 which ## _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
378 DEFINE_DEQUEUE(arg_type, int)
379 DEFINE_ENQUEUE(arg_type)
380 DEFINE_FLUSH(arg_type)
381 DEFINE_DEQUEUE(printf_info, struct printf_info)
382 DEFINE_ENQUEUE(printf_info)
383 DEFINE_FLUSH(printf_info)
384 DEFINE_DEQUEUE(union_arg, union arg)
385 DEFINE_ENQUEUE(union_arg)
386 DEFINE_FLUSH(union_arg)
387
388 static void
389 flush_queues(void)
390 {
391 arg_type_flush();
392 printf_info_flush();
393 union_arg_flush();
394 }
395
396 __private_extern__ void *
397 xprintf_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 *
408 xprintf_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
419 void
420 show_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);
759 error:
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
991 extern 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 */
998 static 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
1049 int
1050 register_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
1056 register_printf_render(int spec, printf_render *render, printf_arginfo_function *arginfo)
1057 {
1058 return register_printf_domain_render(NULL, spec, render, arginfo);
1059 }
1060
1061 int
1062 register_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 */