1 /* Copyright (C) 2002-2004 Manuel Novoa III
2 * My stdio library for linux and (soon) elks.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* This code needs a lot of clean up. Some of that is on hold until uClibc
20 * gets a better configuration system (on Erik's todo list).
21 * The other cleanup will take place during the implementation/integration of
22 * the wide char (un)formatted i/o functions which I'm currently working on.
25 /* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION!
27 * This code is currently under development. Also, I plan to port
28 * it to elks which is a 16-bit environment with a fairly limited
29 * compiler. Therefore, please refrain from modifying this code
30 * and, instead, pass any bug-fixes, etc. to me. Thanks. Manuel
32 * ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! */
36 * Initialize thread locks for fake files in vsnprintf and vdprintf.
37 * reported by Erik Andersen (andersen@codepoet.com)
38 * Fix an arg promotion handling bug in _do_one_spec for %c.
39 * reported by Ilguiz Latypov <ilatypov@superbt.com>
42 * Remove __isdigit and use new ctype.h version.
43 * Add conditional setting of QUAL_CHARS for size_t and ptrdiff_t.
46 * Fix two problems that showed up with the python 2.2.1 tests; one
47 * involving %o and one involving %f.
50 * Fix a problem in vasprintf (reported by vodz a while back) when built
51 * without custom stream support. In that case, it is necessary to do
53 * Make sure each va_copy has a matching va_end, as required by C99.
56 * Add locale-specific grouping support for integer decimal conversion.
57 * Add locale-specific decimal point support for floating point conversion.
58 * Note: grouping will have to wait for _dtostr() rewrite.
59 * Add printf wchar support for %lc (%C) and %ls (%S).
60 * Require printf format strings to be valid multibyte strings beginning and
61 * ending in their initial shift state, as per the stds.
64 * Add *wprintf functions. Currently they don't support floating point
65 * conversions. That will wait until the rewrite of _dtostr.
68 * Optional hexadecimal float notation support for %a/%A.
69 * Floating point output now works for *wprintf.
70 * Support for glibc locale-specific digit grouping for floats.
74 * Fix precision bug for %g conversion specifier when using %f style.
77 * Implement *s*scanf for the non-buffered stdio case with old_vfprintf.
80 * vfprintf was not always checking for narrow stream orientation.
85 * Should we validate that *printf format strings are valid multibyte
86 * strings in the current locale? ANSI/ISO C99 seems to imply this
87 * and Plauger's printf implementation in his Standard C Library book
88 * treats this as an error.
91 #define _ISOC99_SOURCE /* for ULLONG primarily... */
106 #ifdef __UCLIBC_HAS_THREADS__
107 #include <stdio_ext.h>
109 #endif /* __UCLIBC_HAS_THREADS__ */
111 #ifdef __UCLIBC_HAS_WCHAR__
113 #endif /* __UCLIBC_HAS_WCHAR__ */
115 #include <bits/uClibc_uintmaxtostr.h>
116 #include <bits/uClibc_va_copy.h>
118 /* Experimentally off - libc_hidden_proto(memcpy) */
119 /* Experimentally off - libc_hidden_proto(memset) */
120 /* Experimentally off - libc_hidden_proto(strlen) */
121 /* Experimentally off - libc_hidden_proto(strnlen) */
122 libc_hidden_proto(__glibc_strerror_r)
123 libc_hidden_proto(fputs_unlocked)
124 libc_hidden_proto(abort)
125 #ifdef __UCLIBC_HAS_WCHAR__
126 libc_hidden_proto(wcslen)
127 libc_hidden_proto(wcsnlen)
128 libc_hidden_proto(mbsrtowcs)
129 libc_hidden_proto(wcsrtombs)
130 libc_hidden_proto(btowc)
131 libc_hidden_proto(wcrtomb)
132 libc_hidden_proto(fputws)
135 /* Some older or broken gcc toolchains define LONG_LONG_MAX but not
136 * LLONG_MAX. Since LLONG_MAX is part of the standard, that's what
137 * we use. So complain if we do not have it but should.
139 #if !defined(LLONG_MAX) && defined(LONG_LONG_MAX)
140 #error Apparently, LONG_LONG_MAX is defined but LLONG_MAX is not. You need to fix your toolchain headers to support the standard macros for (unsigned) long long.
143 /**********************************************************************/
144 /* These provide some control over printf's feature set */
146 /* This is undefined below depeding on uClibc's configuration. */
147 #define __STDIO_PRINTF_FLOAT 1
149 /* Now controlled by uClibc_stdio.h. */
150 /* #define __UCLIBC_HAS_PRINTF_M_SPEC__ */
153 /**********************************************************************/
155 #if defined(__UCLIBC__) && !defined(__UCLIBC_HAS_FLOATS__)
156 #undef __STDIO_PRINTF_FLOAT
160 #undef __STDIO_PRINTF_FLOAT
163 #ifdef __STDIO_PRINTF_FLOAT
165 #include <bits/uClibc_fpmax.h>
166 #else /* __STDIO_PRINTF_FLOAT */
168 #endif /* __STDIO_PRINTF_FLOAT */
171 #undef __STDIO_HAS_VSNPRINTF
172 #if defined(__STDIO_BUFFERS) || defined(__USE_OLD_VFPRINTF__) || defined(__UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__)
173 #define __STDIO_HAS_VSNPRINTF 1
176 /**********************************************************************/
178 /* Now controlled by uClibc_stdio.h. */
179 /* #define __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
181 /* TODO -- move these to a configuration section? */
182 #define MAX_FIELD_WIDTH 4095
184 #ifdef __UCLIBC_MJN3_ONLY__
185 #ifdef L_register_printf_function
187 #warning WISHLIST: Make MAX_USER_SPEC configurable?
188 #warning WISHLIST: Make MAX_ARGS_PER_SPEC configurable?
190 #endif /* __UCLIBC_MJN3_ONLY__ */
192 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
194 #define MAX_USER_SPEC 10
195 #define MAX_ARGS_PER_SPEC 5
197 #else /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
200 #define MAX_ARGS_PER_SPEC 1
202 #endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
204 #if MAX_ARGS_PER_SPEC < 1
205 #error MAX_ARGS_PER_SPEC < 1!
206 #undef MAX_ARGS_PER_SPEC
207 #define MAX_ARGS_PER_SPEC 1
210 #if defined(NL_ARGMAX) && (NL_ARGMAX < 9)
211 #error NL_ARGMAX < 9!
214 #if defined(NL_ARGMAX) && (NL_ARGMAX >= (MAX_ARGS_PER_SPEC + 2))
215 #define MAX_ARGS NL_ARGMAX
217 /* N for spec itself, plus 1 each for width and precision */
218 #define MAX_ARGS (MAX_ARGS_PER_SPEC + 2)
221 /**********************************************************************/
223 #define __PA_FLAG_INTMASK \
224 (__PA_FLAG_CHAR|PA_FLAG_SHORT|__PA_FLAG_INT|PA_FLAG_LONG|PA_FLAG_LONG_LONG)
226 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
227 extern printf_function _custom_printf_handler[MAX_USER_SPEC] attribute_hidden;
228 extern printf_arginfo_function *_custom_printf_arginfo[MAX_USER_SPEC] attribute_hidden;
229 extern char *_custom_printf_spec attribute_hidden;
230 #endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
232 /**********************************************************************/
234 #define SPEC_FLAGS " +0-#'I"
237 FLAG_PLUS = 0x02, /* must be 2 * FLAG_SPACE */
239 FLAG_MINUS = 0x08, /* must be 2 * FLAG_ZERO */
241 FLAG_THOUSANDS = 0x20,
242 FLAG_I18N = 0x40, /* only works for d, i, u */
243 FLAG_WIDESTREAM = 0x80
246 /**********************************************************************/
248 /* float layout 01234567890123456789 TODO: B?*/
249 #define SPEC_CHARS "npxXoudifFeEgGaACScs"
253 CONV_x, CONV_X, CONV_o, CONV_u, CONV_d, CONV_i,
254 CONV_f, CONV_F, CONV_e, CONV_E, CONV_g, CONV_G, CONV_a, CONV_A,
255 CONV_C, CONV_S, CONV_c, CONV_s,
256 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
259 CONV_custom0 /* must be last */
263 #define SPEC_BASE { 16, 16, 16, 8, 10, 10, 10 }
265 #define SPEC_RANGES { CONV_n, CONV_p, CONV_i, CONV_A, \
266 CONV_C, CONV_S, CONV_c, CONV_s, CONV_custom0 }
268 #define SPEC_OR_MASK { \
269 /* n */ (PA_FLAG_PTR|PA_INT), \
270 /* p */ PA_POINTER, \
271 /* oxXudi */ PA_INT, \
272 /* fFeEgGaA */ PA_DOUBLE, \
274 /* S */ PA_WSTRING, \
279 #define SPEC_AND_MASK { \
280 /* n */ (PA_FLAG_PTR|__PA_INTMASK), \
281 /* p */ PA_POINTER, \
282 /* oxXudi */ (__PA_INTMASK), \
283 /* fFeEgGaA */ (PA_FLAG_LONG_DOUBLE|PA_DOUBLE), \
284 /* C */ (PA_WCHAR), \
285 /* S */ (PA_WSTRING), \
287 /* s */ (PA_STRING), \
290 /**********************************************************************/
292 * In order to ease translation to what arginfo and _print_info._flags expect,
293 * we map: 0:int 1:char 2:longlong 4:long 8:short
294 * and then _flags |= (((q << 7) + q) & 0x701) and argtype |= (_flags & 0x701)
297 /* TODO -- Fix the table below to take into account stdint.h. */
298 /* #ifndef LLONG_MAX */
299 /* #error fix QUAL_CHARS for no long long! Affects 'L', 'j', 'q', 'll'. */
301 /* #if LLONG_MAX != INTMAX_MAX */
302 /* #error fix QUAL_CHARS intmax_t entry 'j'! */
307 #error PDS already defined!
310 #error SS already defined!
313 #error IMS already defined!
316 #if PTRDIFF_MAX == INT_MAX
318 #elif PTRDIFF_MAX == LONG_MAX
320 #elif defined(LLONG_MAX) && (PTRDIFF_MAX == LLONG_MAX)
323 #error fix QUAL_CHARS ptrdiff_t entry 't'!
326 #if SIZE_MAX == UINT_MAX
328 #elif SIZE_MAX == ULONG_MAX
330 #elif defined(LLONG_MAX) && (SIZE_MAX == ULLONG_MAX)
333 #error fix QUAL_CHARS size_t entries 'z', 'Z'!
336 #if INTMAX_MAX == INT_MAX
338 #elif INTMAX_MAX == LONG_MAX
340 #elif defined(LLONG_MAX) && (INTMAX_MAX == LLONG_MAX)
343 #error fix QUAL_CHARS intmax_t entry 'j'!
346 #define QUAL_CHARS { \
347 /* j:(u)intmax_t z:(s)size_t t:ptrdiff_t \0:int */ \
348 /* q:long_long Z:(s)size_t */ \
349 'h', 'l', 'L', 'j', 'z', 't', 'q', 'Z', 0, \
350 2, 4, 8, IMS, SS, PDS, 8, SS, 0, /* TODO -- fix!!! */\
354 /**********************************************************************/
356 #ifdef __STDIO_VA_ARG_PTR
358 #define __va_arg_ptr(ap,type) (((type *)(ap += sizeof(type))) - 1)
363 /* TODO -- need other than for 386 as well! */
365 #ifndef __va_rounded_size
366 #define __va_rounded_size(TYPE) \
367 (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
369 #define __va_arg_ptr(AP, TYPE) \
370 (AP = (va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \
371 ((void *) ((char *) (AP) - __va_rounded_size (TYPE))))
374 #endif /* __STDIO_VA_ARG_PTR */
377 #define GET_VA_ARG(AP,F,TYPE,ARGS) (*(AP) = __va_arg_ptr(ARGS,TYPE))
378 #define GET_ARG_VALUE(AP,F,TYPE) (*((TYPE *)(*(AP))))
385 unsigned long long ull;
387 #ifdef __STDIO_PRINTF_FLOAT
390 #endif /* __STDIO_PRINTF_FLOAT */
394 #define GET_VA_ARG(AU,F,TYPE,ARGS) (AU->F = va_arg(ARGS,TYPE))
395 #define GET_ARG_VALUE(AU,F,TYPE) ((TYPE)((AU)->F))
399 const char *fmtpos; /* TODO: move below struct?? */
400 struct printf_info info;
402 int maxposarg; /* > 0 if args are positional, 0 if not, -1 if unknown */
403 #endif /* NL_ARGMAX */
404 int num_data_args; /* TODO: use sentinal??? */
405 unsigned int conv_num;
406 unsigned char argnumber[4]; /* width | prec | 1st data | unused */
407 int argtype[MAX_ARGS];
410 void *argptr[MAX_ARGS];
412 /* if defined(NL_ARGMAX) || defined(__UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__) */
413 /* While this is wasteful of space in the case where pos args aren't
414 * enabled, it is also needed to support custom printf handlers. */
415 argvalue_t argvalue[MAX_ARGS];
417 } ppfs_t; /* parse printf format state */
419 /**********************************************************************/
421 /* TODO: fix printf to return 0 and set errno if format error. Standard says
422 only returns -1 if sets error indicator for the stream. */
424 #ifdef __STDIO_PRINTF_FLOAT
425 typedef size_t (__fp_outfunc_t)(FILE *fp, intptr_t type, intptr_t len,
428 extern ssize_t _fpmaxtostr(FILE * fp, __fpmax_t x, struct printf_info *info,
429 __fp_outfunc_t fp_outfunc) attribute_hidden;
432 extern int _ppfs_init(ppfs_t *ppfs, const char *fmt0) attribute_hidden; /* validates */
433 extern void _ppfs_prepargs(ppfs_t *ppfs, va_list arg) attribute_hidden; /* sets posargptrs */
434 extern void _ppfs_setargs(ppfs_t *ppfs) attribute_hidden; /* sets argptrs for current spec */
435 extern int _ppfs_parsespec(ppfs_t *ppfs) attribute_hidden; /* parses specifier */
437 extern void _store_inttype(void *dest, int desttype, uintmax_t val) attribute_hidden;
438 extern uintmax_t _load_inttype(int desttype, const void *src, int uflag) attribute_hidden;
440 /**********************************************************************/
441 #ifdef L_parse_printf_format
443 /* NOTE: This function differs from the glibc version in that parsing stops
444 * upon encountering an invalid conversion specifier. Since this is the way
445 * my printf functions work, I think it makes sense to do it that way here.
446 * Unfortunately, since glibc sets the return type as size_t, we have no way
447 * of returning that the template is illegal, other than returning 0.
450 size_t parse_printf_format(register const char *template,
451 size_t n, register int *argtypes)
457 if (_ppfs_init(&ppfs, template) >= 0) {
459 if (ppfs.maxposarg > 0) { /* Using positional args. */
460 count = ppfs.maxposarg;
464 for (i = 0 ; i < n ; i++) {
465 *argtypes++ = ppfs.argtype[i];
467 } else { /* Not using positional args. */
468 #endif /* NL_ARGMAX */
470 if ((*template == '%') && (*++template != '%')) {
471 ppfs.fmtpos = template;
472 _ppfs_parsespec(&ppfs); /* Can't fail. */
473 template = ppfs.fmtpos; /* Update to one past spec end. */
474 if (ppfs.info.width == INT_MIN) {
477 *argtypes++ = PA_INT;
481 if (ppfs.info.prec == INT_MIN) {
484 *argtypes++ = PA_INT;
488 for (i = 0 ; i < ppfs.num_data_args ; i++) {
489 if ((ppfs.argtype[i]) != __PA_NOARG) {
492 *argtypes++ = ppfs.argtype[i];
503 #endif /* NL_ARGMAX */
510 /**********************************************************************/
513 int attribute_hidden _ppfs_init(register ppfs_t *ppfs, const char *fmt0)
517 /* First, zero out everything... argnumber[], argtype[], argptr[] */
518 memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */
520 --ppfs->maxposarg; /* set to -1 */
521 #endif /* NL_ARGMAX */
523 #ifdef __UCLIBC_MJN3_ONLY__
524 #warning TODO: Make checking of the format string in C locale an option.
526 #ifdef __UCLIBC_HAS_LOCALE__
527 /* To support old programs, don't check mb validity if in C locale. */
528 if (((__UCLIBC_CURLOCALE_DATA).encoding) != __ctype_encoding_7_bit) {
529 /* ANSI/ISO C99 requires format string to be a valid multibyte string
530 * beginning and ending in its initial shift state. */
531 static const char invalid_mbs[] = "Invalid multibyte format string.";
534 mbstate.__mask = 0; /* Initialize the mbstate. */
536 if (mbsrtowcs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) {
537 ppfs->fmtpos = invalid_mbs;
541 #endif /* __UCLIBC_HAS_LOCALE__ */
542 /* now set all argtypes to no-arg */
545 /* TODO - use memset here since already "paid for"? */
546 register int *p = ppfs->argtype;
553 /* TODO -- get rid of this?? */
554 register char *p = (char *) ((MAX_ARGS-1) * sizeof(int));
557 *((int *)(((char *)ppfs) + ((int)p) + offsetof(ppfs_t,argtype))) = __PA_NOARG;
564 * Run through the entire format string to validate it and initialize
565 * the positional arg numbers (if any).
568 register const char *fmt = fmt0;
571 if ((*fmt == '%') && (*++fmt != '%')) {
572 ppfs->fmtpos = fmt; /* back up to the '%' */
573 if ((r = _ppfs_parsespec(ppfs)) < 0) {
576 fmt = ppfs->fmtpos; /* update to one past end of spec */
581 ppfs->fmtpos = fmt0; /* rewind */
585 /* If we have positional args, make sure we know all the types. */
587 register int *p = ppfs->argtype;
590 if ( *p == __PA_NOARG ) { /* missing arg type!!! */
596 #endif /* NL_MAX_ARG */
601 /**********************************************************************/
602 #ifdef L__ppfs_prepargs
603 void attribute_hidden _ppfs_prepargs(register ppfs_t *ppfs, va_list arg)
607 va_copy(ppfs->arg, arg);
610 if ((i = ppfs->maxposarg) > 0) { /* init for positional args */
611 ppfs->num_data_args = i;
612 ppfs->info.width = ppfs->info.prec = ppfs->maxposarg = 0;
616 #endif /* NL_ARGMAX */
619 /**********************************************************************/
620 #ifdef L__ppfs_setargs
622 void attribute_hidden _ppfs_setargs(register ppfs_t *ppfs)
625 register void **p = ppfs->argptr;
627 register argvalue_t *p = ppfs->argvalue;
632 if (ppfs->maxposarg == 0) { /* initing for or no pos args */
633 #endif /* NL_ARGMAX */
634 if (ppfs->info.width == INT_MIN) {
639 GET_VA_ARG(p,u,unsigned int,ppfs->arg);
641 if (ppfs->info.prec == INT_MIN) {
646 GET_VA_ARG(p,u,unsigned int,ppfs->arg);
649 while (i < ppfs->num_data_args) {
650 switch(ppfs->argtype[i++]) {
651 case (PA_INT|PA_FLAG_LONG_LONG):
653 GET_VA_ARG(p,ull,unsigned long long,ppfs->arg);
656 case (PA_INT|PA_FLAG_LONG):
657 #if ULONG_MAX != UINT_MAX
658 GET_VA_ARG(p,ul,unsigned long,ppfs->arg);
661 case PA_CHAR: /* TODO - be careful */
662 /* ... users could use above and really want below!! */
663 case (PA_INT|__PA_FLAG_CHAR):/* TODO -- translate this!!! */
664 case (PA_INT|PA_FLAG_SHORT):
666 GET_VA_ARG(p,u,unsigned int,ppfs->arg);
668 case PA_WCHAR: /* TODO -- assume int? */
669 /* we're assuming wchar_t is at least an int */
670 GET_VA_ARG(p,wc,wchar_t,ppfs->arg);
672 #ifdef __STDIO_PRINTF_FLOAT
675 GET_VA_ARG(p,d,double,ppfs->arg);
677 case (PA_DOUBLE|PA_FLAG_LONG_DOUBLE):
678 GET_VA_ARG(p,ld,long double,ppfs->arg);
680 #else /* __STDIO_PRINTF_FLOAT */
682 case (PA_DOUBLE|PA_FLAG_LONG_DOUBLE):
685 #endif /* __STDIO_PRINTF_FLOAT */
687 /* TODO -- really need to ensure this can't happen */
688 assert(ppfs->argtype[i-1] & PA_FLAG_PTR);
692 GET_VA_ARG(p,p,void *,ppfs->arg);
701 if (ppfs->info.width == INT_MIN) {
703 = (int) GET_ARG_VALUE(p + ppfs->argnumber[0] - 1,u,unsigned int);
705 if (ppfs->info.prec == INT_MIN) {
707 = (int) GET_ARG_VALUE(p + ppfs->argnumber[1] - 1,u,unsigned int);
710 #endif /* NL_ARGMAX */
712 /* Now we know the width and precision. */
713 if (ppfs->info.width < 0) {
714 ppfs->info.width = -ppfs->info.width;
715 PRINT_INFO_SET_FLAG(&(ppfs->info),left);
716 PRINT_INFO_CLR_FLAG(&(ppfs->info),space);
717 ppfs->info.pad = ' ';
720 /* NOTE -- keep neg for now so float knows! */
721 if (ppfs->info.prec < 0) { /* spec says treat as omitted. */
722 /* so use default prec... 1 for everything but floats and strings. */
728 /**********************************************************************/
729 #ifdef L__ppfs_parsespec
731 #ifdef __UCLIBC_HAS_XLOCALE__
732 libc_hidden_proto(__ctype_b_loc)
733 #elif defined __UCLIBC_HAS_CTYPE_TABLES__
734 libc_hidden_proto(__ctype_b)
737 /* Notes: argtype differs from glibc for the following:
739 * lc PA_WCHAR PA_CHAR the standard says %lc means %C
740 * ls PA_WSTRING PA_STRING the standard says %ls means %S
741 * {*}n {*}|PA_FLAG_PTR PA_FLAG_PTR size of n can be qualified
744 /* TODO: store positions of positional args */
746 /* TODO -- WARNING -- assumes aligned on integer boundaries!!! */
748 /* TODO -- disable if not using positional args!!! */
749 #define _OVERLAPPING_DIFFERENT_ARGS
751 /* TODO -- rethink this -- perhaps we should set to largest type??? */
753 #ifdef _OVERLAPPING_DIFFERENT_ARGS
755 #define PROMOTED_SIZE_OF(X) ((sizeof(X) + sizeof(int) - 1) / sizeof(X))
757 static const short int type_codes[] = {
758 __PA_NOARG, /* must be first entry */
763 PA_INT|PA_FLAG_SHORT,
766 PA_INT|PA_FLAG_LONG_LONG,
768 #ifdef __STDIO_PRINTF_FLOAT
771 PA_DOUBLE|PA_FLAG_LONG_DOUBLE,
772 #endif /* __STDIO_PRINTF_FLOAT */
775 static const unsigned char type_sizes[] = {
776 /* unknown type consumes no arg */
777 0, /* must be first entry */
778 PROMOTED_SIZE_OF(void *),
779 PROMOTED_SIZE_OF(char *),
780 PROMOTED_SIZE_OF(wchar_t *),
781 PROMOTED_SIZE_OF(char),
782 PROMOTED_SIZE_OF(short),
783 PROMOTED_SIZE_OF(int),
784 PROMOTED_SIZE_OF(long),
786 PROMOTED_SIZE_OF(long long),
788 PROMOTED_SIZE_OF(long), /* TODO -- is this correct? (above too) */
790 PROMOTED_SIZE_OF(wchar_t),
791 #ifdef __STDIO_PRINTF_FLOAT
792 /* PROMOTED_SIZE_OF(float), */
793 PROMOTED_SIZE_OF(double),
794 PROMOTED_SIZE_OF(long double),
795 #endif /* __STDIO_PRINTF_FLOAT */
798 static int _promoted_size(int argtype)
800 register const short int *p;
802 /* note -- since any unrecognized type is treated as a pointer */
803 p = type_codes + sizeof(type_codes)/sizeof(type_codes[0]);
805 if (*--p == argtype) {
808 } while (p > type_codes);
810 return type_sizes[(int)(p - type_codes)];
813 static int _is_equal_or_bigger_arg(int curtype, int newtype)
816 if (newtype == __PA_NOARG) {
819 if ((curtype == __PA_NOARG) || (curtype == newtype)) {
822 /* Ok... slot is already filled and types are different in name. */
823 /* So, compare promoted sizes of curtype and newtype args. */
824 return _promoted_size(curtype) <= _promoted_size(newtype);
829 #define _is_equal_or_bigger_arg(C,N) (((C) == __PA_NOARG) || ((C) == (N)))
833 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
834 /* TODO - do this differently? */
835 static char _bss_custom_printf_spec[MAX_USER_SPEC]; /* 0-init'd for us. */
837 attribute_hidden char *_custom_printf_spec = _bss_custom_printf_spec;
838 attribute_hidden printf_arginfo_function *_custom_printf_arginfo[MAX_USER_SPEC];
839 attribute_hidden printf_function _custom_printf_handler[MAX_USER_SPEC];
840 #endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
842 int attribute_hidden _ppfs_parsespec(ppfs_t *ppfs)
844 register const char *fmt;
845 register const char *p;
854 #endif /* NL_ARGMAX */
857 int argtype[MAX_ARGS_PER_SPEC+2];
858 int argnumber[3]; /* width, precision, 1st data arg */
859 static const char spec_flags[] = SPEC_FLAGS;
860 static const char spec_chars[] = SPEC_CHARS;/* TODO: b? */
861 static const char spec_ranges[] = SPEC_RANGES;
862 static const short spec_or_mask[] = SPEC_OR_MASK;
863 static const short spec_and_mask[] = SPEC_AND_MASK;
864 static const char qual_chars[] = QUAL_CHARS;
865 #ifdef __UCLIBC_HAS_WCHAR__
867 #endif /* __UCLIBC_HAS_WCHAR__ */
869 /* WIDE note: we can test against '%' here since we don't allow */
870 /* WIDE note: other mappings of '%' in the wide char set. */
874 argtype[0] = __PA_NOARG;
875 argtype[1] = __PA_NOARG;
877 maxposarg = ppfs->maxposarg;
878 #endif /* NL_ARGMAX */
880 #ifdef __UCLIBC_HAS_WCHAR__
881 /* This is somewhat lame, but saves a lot of code. If we're dealing with
882 * a wide stream, that means the format is a wchar string. So, copy it
883 * char-by-char into a normal char buffer for processing. Make the buffer
884 * (buf) big enough so that any reasonable format specifier will fit.
885 * While there a legal specifiers that won't, the all involve duplicate
886 * flags or outrageous field widths/precisions. */
888 if ((flags = ppfs->info._flags & FLAG_WIDESTREAM) == 0) {
894 if ((buf[i] = (char) (((wchar_t *) ppfs->fmtpos)[i-1]))
895 != (((wchar_t *) ppfs->fmtpos)[i-1])
899 } while (buf[i++] && (i < sizeof(buf)));
900 buf[sizeof(buf)-1] = 0;
902 #else /* __UCLIBC_HAS_WCHAR__ */
903 width = flags = dpoint = 0;
905 #endif /* __UCLIBC_HAS_WCHAR__ */
907 assert(fmt[-1] == '%');
908 assert(fmt[0] != '%');
910 /* Process arg pos and/or flags and/or width and/or precision. */
914 argtype[-dpoint] = PA_INT;
918 while (isdigit(*fmt)) {
919 if (i < MAX_FIELD_WIDTH) { /* Avoid overflow. */
920 i = (i * 10) + (*fmt - '0');
924 if (p[-1] == '%') { /* Check for a position. */
926 /* TODO: if val not in range, then error */
929 if ((*fmt == '$') && (i > 0)) {/* Positional spec. */
931 if (maxposarg == 0) {
934 if ((argnumber[2] = i) > maxposarg) {
937 /* Now fall through to check flags. */
940 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
941 #ifdef __UCLIBC_MJN3_ONLY__
942 #warning TODO: Support prec and width for %m when positional args used
943 /* Actually, positional arg processing will fail in general
944 * for specifiers that don't require an arg. */
945 #endif /* __UCLIBC_MJN3_ONLY__ */
949 #endif /* __UCLIBC_HAS_PRINTF_M_SPEC__ */
952 maxposarg = 0; /* Possible redundant store, but cuts size. */
954 if ((fmt > p) && (*p != '0')) {
958 fmt = p; /* Back up for possible '0's flag. */
959 /* Now fall through to check flags. */
961 #else /* NL_ARGMAX */
962 if (*fmt == '$') { /* Positional spec. */
966 if ((fmt > p) && (*p != '0')) {
970 fmt = p; /* Back up for possible '0's flag. */
971 /* Now fall through to check flags. */
972 #endif /* NL_ARGMAX */
974 restart_flags: /* Process flags. */
984 i += i; /* Better than i <<= 1 for bcc */
988 /* If '+' then ignore ' ', and if '-' then ignore '0'. */
989 /* Note: Need to ignore '0' when prec is an arg with val < 0, */
990 /* but that test needs to wait until the arg is retrieved. */
991 flags &= ~((flags & (FLAG_PLUS|FLAG_MINUS)) >> 1);
992 /* Note: Ignore '0' when prec is specified < 0 too (in printf). */
994 if (fmt[-1] != '%') { /* If we've done anything, loop for width. */
995 goto width_precision;
999 if (*p == '*') { /* Prec or width takes an arg. */
1002 if ((*fmt++ != '$') || (i <= 0)) {
1003 /* Using pos args and no $ or invalid arg number. */
1006 argnumber[-dpoint] = i;
1008 #endif /* NL_ARGMAX */
1010 /* Not using pos args but digits followed *. */
1020 dpoint = -1; /* To use as default precison. */
1021 goto width_precision;
1027 /* Process qualifier. */
1035 if ((p - qual_chars < 2) && (*fmt == *p)) {
1036 p += ((sizeof(qual_chars)-2) / 2);
1039 dataargtype = ((int)(p[(sizeof(qual_chars)-2) / 2])) << 8;
1041 /* Process conversion specifier. */
1050 p_m_spec_chars = p - spec_chars;
1052 if ((p_m_spec_chars >= CONV_c)
1053 && (dataargtype & PA_FLAG_LONG)) {
1054 p_m_spec_chars -= 2; /* lc -> C and ls -> S */
1057 ppfs->conv_num = p_m_spec_chars;
1059 while (p_m_spec_chars > *++p) {}
1061 i = p - spec_ranges;
1062 argtype[2] = (dataargtype | spec_or_mask[i]) & spec_and_mask[i];
1068 ppfs->info.spec = *fmt;
1069 ppfs->info.prec = preci;
1070 ppfs->info.width = width;
1071 ppfs->info.pad = ((flags & FLAG_ZERO) ? '0' : ' ');
1072 ppfs->info._flags = (flags & ~FLAG_ZERO) | (dataargtype & __PA_INTMASK);
1073 ppfs->num_data_args = 1;
1076 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1078 ppfs->conv_num = CONV_m;
1079 ppfs->num_data_args = 0;
1083 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
1085 /* Handle custom arg -- WARNING -- overwrites p!!! */
1086 ppfs->conv_num = CONV_custom0;
1087 p = _custom_printf_spec;
1090 if ((ppfs->num_data_args
1091 = ((*_custom_printf_arginfo[(int)(p-_custom_printf_spec)])
1092 (&(ppfs->info), MAX_ARGS_PER_SPEC, argtype+2)))
1093 > MAX_ARGS_PER_SPEC) {
1094 break; /* Error -- too many args! */
1098 } while (++p < (_custom_printf_spec + MAX_USER_SPEC));
1099 #endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
1100 /* Otherwise error. */
1104 #if defined(__UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__) || defined(__UCLIBC_HAS_PRINTF_M_SPEC__)
1109 if (maxposarg > 0) {
1112 /* Update maxposarg and check that NL_ARGMAX is not exceeded. */
1114 ? (ppfs->argnumber[i] = argnumber[i])
1115 : argnumber[2] + (i-2));
1116 if (n > maxposarg) {
1117 if ((maxposarg = n) > NL_ARGMAX) {
1122 /* Record argtype with largest size (current, new). */
1123 if (_is_equal_or_bigger_arg(ppfs->argtype[n], argtype[i])) {
1124 ppfs->argtype[n] = argtype[i];
1126 } while (++i < ppfs->num_data_args + 2);
1128 #endif /* NL_ARGMAX */
1129 ppfs->argnumber[2] = 1;
1130 memcpy(ppfs->argtype, argtype + 2, ppfs->num_data_args * sizeof(int));
1134 ppfs->maxposarg = maxposarg;
1135 #endif /* NL_ARGMAX */
1137 #ifdef __UCLIBC_HAS_WCHAR__
1138 if ((flags = ppfs->info._flags & FLAG_WIDESTREAM) == 0) {
1139 ppfs->fmtpos = ++fmt;
1141 ppfs->fmtpos = (const char *) (((const wchar_t *)(ppfs->fmtpos))
1144 #else /* __UCLIBC_HAS_WCHAR__ */
1145 ppfs->fmtpos = ++fmt;
1146 #endif /* __UCLIBC_HAS_WCHAR__ */
1148 return ppfs->num_data_args + 2;
1152 /**********************************************************************/
1153 #ifdef L_register_printf_function
1155 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
1157 int register_printf_function(int spec, printf_function handler,
1158 printf_arginfo_function arginfo)
1163 if (spec && (arginfo != NULL)) { /* TODO -- check if spec is valid char */
1165 p = _custom_printf_spec + MAX_USER_SPEC;
1172 else /* bcc generates less code with fall-through */
1176 p = _custom_printf_spec;
1178 } while (p > _custom_printf_spec);
1183 _custom_printf_handler[(int)(r - p)] = handler;
1184 _custom_printf_arginfo[(int)(r - p)] = arginfo;
1190 /* TODO -- if asked to unregister a non-existent spec, return what? */
1198 /**********************************************************************/
1199 #if defined(L__vfprintf_internal) || defined(L__vfwprintf_internal)
1201 /* We only support ascii digits (or their USC equivalent codes) in
1202 * precision and width settings in *printf (wide) format strings.
1203 * In other words, we don't currently support glibc's 'I' flag.
1204 * We do accept it, but it is currently ignored. */
1206 static size_t _charpad(FILE * __restrict stream, int padchar, size_t numpad);
1208 #ifdef L__vfprintf_internal
1210 #define VFPRINTF_internal _vfprintf_internal
1211 #define FMT_TYPE char
1212 #define OUTNSTR _outnstr
1213 #define STRLEN strlen
1214 #define _PPFS_init _ppfs_init
1215 /* Pulls in fseek: #define OUTPUT(F,S) fputs_unlocked(S,F) */
1216 #define OUTPUT(F,S) __stdio_fwrite((const unsigned char *)(S),strlen(S),(F))
1217 /* #define _outnstr(stream, string, len) __stdio_fwrite(string, len, stream) */
1218 #define _outnstr(stream, string, len) ((len > 0) ? __stdio_fwrite(string, len, stream) : 0)
1219 #define FP_OUT _fp_out_narrow
1221 #ifdef __STDIO_PRINTF_FLOAT
1223 static size_t _fp_out_narrow(FILE *fp, intptr_t type, intptr_t len, intptr_t buf)
1227 if (type & 0x80) { /* Some type of padding needed. */
1228 int buflen = strlen((const char *) buf);
1229 if ((len -= buflen) > 0) {
1230 if ((r = _charpad(fp, (type & 0x7f), len)) != len) {
1236 return r + OUTNSTR(fp, (const unsigned char *) buf, len);
1239 #endif /* __STDIO_PRINTF_FLOAT */
1241 #else /* L__vfprintf_internal */
1243 #define VFPRINTF_internal _vfwprintf_internal
1244 #define FMT_TYPE wchar_t
1245 #define OUTNSTR _outnwcs
1246 #define STRLEN wcslen
1247 #define _PPFS_init _ppwfs_init
1248 /* Pulls in fseek: */
1249 #define OUTPUT(F,S) fputws(S,F)
1250 /* TODO: #define OUTPUT(F,S) _wstdio_fwrite((S),wcslen(S),(F)) */
1251 #define _outnwcs(stream, wstring, len) _wstdio_fwrite(wstring, len, stream)
1252 #define FP_OUT _fp_out_wide
1254 static size_t _outnstr(FILE *stream, const char *s, size_t wclen)
1256 /* NOTE!!! len here is the number of wchars we want to generate!!! */
1265 r = mbsrtowcs(wbuf, &s,
1266 ((todo <= sizeof(wbuf)/sizeof(wbuf[0]))
1268 : sizeof(wbuf)/sizeof(wbuf[0])),
1270 assert(((ssize_t)r) > 0);
1271 n = _outnwcs(stream, wbuf, r);
1278 return wclen - todo;
1281 #ifdef __STDIO_PRINTF_FLOAT
1283 #ifdef __UCLIBC_MJN3_ONLY__
1284 #warning TODO: Move defines from _fpmaxtostr. Put them in a common header.
1287 /* The following defines are from _fpmaxtostr.*/
1288 #define DIGITS_PER_BLOCK 9
1289 #define NUM_DIGIT_BLOCKS ((DECIMAL_DIG+DIGITS_PER_BLOCK-1)/DIGITS_PER_BLOCK)
1290 #define BUF_SIZE ( 3 + NUM_DIGIT_BLOCKS * DIGITS_PER_BLOCK )
1292 static size_t _fp_out_wide(FILE *fp, intptr_t type, intptr_t len, intptr_t buf)
1294 wchar_t wbuf[BUF_SIZE];
1295 const char *s = (const char *) buf;
1299 if (type & 0x80) { /* Some type of padding needed */
1300 int buflen = strlen(s);
1301 if ((len -= buflen) > 0) {
1302 if ((r = _charpad(fp, (type & 0x7f), len)) != len) {
1312 #ifdef __LOCALE_C_ONLY
1314 #else /* __LOCALE_C_ONLY */
1316 #ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
1318 wbuf[i] = __UCLIBC_CURLOCALE_DATA.thousands_sep_wc;
1320 #endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
1322 wbuf[i] = __UCLIBC_CURLOCALE_DATA.decimal_point_wc;
1326 #endif /* __LOCALE_C_ONLY */
1328 } while (++i < len);
1330 r += OUTNSTR(fp, wbuf, len);
1336 #endif /* __STDIO_PRINTF_FLOAT */
1338 static int _ppwfs_init(register ppfs_t *ppfs, const wchar_t *fmt0)
1340 static const wchar_t invalid_wcs[] = L"Invalid wide format string.";
1343 /* First, zero out everything... argnumber[], argtype[], argptr[] */
1344 memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */
1346 --ppfs->maxposarg; /* set to -1 */
1347 #endif /* NL_ARGMAX */
1348 ppfs->fmtpos = (const char *) fmt0;
1349 ppfs->info._flags = FLAG_WIDESTREAM;
1354 mbstate.__mask = 0; /* Initialize the mbstate. */
1356 if (wcsrtombs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) {
1357 ppfs->fmtpos = (const char *) invalid_wcs;
1362 /* now set all argtypes to no-arg */
1365 /* TODO - use memset here since already "paid for"? */
1366 register int *p = ppfs->argtype;
1373 /* TODO -- get rid of this?? */
1374 register char *p = (char *) ((MAX_ARGS-1) * sizeof(int));
1377 *((int *)(((char *)ppfs) + ((int)p) + offsetof(ppfs_t,argtype))) = __PA_NOARG;
1384 * Run through the entire format string to validate it and initialize
1385 * the positional arg numbers (if any).
1388 register const wchar_t *fmt = fmt0;
1391 if ((*fmt == '%') && (*++fmt != '%')) {
1392 ppfs->fmtpos = (const char *) fmt; /* back up to the '%' */
1393 if ((r = _ppfs_parsespec(ppfs)) < 0) {
1396 fmt = (const wchar_t *) ppfs->fmtpos; /* update to one past end of spec */
1401 ppfs->fmtpos = (const char *) fmt0; /* rewind */
1405 /* If we have positional args, make sure we know all the types. */
1407 register int *p = ppfs->argtype;
1408 r = ppfs->maxposarg;
1410 if ( *p == __PA_NOARG ) { /* missing arg type!!! */
1416 #endif /* NL_ARGMAX */
1421 #endif /* L__vfprintf_internal */
1424 static size_t _charpad(FILE * __restrict stream, int padchar, size_t numpad)
1426 size_t todo = numpad;
1428 /* TODO -- Use a buffer to cut down on function calls... */
1432 while (todo && (OUTNSTR(stream, (const unsigned char *) pad, 1) == 1)) {
1436 return numpad - todo;
1439 /* TODO -- Dynamically allocate work space to accomodate stack-poor archs? */
1440 static int _do_one_spec(FILE * __restrict stream,
1441 register ppfs_t *ppfs, int *count)
1443 static const char spec_base[] = SPEC_BASE;
1444 #ifdef L__vfprintf_internal
1445 static const char prefix[] = "+\0-\0 \0000x\0000X";
1447 #else /* L__vfprintf_internal */
1448 static const wchar_t prefix[] = L"+\0-\0 \0000x\0000X";
1449 #endif /* L__vfprintf_internal */
1460 const void * const *argptr;
1462 const void * argptr[MAX_ARGS_PER_SPEC];
1465 #ifdef __UCLIBC_HAS_WCHAR__
1466 const wchar_t *ws = NULL;
1468 #endif /* __UCLIBC_HAS_WCHAR__ */
1470 #ifdef L__vfprintf_internal
1479 int numfill = 0; /* TODO: fix */
1480 int prefix_num = PREFIX_NONE;
1482 #ifdef __UCLIBC_MJN3_ONLY__
1483 #warning TODO: Determine appropriate buf size.
1484 #endif /* __UCLIBC_MJN3_ONLY__ */
1485 /* TODO: buf needs to be big enough for any possible error return strings
1486 * and also for any locale-grouped long long integer strings generated.
1487 * This should be large enough for any of the current archs/locales, but
1488 * eventually this should be handled robustly. */
1492 _ppfs_parsespec(ppfs);
1494 if (_ppfs_parsespec(ppfs) < 0) { /* TODO: just for debugging */
1498 _ppfs_setargs(ppfs);
1500 argtype = ppfs->argtype + ppfs->argnumber[2] - 1;
1501 /* Deal with the argptr vs argvalue issue. */
1503 argptr = (const void * const *) ppfs->argptr;
1505 if (ppfs->maxposarg > 0) { /* Using positional args... */
1506 argptr += ppfs->argnumber[2] - 1;
1508 #endif /* NL_ARGMAX */
1510 /* Need to build a local copy... */
1512 register argvalue_t *p = ppfs->argvalue;
1515 if (ppfs->maxposarg > 0) { /* Using positional args... */
1516 p += ppfs->argnumber[2] - 1;
1518 #endif /* NL_ARGMAX */
1519 for (i = 0 ; i < ppfs->num_data_args ; i++ ) {
1520 argptr[i] = (void *) p++;
1525 register char *s = NULL; /* TODO: Should s be unsigned char * ? */
1527 if (ppfs->conv_num == CONV_n) {
1528 _store_inttype(*(void **)*argptr,
1529 ppfs->info._flags & __PA_INTMASK,
1530 (intmax_t) (*count));
1533 if (ppfs->conv_num <= CONV_i) { /* pointer or (un)signed int */
1534 alphacase = __UIM_LOWER;
1536 #ifdef __UCLIBC_MJN3_ONLY__
1537 #ifdef L__vfprintf_internal
1538 #warning CONSIDER: Should we ignore these flags if stub locale? What about custom specs?
1540 #endif /* __UCLIBC_MJN3_ONLY__ */
1541 if ((base = spec_base[(int)(ppfs->conv_num - CONV_p)]) == 10) {
1542 if (PRINT_INFO_FLAG_VAL(&(ppfs->info),group)) {
1543 alphacase = __UIM_GROUP;
1545 if (PRINT_INFO_FLAG_VAL(&(ppfs->info),i18n)) {
1550 if (ppfs->conv_num <= CONV_u) { /* pointer or unsigned int */
1551 if (ppfs->conv_num == CONV_X) {
1552 alphacase = __UIM_UPPER;
1554 if (ppfs->conv_num == CONV_p) { /* pointer */
1555 prefix_num = PREFIX_LWR_X;
1556 } else { /* unsigned int */
1558 } else { /* signed int */
1561 if (ppfs->info.prec < 0) { /* Ignore '0' flag if prec specified. */
1562 padchar = ppfs->info.pad;
1564 #ifdef __UCLIBC_MJN3_ONLY__
1565 #ifdef L__vfprintf_internal
1566 #warning CONSIDER: If using outdigits and/or grouping, how should we interpret precision?
1568 #endif /* __UCLIBC_MJN3_ONLY__ */
1569 s = _uintmaxtostr(buf + sizeof(buf) - 1,
1571 _load_inttype(ppfs->conv_num == CONV_p ? PA_FLAG_LONG : *argtype & __PA_INTMASK,
1572 *argptr, base), base, alphacase);
1573 if (ppfs->conv_num > CONV_u) { /* signed int */
1575 PRINT_INFO_SET_FLAG(&(ppfs->info),showsign);
1576 ++s; /* handle '-' in the prefix string */
1577 prefix_num = PREFIX_MINUS;
1578 } else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),showsign)) {
1579 prefix_num = PREFIX_PLUS;
1580 } else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),space)) {
1581 prefix_num = PREFIX_SPACE;
1584 slen = (char *)(buf + sizeof(buf) - 1) - s;
1585 #ifdef L__vfwprintf_internal
1588 mbstate.__mask = 0; /* Initialize the mbstate. */
1589 SLEN = mbsrtowcs(NULL, &q, 0, &mbstate);
1592 numfill = ((ppfs->info.prec < 0) ? 1 : ppfs->info.prec);
1593 if (PRINT_INFO_FLAG_VAL(&(ppfs->info),alt)) {
1594 if (ppfs->conv_num <= CONV_x) { /* x or p */
1595 prefix_num = PREFIX_LWR_X;
1597 if (ppfs->conv_num == CONV_X) {
1598 prefix_num = PREFIX_UPR_X;
1600 if ((ppfs->conv_num == CONV_o) && (numfill <= SLEN)) {
1601 numfill = ((*s == '0') ? 1 : SLEN + 1);
1605 if (prefix_num >= PREFIX_LWR_X) {
1606 prefix_num = PREFIX_NONE;
1608 if (ppfs->conv_num == CONV_p) {/* null pointer */
1610 #ifdef L__vfwprintf_internal
1615 } else if (numfill == 0) { /* if precision 0, no output */
1616 #ifdef L__vfwprintf_internal
1622 numfill = ((numfill > SLEN) ? numfill - SLEN : 0);
1623 } else if (ppfs->conv_num <= CONV_A) { /* floating point */
1624 #ifdef __STDIO_PRINTF_FLOAT
1626 nf = _fpmaxtostr(stream,
1628 (PRINT_INFO_FLAG_VAL(&(ppfs->info),is_long_double)
1629 ? *(long double *) *argptr
1630 : (long double) (* (double *) *argptr)),
1631 &ppfs->info, FP_OUT );
1638 #else /* __STDIO_PRINTF_FLOAT */
1639 return -1; /* TODO -- try to continue? */
1640 #endif /* __STDIO_PRINTF_FLOAT */
1641 } else if (ppfs->conv_num <= CONV_S) { /* wide char or string */
1642 #ifdef L__vfprintf_internal
1644 #ifdef __UCLIBC_HAS_WCHAR__
1645 mbstate.__mask = 0; /* Initialize the mbstate. */
1646 if (ppfs->conv_num == CONV_S) { /* wide string */
1647 if (!(ws = *((const wchar_t **) *argptr))) {
1650 /* We use an awful uClibc-specific hack here, passing
1651 * (char*) &ws as the conversion destination. This signals
1652 * uClibc's wcsrtombs that we want a "restricted" length
1653 * such that the mbs fits in a buffer of the specified
1654 * size with no partial conversions. */
1655 if ((slen = wcsrtombs((char *) &ws, &ws, /* Use awful hack! */
1656 ((ppfs->info.prec >= 0)
1658 : SIZE_MAX), &mbstate))
1661 return -1; /* EILSEQ */
1663 } else { /* wide char */
1665 slen = wcrtomb(s, (*((const wchar_t *) *argptr)), &mbstate);
1666 if (slen == ((size_t)-1)) {
1667 return -1; /* EILSEQ */
1669 s[slen] = 0; /* TODO - Is this necessary? */
1671 #else /* __UCLIBC_HAS_WCHAR__ */
1673 #endif /* __UCLIBC_HAS_WCHAR__ */
1674 } else if (ppfs->conv_num <= CONV_s) { /* char or string */
1675 if (ppfs->conv_num == CONV_s) { /* string */
1676 s = *((char **) (*argptr));
1678 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1681 slen = strnlen(s, ((ppfs->info.prec >= 0)
1682 ? ppfs->info.prec : SIZE_MAX));
1684 #ifdef __UCLIBC_HAS_WCHAR__
1692 *s = (unsigned char)(*((const int *) *argptr));
1697 #else /* L__vfprintf_internal */
1699 if (ppfs->conv_num == CONV_S) { /* wide string */
1700 ws = *((wchar_t **) (*argptr));
1704 SLEN = wcsnlen(ws, ((ppfs->info.prec >= 0)
1705 ? ppfs->info.prec : SIZE_MAX));
1706 } else { /* wide char */
1707 *wbuf = (wchar_t)(*((const wint_t *) *argptr));
1714 } else if (ppfs->conv_num <= CONV_s) { /* char or string */
1716 if (ppfs->conv_num == CONV_s) { /* string */
1717 #ifdef __UCLIBC_MJN3_ONLY__
1718 #warning TODO: Fix %s for _vfwprintf_internal... output upto illegal sequence?
1719 #endif /* __UCLIBC_MJN3_ONLY__ */
1720 s = *((char **) (*argptr));
1722 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1725 /* We use an awful uClibc-specific hack here, passing
1726 * (wchar_t*) &mbstate as the conversion destination.
1727 * This signals uClibc's mbsrtowcs that we want a
1728 * "restricted" length such that the mbs fits in a buffer
1729 * of the specified size with no partial conversions. */
1732 mbstate.__mask = 0; /* Initialize the mbstate. */
1733 SLEN = mbsrtowcs((wchar_t *) &mbstate, &q,
1734 ((ppfs->info.prec >= 0)
1735 ? ppfs->info.prec : SIZE_MAX),
1738 if (SLEN == ((size_t)(-1))) {
1739 return -1; /* EILSEQ */
1747 *wbuf = btowc( (unsigned char)(*((const int *) *argptr)) );
1751 #endif /* L__vfprintf_internal */
1753 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1754 } else if (ppfs->conv_num == CONV_m) {
1755 s = __glibc_strerror_r(errno, buf, sizeof(buf));
1756 goto SET_STRING_LEN;
1759 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
1760 assert(ppfs->conv_num == CONV_custom0);
1762 s = _custom_printf_spec;
1764 if (*s == ppfs->info.spec) {
1766 /* TODO -- check return value for sanity? */
1767 rv = (*_custom_printf_handler
1768 [(int)(s-_custom_printf_spec)])
1769 (stream, &ppfs->info, argptr);
1776 } while (++s < (_custom_printf_spec + MAX_USER_SPEC));
1777 #endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
1782 #ifdef __UCLIBC_MJN3_ONLY__
1783 #ifdef L__vfprintf_internal
1784 #warning CONSIDER: If using outdigits and/or grouping, how should we pad?
1786 #endif /* __UCLIBC_MJN3_ONLY__ */
1791 if (prefix_num != PREFIX_NONE) {
1792 t += ((prefix_num < PREFIX_LWR_X) ? 1 : 2);
1794 numpad = ((ppfs->info.width > t) ? (ppfs->info.width - t) : 0);
1795 *count += t + numpad;
1797 if (padchar == '0') { /* TODO: check this */
1802 /* Now handle the output itself. */
1803 if (!PRINT_INFO_FLAG_VAL(&(ppfs->info),left)) {
1804 if (_charpad(stream, ' ', numpad) != numpad) {
1809 OUTPUT(stream, prefix + prefix_num);
1811 if (_charpad(stream, '0', numfill) != numfill) {
1815 #ifdef L__vfprintf_internal
1817 #ifdef __UCLIBC_HAS_WCHAR__
1820 if (_outnstr(stream, s, slen) != slen) {
1823 } else { /* wide string */
1825 mbstate.__mask = 0; /* Initialize the mbstate. */
1827 t = (slen <= sizeof(buf)) ? slen : sizeof(buf);
1828 t = wcsrtombs(buf, &ws, t, &mbstate);
1829 assert (t != ((size_t)(-1)));
1830 if (_outnstr(stream, buf, t) != t) {
1836 #else /* __UCLIBC_HAS_WCHAR__ */
1837 if (_outnstr(stream, (const unsigned char *) s, slen) != slen) {
1840 #endif /* __UCLIBC_HAS_WCHAR__ */
1842 #else /* L__vfprintf_internal */
1846 if (_outnstr(stream, s, SLEN) != SLEN) {
1850 if (_outnwcs(stream, ws, SLEN) != SLEN) {
1855 #endif /* L__vfprintf_internal */
1856 if (_charpad(stream, ' ', numpad) != numpad) {
1864 libc_hidden_proto(fprintf)
1866 int VFPRINTF_internal (FILE * __restrict stream,
1867 const FMT_TYPE * __restrict format,
1872 register const FMT_TYPE *s;
1877 if (_PPFS_init(&ppfs, format) < 0) { /* Bad format string. */
1878 OUTNSTR(stream, (const unsigned char *) ppfs.fmtpos,
1879 STRLEN((const FMT_TYPE *)(ppfs.fmtpos)));
1880 #if defined(L__vfprintf_internal) && !defined(NDEBUG)
1881 fprintf(stderr,"\nIMbS: \"%s\"\n\n", format);
1885 _ppfs_prepargs(&ppfs, arg); /* This did a va_copy!!! */
1888 while (*format && (*format != '%')) {
1892 if (format-s) { /* output any literal text in format string */
1893 if ( (r = OUTNSTR(stream, (const unsigned char *) s, format-s)) != (format-s)) {
1900 if (!*format) { /* we're done */
1904 if (format[1] != '%') { /* if we get here, *format == '%' */
1905 /* TODO: _do_one_spec needs to know what the output funcs are!!! */
1906 ppfs.fmtpos = (const char *)(++format);
1907 /* TODO: check -- should only fail on stream error */
1908 if ( (r = _do_one_spec(stream, &ppfs, &count)) < 0) {
1912 s = format = (const FMT_TYPE *) ppfs.fmtpos;
1913 } else { /* %% means literal %, so start new string */
1919 va_end(ppfs.arg); /* Need to clean up after va_copy! */
1922 /* #if defined(L__vfprintf_internal) && defined(__UCLIBC_HAS_WCHAR__) */
1928 #endif /* defined(L__vfprintf_internal) || defined(L__vfwprintf_internal) */
1931 /**********************************************************************/
1932 #if defined(L_vfprintf) || defined(L_vfwprintf)
1934 /* This is just a wrapper around VFPRINTF_internal.
1935 * Factoring out vfprintf internals allows:
1936 * (1) vdprintf and vsnprintf don't need to setup fake locking,
1937 * (2) __STDIO_STREAM_TRANS_TO_WRITE is not used in vfprintf internals,
1938 * and thus fseek etc is not pulled in by vdprintf and vsnprintf.
1940 * In order to not pull in fseek through fputs, OUTPUT() macro
1941 * is using __stdio_fwrite (TODO: do the same for wide functions).
1944 #define VFPRINTF vfprintf
1945 #define VFPRINTF_internal _vfprintf_internal
1946 #define FMT_TYPE char
1948 #define VFPRINTF vfwprintf
1949 #define VFPRINTF_internal _vfwprintf_internal
1950 #define FMT_TYPE wchar_t
1953 libc_hidden_proto(VFPRINTF)
1954 int VFPRINTF (FILE * __restrict stream,
1955 const FMT_TYPE * __restrict format,
1959 __STDIO_AUTO_THREADLOCK_VAR;
1961 __STDIO_AUTO_THREADLOCK(stream);
1965 (!__STDIO_STREAM_IS_NARROW_WRITING(stream)
1966 && __STDIO_STREAM_TRANS_TO_WRITE(stream, __FLAG_NARROW))
1968 (!__STDIO_STREAM_IS_WIDE_WRITING(stream)
1969 && __STDIO_STREAM_TRANS_TO_WRITE(stream, __FLAG_WIDE))
1974 count = VFPRINTF_internal(stream, format, arg);
1977 __STDIO_AUTO_THREADUNLOCK(stream);
1981 libc_hidden_def(VFPRINTF)
1982 #endif /* defined(L_vfprintf) || defined(L_vfwprintf) */
1984 /**********************************************************************/