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 */