2  * Copyright (c) 2005 Poul-Henning Kamp 
   3  * Copyright (c) 1990, 1993 
   4  *      The Regents of the University of California.  All rights reserved. 
   6  * This code is derived from software contributed to Berkeley by 
   9  * Redistribution and use in source and binary forms, with or without 
  10  * modification, are permitted provided that the following conditions 
  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. 
  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 
  33  * $FreeBSD: src/lib/libc/stdio/xprintf.c,v 1.9 2010/03/11 17:03:32 jhb Exp $ 
  36 #include "namespace.h" 
  38 #include <sys/types.h> 
  46 #include <namespace.h> 
  50 #include "un-namespace.h" 
  54 #include <mach/mach_time.h> 
  58 #include <libkern/OSAtomic.h> 
  59 #endif /* XPRINTF_PERF */ 
  62 #include "xprintf_private.h" 
  63 #include "xprintf_domain.h" 
  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. 
  74 int __use_xprintf 
= 0; 
  77 /* private stuff -----------------------------------------------------*/ 
  83 #ifndef NO_FLOATING_POINT 
  85         long double             longdoublearg
; 
  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]; 
 101         double                  vdoublearg
[2]; 
 102         unsigned long long      vulonglongarg
[2]; 
 103         long long               vlonglongarg
[2]; 
 109  * Macros for converting digits to letters and vice versa 
 111 #define to_digit(c)     ((c) - '0') 
 112 #define is_digit(c)     (((unsigned)to_digit(c)) <= 9) 
 114 /* various globals ---------------------------------------------------*/ 
 116 __private_extern__ 
const char __lowercase_hex
[17] = "0123456789abcdef?";        /*lint !e784 */ 
 117 __private_extern__ 
const char __uppercase_hex
[17] = "0123456789ABCDEF?";        /*lint !e784 */ 
 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'}; 
 125 /* printing and padding functions ------------------------------------*/ 
 132         struct __siov   iov
[NIOV
]; 
 137 __printf_init(struct __printf_io 
*io
) 
 140         io
->uio
.uio_iov 
= io
->iovp 
= &io
->iov
[0]; 
 141         io
->uio
.uio_resid 
= 0; 
 142         io
->uio
.uio_iovcnt 
= 0; 
 145 __private_extern__ 
void 
 146 __printf_flush(struct __printf_io 
*io
) 
 149         __sfvwrite(io
->fp
, &io
->uio
); 
 153 __private_extern__ 
int 
 154 __printf_puts(struct __printf_io 
*io
, const void *ptr
, int len
) 
 159         if (io
->fp
->_flags 
& __SERR
) 
 164         io
->iovp
->iov_base 
= __DECONST(void *, ptr
); 
 165         io
->iovp
->iov_len 
= len
; 
 166         io
->uio
.uio_resid 
+= len
; 
 168         io
->uio
.uio_iovcnt
++; 
 169         if (io
->uio
.uio_iovcnt 
>= NIOV
) 
 174 __private_extern__ 
int 
 175 __printf_pad(struct __printf_io 
*io
, int howmany
, int zero
) 
 186         if ((n 
= (howmany
)) > 0) { 
 187                 while (n 
> PADSIZE
) {  
 188                         ret 
+= __printf_puts(io
, with
, PADSIZE
); 
 191                 ret 
+= __printf_puts(io
, with
, n
); 
 196 __private_extern__ 
int 
 197 __printf_out(struct __printf_io 
*io
, const struct printf_info 
*pi
, const void *ptr
, int len
) 
 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'); 
 210 /* percent handling  -------------------------------------------------*/ 
 212 __private_extern__ 
int 
 213 __printf_arginfo_pct(const struct printf_info 
*pi __unused
, size_t n __unused
, int *argt __unused
) 
 219 __private_extern__ 
int 
 220 __printf_render_pct(struct __printf_io 
*io
, const struct printf_info 
*pi __unused
, const void *const *arg __unused
) 
 223         return (__printf_puts(io
, "%", 1)); 
 226 /* 'n' ---------------------------------------------------------------*/ 
 228 __private_extern__ 
int 
 229 __printf_arginfo_n(const struct printf_info 
*pi
, size_t n
, int *argt
) 
 233         argt
[0] = PA_POINTER
; 
 238  * This is a printf_render so that all output has been flushed before it 
 242 __private_extern__ 
int 
 243 __printf_render_n(FILE *io __unused
, const struct printf_info 
*pi
, const void *const *arg
) 
 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
; 
 263                 **((int **)arg
[0]) = pi
->sofar
; 
 268 /* dynamic array handling  -------------------------------------------------*/ 
 274 #endif /* XPRINTF_PERF */ 
 282 #else /* !XPRINTF_PERF */ 
 284 #endif /* !XPRINTF_PERF */ 
 286 arrayfree(struct array 
*a
) 
 292 arrayget(struct array 
*a
, int i
) 
 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
); 
 304         return a
->data 
+ i 
* a
->itemsize
; 
 307 static struct array 
* 
 308 arrayinit(struct array 
*a
, int itemsize
) 
 310         a
->data 
= CALLOC(ARRAYDELTA
, itemsize
); 
 311         if(!a
->data
) return NULL
; 
 312         a
->itemsize 
= itemsize
; 
 317 /* dynamic array caching  -------------------------------------------------*/ 
 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. 
 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. 
 332  * However, we do flush these caches in case we every are unable to allocate 
 333  * memory, and retry the allocation, just in case. 
 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
; 
 340 #define DEFINE_DEQUEUE(which, type) \ 
 341 static struct array * \ 
 342 which ## _dequeue(void) \ 
 344         struct array *a = (struct array *)OSAtomicDequeue(&which ## _queue, offsetof(struct array, next)); \ 
 347                 bzero(a->data, a->max * a->itemsize); \ 
 350         a = (struct array *)MALLOC(sizeof(*a)); \ 
 351         if (!a) return NULL; \ 
 352         if (!arrayinit(a, sizeof(type))) { \ 
 359 #define DEFINE_ENQUEUE(which) \ 
 360 __private_extern__ void \ 
 361 which ## _enqueue(struct array *a) \ 
 364         OSAtomicEnqueue(&which ## _queue, a, offsetof(struct array, next)); \ 
 367 #define DEFINE_FLUSH(which) \ 
 369 which ## _flush(void) \ 
 372         while((a = (struct array *)OSAtomicDequeue(&which ## _queue, offsetof(struct array, next))) != NULL) { \ 
 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
) 
 396 __private_extern__ 
void * 
 397 xprintf_calloc(size_t count
, size_t size
) 
 399     void *x 
= calloc(count
, size
); 
 402         x 
= calloc(count
, size
); 
 407 __private_extern__ 
void * 
 408 xprintf_malloc(size_t size
) 
 410     void *x 
= malloc(size
); 
 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
); 
 432 #endif /* XPRINTF_PERF */ 
 434 /* -------------------------------------------------------------------------*/ 
 436 __private_extern__ 
int 
 437 __printf_comp(printf_comp_t restrict pc
, printf_domain_t restrict domain
) 
 439         struct printf_info      
*pi
, *pil
; 
 448         struct array            piarr
, argtarr
; 
 449 #endif /* XPRINTF_PERF */ 
 450         struct array            
*pa
, *aa
; 
 456         pa 
= printf_info_dequeue(); 
 457 #else /* !XPRINTF_PERF */ 
 458         pa 
= arrayinit(&piarr
, sizeof(*pi
)); 
 459 #endif /* !XPRINTF_PERF */ 
 463 #endif /* XPRINTF_PERF */ 
 468         aa 
= arg_type_dequeue(); 
 469 #else /* !XPRINTF_PERF */ 
 470         aa 
= arrayinit(&argtarr
, sizeof(*argt
)); 
 471 #endif /* !XPRINTF_PERF */ 
 477 #endif /* XPRINTF_PERF */ 
 482 #endif /* XPRINTF_PERF */ 
 483         for (pii 
= 0; ; pii
++) { 
 484                 pi 
= arrayget(pa
, pii
); 
 496                 pi
->vsep 
= 'X'; /* Illegal value, changed to defaults later. */ 
 498                 pi
->begin 
= pi
->end 
= fmt
; 
 499                 while (*fmt 
!= '\0' && *fmt 
!= '%') 
 509                                  * ``If the space and + flags both appear, the space 
 510                                  * flag will be ignored.'' 
 513                                 if (pi
->showsign 
== 0) { 
 524                         case ',': case ';': case ':': case '_': 
 534                                         /* Look for *nn$ and deal with it */ 
 536                                         while (*fmt 
!= '\0' && is_digit(*fmt
)) { 
 542                                                 if ((n 
+ 1) > maxarg
) 
 545                                         } else n 
= nextarg
++; 
 547                                         argt 
= (int *)arrayget(aa
, n
); 
 555                                 while (*fmt 
!= '\0' && is_digit(*fmt
)) { 
 557                                         pi
->prec 
+= to_digit(*fmt
); 
 572                                 /* Look for *nn$ and deal with it */ 
 574                                 while (*fmt 
!= '\0' && is_digit(*fmt
)) { 
 580                                         if ((n 
+ 1) > maxarg
) 
 583                                 } else n 
= nextarg
++; 
 585                                 argt 
= (int *)arrayget(aa
, n
); 
 601                                  * ``Note that 0 is taken as a flag, not as the 
 602                                  * beginning of a field width.'' 
 608                         case '1': case '2': case '3': 
 609                         case '4': case '5': case '6': 
 610                         case '7': case '8': case '9': 
 612                                 while (*fmt 
!= '\0' && is_digit(*fmt
)) { 
 618                                         if (nextarg 
> maxarg
) 
 629                                 pi
->spec 
+= ('a' - 'A'); 
 631                                 if (pi
->is_long_double 
|| pi
->is_quad
) { 
 633                                         pi
->is_long_double 
= 1; 
 636                                         pi
->is_long_double 
= 0; 
 651                                 pi
->is_long_double 
= 1; 
 667                                         pi
->is_long_double 
= 1; 
 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
: 
 700                                          * Insure that there are always 
 701                                          * __PRINTFMAXARG available. 
 703                                         if (!arrayget(aa
, nextarg 
+ __PRINTFMAXARG 
- 1)) { 
 707                                         pi
->context 
= domain
->tbl
[printf_tbl_index(pi
->spec
)].context
; 
 709                                         ch 
= domain
->tbl
[printf_tbl_index(pi
->spec
)].arginfo( 
 710                                             pi
, __PRINTFMAXARG
, arrayget(aa
, nextarg
)); 
 712                                                 pi
->arg
[0] = (void *)(long)nextarg
; 
 714                                                 pi
->arg
[1] = (void *)(long)(nextarg 
+ 1); 
 722         if (nextarg 
> maxarg
) 
 727         pc
->maxarg 
= ch 
= maxarg
; 
 730         pc
->ua 
= union_arg_dequeue(); 
 735         if (!arrayget(pc
->ua
, ch
)) { 
 736             union_arg_enqueue(pc
->ua
); 
 740         pc
->args 
= pc
->ua
->data
; 
 741 #else /* !XPRINTF_PERF */ 
 742         pc
->args 
= (union arg 
*)malloc(ch 
* sizeof(*pc
->args
)); 
 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]]; 
 753         fprintf(stderr
, "fmt0 <%s>\n", fmt0
); 
 754         fprintf(stderr
, "pil %p\n", pil
); 
 766 #endif /* XPRINTF_PERF */ 
 770 __private_extern__ 
int 
 771 __printf_exec(printf_comp_t restrict pc
, FILE * restrict fp
, va_list ap
) 
 773         struct printf_info      
*pi
; 
 777         struct __printf_io      io
; 
 782         for (ch 
= 1; ch 
< pc
->maxarg
; ch
++) { 
 784                 fprintf(stderr
, "arg %d %x\n", ch
, pc
->argt
[ch
]); 
 786                 switch(pc
->argt
[ch
]) { 
 788                         pc
->args
[ch
].intarg 
= (char)va_arg (ap
, int); 
 791                         pc
->args
[ch
].intarg 
= va_arg (ap
, int); 
 793                 case PA_INT 
| PA_FLAG_SHORT
: 
 794                         pc
->args
[ch
].intarg 
= (short)va_arg (ap
, int); 
 796                 case PA_INT 
| PA_FLAG_LONG
: 
 797                         pc
->args
[ch
].longarg 
= va_arg (ap
, long); 
 799                 case PA_INT 
| PA_FLAG_INTMAX
: 
 800                         pc
->args
[ch
].intmaxarg 
= va_arg (ap
, intmax_t); 
 802                 case PA_INT 
| PA_FLAG_QUAD
: 
 803                         pc
->args
[ch
].intmaxarg 
= va_arg (ap
, quad_t
); 
 805                 case PA_INT 
| PA_FLAG_LONG_LONG
: 
 806                         pc
->args
[ch
].intmaxarg 
= va_arg (ap
, long long); 
 808                 case PA_INT 
| PA_FLAG_SIZE
: 
 809                         pc
->args
[ch
].intmaxarg 
= va_arg (ap
, size_t); 
 811                 case PA_INT 
| PA_FLAG_PTRDIFF
: 
 812                         pc
->args
[ch
].intmaxarg 
= (unsigned long)va_arg (ap
, ptrdiff_t); 
 815                         pc
->args
[ch
].wintarg 
= va_arg (ap
, wint_t); 
 818                         pc
->args
[ch
].pvoidarg 
= va_arg (ap
, void *); 
 821                         pc
->args
[ch
].pchararg 
= va_arg (ap
, char *); 
 824                         pc
->args
[ch
].pwchararg 
= va_arg (ap
, wchar_t *); 
 827 #ifndef NO_FLOATING_POINT 
 828                         pc
->args
[ch
].doublearg 
= va_arg (ap
, double); 
 831                 case PA_DOUBLE 
| PA_FLAG_LONG_DOUBLE
: 
 832 #ifndef NO_FLOATING_POINT 
 833                         pc
->args
[ch
].longdoublearg 
= va_arg (ap
, long double); 
 838                         pc
->args
[ch
].vectorarg 
= va_arg (ap
, VECTORTYPE
); 
 842                         errx(1, "argtype = %x (fmt = \"%s\")\n", 
 843                             pc
->argt
[ch
], pc
->fmt
); 
 846         for (pi 
= pc
->pi
; pi 
< pc
->pil
; pi
++) { 
 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
); 
 866                         pi
->width 
= pc
->args
[pi
->get_width
].intarg
; 
 868                          * ``A negative field width argument is taken as a 
 869                          * - flag followed by a positive field width.'' 
 871                          * They don't exclude field widths read from args. 
 875                                 pi
->width 
= -pi
->width
; 
 879                         pi
->prec 
= pc
->args
[pi
->get_prec
].intarg
; 
 880                 ret 
+= __printf_puts(&io
, pi
->begin
, pi
->end 
- pi
->begin
); 
 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
: 
 887                                 char unknown 
= pi
->spec
; 
 888                                 ret 
+= __printf_out(&io
, pi
, &unknown
, 1); 
 891                         case PRINTF_DOMAIN_GLIBC_API
: 
 894                                 ret 
+= ((printf_function 
*)pc
->domain
->tbl
[printf_tbl_index(pi
->spec
)].render
)( 
 895                                     fp
, pi
, (const void *)pi
->arg
); 
 897                         case PRINTF_DOMAIN_FBSD_API
: 
 899                                 n 
= ((printf_render 
*)pc
->domain
->tbl
[printf_tbl_index(pi
->spec
)].render
)( 
 900                                     &io
, pi
, (const void *)pi
->arg
); 
 902                                         io
.fp
->_flags 
|= __SERR
; 
 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
) 
 916         struct _printf_compiled spc
; 
 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. 
 924         /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 
 925         if (prepwrite(fp
) != 0) { 
 931         if (pc 
== XPRINTF_PLAIN
) { 
 932                 NORMALIZE_LOCALE(loc
); 
 936                                     return __vfprintf(fp
, loc
, fmt
, ap
); 
 938                 xprintf_domain_init(); 
 939                 domain 
= xprintf_domain_global
; 
 942             pthread_mutex_lock(&pc
->mutex
); 
 943             pthread_rwlock_rdlock(&pc
->domain
->rwlock
); 
 944             ret 
= __printf_exec(pc
, fp
, ap
); 
 946             pthread_rwlock_unlock(&pc
->domain
->rwlock
); 
 947             pthread_mutex_unlock(&pc
->mutex
); 
 955         xprintf_domain_init(); 
 956         bzero(&spc
, sizeof(spc
)); 
 958         DEFAULT_CURRENT_LOCALE(loc
); 
 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. 
 965         pthread_rwlock_rdlock(&domain
->rwlock
); 
 966         if (__printf_comp(&spc
, domain
) < 0) { 
 968             pthread_rwlock_unlock(&domain
->rwlock
); 
 973         ret 
= __printf_exec(&spc
, fp
, ap
); 
 975         pthread_rwlock_unlock(&domain
->rwlock
); 
 979         printf_info_enqueue(spc
.pa
); 
 980         arg_type_enqueue(spc
.aa
); 
 981         union_arg_enqueue(spc
.ua
); 
 982 #else /* !XPRINTF_PERF */ 
 986 #endif /* !XPRINTF_PERF */ 
 991 extern int      __fflush(FILE *fp
); 
 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. 
 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
) 
1003         struct __sFILEX extra
; 
1004         unsigned char buf
[BUFSIZ
]; 
1006         fake
._extra 
= &extra
; 
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
; 
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 */ 
1022         /* do the work, then copy any error status */ 
1023         ret 
= __v2printf(pc
, domain
, &fake
, loc
, fmt
, ap
); 
1024         if (ret 
>= 0 && __fflush(&fake
)) 
1026         if (fake
._flags 
& __SERR
) 
1027                 fp
->_flags 
|= __SERR
; 
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
) 
1036         /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 
1037         if ((fp
->_flags 
& (__SNBF
|__SWR
|__SRW
)) == (__SNBF
|__SWR
) && 
1039                 ret 
= __v3printf(pc
, domain
, fp
, loc
, fmt0
, ap
); 
1041                 ret 
= __v2printf(pc
, domain
, fp
, loc
, fmt0
, ap
); 
1045 /* extending ---------------------------------------------------------*/ 
1047 // No global domain support 
1050 register_printf_function(int spec
, printf_function 
*render
, printf_arginfo_function 
*arginfo
) 
1052         return register_printf_domain_function(NULL
, spec
, render
, arginfo
); 
1055 __private_extern__ 
int 
1056 register_printf_render(int spec
, printf_render 
*render
, printf_arginfo_function 
*arginfo
) 
1058         return register_printf_domain_render(NULL
, spec
, render
, arginfo
); 
1062 register_printf_render_std(const char *specs
) 
1064         return register_printf_domain_render_std(NULL
, specs
); 
1069 /* vector support ----------------------------------------------------*/ 
1071 #define PRINTVECTOR(_io, _pi, _arg, _cnt, _type, _elem, _render, _ret) { \ 
1074         a = (_type)(_arg)->_elem[0]; \ 
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); \ 
1084 #define PRINTVECTOR_P(_io, _pi, _arg, _cnt, _elem, _render, _ret) { \ 
1087         a = (void *)(uintptr_t)(_arg)->_elem[0]; \ 
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); \ 
1097 __private_extern__ 
int 
1098 __xprintf_vector(struct __printf_io 
*io
, const struct printf_info 
*pi
, const void *const *arg
) 
1100         char vsep
;      /* Vector separator character. */ 
1101         const union arg 
*argp
; 
1103         struct printf_info info 
= *pi
; 
1108                 if (pi
->spec 
== 'c') 
1113         info
.begin 
= info
.end 
= &vsep
; 
1114         if (vsep
) info
.end
++; 
1118                 if (pi
->spec 
== 'p') { 
1119                         PRINTVECTOR_P(io
, &info
, argp
, 8, vushortarg
, __printf_render_ptr
, ret
); 
1121                         PRINTVECTOR(io
, &info
, argp
, 8, unsigned int, vushortarg
, __printf_render_int
, ret
); 
1123         } else if (pi
->is_long
) { 
1125                 if (pi
->spec 
== 'p') { 
1126                         PRINTVECTOR_P(io
, &info
, argp
, 4, vuintarg
, __printf_render_ptr
, ret
); 
1128                         PRINTVECTOR(io
, &info
, argp
, 4, unsigned int, vuintarg
, __printf_render_int
, ret
); 
1131         } else if (pi
->is_long_double
) { 
1140                         info
.is_long_double 
= 0; 
1141                         PRINTVECTOR(io
, &info
, argp
, 2, double, vdoublearg
, __printf_render_float
, ret
); 
1144                         info
.is_long_double 
= 0; 
1145                         PRINTVECTOR_P(io
, &info
, argp
, 2, vulonglongarg
, __printf_render_ptr
, ret
); 
1153                         PRINTVECTOR(io
, &info
, argp
, 2, unsigned long long, vulonglongarg
, __printf_render_int
, ret
); 
1157                          * The default case should never 
1161                         info
.is_long_double 
= 0; 
1162                         PRINTVECTOR(io
, &info
, argp
, 16, unsigned int, vuchararg
, __printf_render_chr
, ret
); 
1164 #endif /* V64TYPE */ 
1174                         PRINTVECTOR(io
, &info
, argp
, 4, double, vfloatarg
, __printf_render_float
, ret
); 
1178                          * The default case should never 
1182                         PRINTVECTOR_P(io
, &info
, argp
, 16, vuchararg
, __printf_render_ptr
, ret
); 
1191                         PRINTVECTOR(io
, &info
, argp
, 16, unsigned int, vuchararg
, __printf_render_int
, ret
); 
1194                         PRINTVECTOR(io
, &info
, argp
, 16, unsigned int, vuchararg
, __printf_render_chr
, ret
); 
1199 #endif /* VECTORS */