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, see
16 * <http://www.gnu.org/licenses/>.
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.
104 #ifdef __UCLIBC_HAS_THREADS__
105 # include <stdio_ext.h>
106 # include <pthread.h>
109 #ifdef __UCLIBC_HAS_WCHAR__
113 #include <bits/uClibc_uintmaxtostr.h>
114 #include <bits/uClibc_va_copy.h>
116 /* Some older or broken gcc toolchains define LONG_LONG_MAX but not
117 * LLONG_MAX. Since LLONG_MAX is part of the standard, that's what
118 * we use. So complain if we do not have it but should.
120 #if !defined(LLONG_MAX) && defined(LONG_LONG_MAX)
121 #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.
124 /**********************************************************************/
125 /* These provide some control over printf's feature set */
127 /* Now controlled by uClibc_config.h. */
128 /* #define __UCLIBC_HAS_FLOATS__ 1 */
130 /* Now controlled by uClibc_config.h. */
131 /* #define __UCLIBC_HAS_PRINTF_M_SPEC__ */
134 /**********************************************************************/
136 #include "_fpmaxtostr.h"
138 #undef __STDIO_HAS_VSNPRINTF
139 #if defined(__STDIO_BUFFERS) || defined(__USE_OLD_VFPRINTF__) || defined(__UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__)
140 # define __STDIO_HAS_VSNPRINTF 1
143 /**********************************************************************/
145 /* Now controlled by uClibc_config.h. */
146 /* #define __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
148 #ifdef __UCLIBC_MJN3_ONLY__
149 # ifdef L_register_printf_function
151 # warning WISHLIST: Make MAX_USER_SPEC configurable?
152 # warning WISHLIST: Make MAX_ARGS_PER_SPEC configurable?
156 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
157 # define MAX_USER_SPEC 10
158 # define MAX_ARGS_PER_SPEC 5
160 # undef MAX_USER_SPEC
161 # define MAX_ARGS_PER_SPEC 1
164 #if MAX_ARGS_PER_SPEC < 1
165 # error MAX_ARGS_PER_SPEC < 1!
166 # undef MAX_ARGS_PER_SPEC
167 # define MAX_ARGS_PER_SPEC 1
170 #if defined(NL_ARGMAX) && (NL_ARGMAX < 9)
171 # error NL_ARGMAX < 9!
174 #if defined(NL_ARGMAX) && (NL_ARGMAX >= (MAX_ARGS_PER_SPEC + 2))
175 # define MAX_ARGS NL_ARGMAX
177 /* N for spec itself, plus 1 each for width and precision */
178 # define MAX_ARGS (MAX_ARGS_PER_SPEC + 2)
181 /**********************************************************************/
183 #define __PA_FLAG_INTMASK \
184 (__PA_FLAG_CHAR|PA_FLAG_SHORT|__PA_FLAG_INT|PA_FLAG_LONG|PA_FLAG_LONG_LONG)
186 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
187 extern printf_function _custom_printf_handler[MAX_USER_SPEC] attribute_hidden;
188 extern printf_arginfo_function *_custom_printf_arginfo[MAX_USER_SPEC] attribute_hidden;
189 extern char *_custom_printf_spec attribute_hidden;
192 /**********************************************************************/
194 #define SPEC_FLAGS " +0-#'I"
197 FLAG_PLUS = 0x02, /* must be 2 * FLAG_SPACE */
199 FLAG_MINUS = 0x08, /* must be 2 * FLAG_ZERO */
201 FLAG_THOUSANDS = 0x20,
202 FLAG_I18N = 0x40, /* only works for d, i, u */
203 FLAG_WIDESTREAM = 0x80
206 /**********************************************************************/
208 /* float layout 01234567890123456789 TODO: B?*/
209 #define SPEC_CHARS "npxXoudifFeEgGaACScs"
213 CONV_x, CONV_X, CONV_o, CONV_u, CONV_d, CONV_i,
214 CONV_f, CONV_F, CONV_e, CONV_E, CONV_g, CONV_G, CONV_a, CONV_A,
215 CONV_C, CONV_S, CONV_c, CONV_s,
216 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
219 CONV_custom0 /* must be last */
223 #define SPEC_BASE { 16, 16, 16, 8, 10, 10, 10 }
225 #define SPEC_RANGES { CONV_n, CONV_p, CONV_i, CONV_A, \
226 CONV_C, CONV_S, CONV_c, CONV_s, CONV_custom0 }
228 #define SPEC_OR_MASK { \
229 /* n */ (PA_FLAG_PTR|PA_INT), \
230 /* p */ PA_POINTER, \
231 /* oxXudi */ PA_INT, \
232 /* fFeEgGaA */ PA_DOUBLE, \
234 /* S */ PA_WSTRING, \
239 #define SPEC_AND_MASK { \
240 /* n */ (PA_FLAG_PTR|__PA_INTMASK), \
241 /* p */ PA_POINTER, \
242 /* oxXudi */ (__PA_INTMASK), \
243 /* fFeEgGaA */ (PA_FLAG_LONG_DOUBLE|PA_DOUBLE), \
244 /* C */ (PA_WCHAR), \
245 /* S */ (PA_WSTRING), \
247 /* s */ (PA_STRING), \
250 /**********************************************************************/
252 * In order to ease translation to what arginfo and _print_info._flags expect,
253 * we map: 0:int 1:char 2:longlong 4:long 8:short
254 * and then _flags |= (((q << 7) + q) & 0x701) and argtype |= (_flags & 0x701)
257 /* TODO -- Fix the table below to take into account stdint.h. */
258 /* #ifndef LLONG_MAX */
259 /* #error fix QUAL_CHARS for no long long! Affects 'L', 'j', 'q', 'll'. */
261 /* #if LLONG_MAX != INTMAX_MAX */
262 /* #error fix QUAL_CHARS intmax_t entry 'j'! */
267 # error PDS already defined!
270 # error SS already defined!
273 # error IMS already defined!
276 #if PTRDIFF_MAX == INT_MAX
278 #elif PTRDIFF_MAX == LONG_MAX
280 #elif defined(LLONG_MAX) && (PTRDIFF_MAX == LLONG_MAX)
283 # error fix QUAL_CHARS ptrdiff_t entry 't'!
286 #if SIZE_MAX == UINT_MAX
288 #elif SIZE_MAX == ULONG_MAX
290 #elif defined(LLONG_MAX) && (SIZE_MAX == ULLONG_MAX)
293 # error fix QUAL_CHARS size_t entries 'z', 'Z'!
296 #if INTMAX_MAX == INT_MAX
298 #elif INTMAX_MAX == LONG_MAX
300 #elif defined(LLONG_MAX) && (INTMAX_MAX == LLONG_MAX)
303 # error fix QUAL_CHARS intmax_t entry 'j'!
306 #define QUAL_CHARS { \
307 /* j:(u)intmax_t z:(s)size_t t:ptrdiff_t \0:int */ \
308 /* q:long_long Z:(s)size_t */ \
309 'h', 'l', 'L', 'j', 'z', 't', 'q', 'Z', 0, \
310 2, 4, 8, IMS, SS, PDS, 8, SS, 0, /* TODO -- fix!!! */\
314 /**********************************************************************/
316 #ifdef __STDIO_VA_ARG_PTR
318 # define __va_arg_ptr(ap,type) (((type *)(ap += sizeof(type))) - 1)
323 /* TODO -- need other than for 386 as well! */
325 # ifndef __va_rounded_size
326 # define __va_rounded_size(TYPE) \
327 (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
329 # define __va_arg_ptr(AP, TYPE) \
330 (AP = (va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \
331 ((void *) ((char *) (AP) - __va_rounded_size (TYPE))) \
335 #endif /* __STDIO_VA_ARG_PTR */
338 # define GET_VA_ARG(AP,F,TYPE,ARGS) (*(AP) = __va_arg_ptr(ARGS,TYPE))
339 # define GET_ARG_VALUE(AP,F,TYPE) (*((TYPE *)(*(AP))))
346 unsigned long long ull;
348 # ifdef __UCLIBC_HAS_FLOATS__
355 # define GET_VA_ARG(AU,F,TYPE,ARGS) (AU->F = va_arg(ARGS,TYPE))
356 # define GET_ARG_VALUE(AU,F,TYPE) ((TYPE)((AU)->F))
360 const char *fmtpos; /* TODO: move below struct?? */
361 struct printf_info info;
363 int maxposarg; /* > 0 if args are positional, 0 if not, -1 if unknown */
365 int num_data_args; /* TODO: use sentinal??? */
366 unsigned int conv_num;
367 unsigned char argnumber[4]; /* width | prec | 1st data | unused */
368 int argtype[MAX_ARGS];
371 void *argptr[MAX_ARGS];
373 /* if defined(NL_ARGMAX) || defined(__UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__) */
374 /* While this is wasteful of space in the case where pos args aren't
375 * enabled, it is also needed to support custom printf handlers. */
376 argvalue_t argvalue[MAX_ARGS];
378 } ppfs_t; /* parse printf format state */
380 /**********************************************************************/
382 /* TODO: fix printf to return 0 and set errno if format error. Standard says
383 only returns -1 if sets error indicator for the stream. */
385 extern int _ppfs_init(ppfs_t *ppfs, const char *fmt0) attribute_hidden; /* validates */
386 extern void _ppfs_prepargs(ppfs_t *ppfs, va_list arg) attribute_hidden; /* sets posargptrs */
387 extern void _ppfs_setargs(ppfs_t *ppfs) attribute_hidden; /* sets argptrs for current spec */
388 extern int _ppfs_parsespec(ppfs_t *ppfs) attribute_hidden; /* parses specifier */
390 /**********************************************************************/
391 #ifdef L_parse_printf_format
393 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
395 /* NOTE: This function differs from the glibc version in that parsing stops
396 * upon encountering an invalid conversion specifier. Since this is the way
397 * my printf functions work, I think it makes sense to do it that way here.
398 * Unfortunately, since glibc sets the return type as size_t, we have no way
399 * of returning that the template is illegal, other than returning 0.
402 size_t parse_printf_format(register const char *template,
403 size_t n, register int *argtypes)
409 if (_ppfs_init(&ppfs, template) >= 0) {
411 if (ppfs.maxposarg > 0) {
412 /* Using positional args. */
413 count = ppfs.maxposarg;
417 for (i = 0 ; i < n ; i++) {
418 *argtypes++ = ppfs.argtype[i];
423 /* Not using positional args. */
425 if ((*template == '%') && (*++template != '%')) {
426 ppfs.fmtpos = template;
427 _ppfs_parsespec(&ppfs); /* Can't fail. */
428 template = ppfs.fmtpos; /* Update to one past spec end. */
429 if (ppfs.info.width == INT_MIN) {
432 *argtypes++ = PA_INT;
436 if (ppfs.info.prec == INT_MIN) {
439 *argtypes++ = PA_INT;
443 for (i = 0 ; i < ppfs.num_data_args ; i++) {
444 if ((ppfs.argtype[i]) != __PA_NOARG) {
447 *argtypes++ = ppfs.argtype[i];
465 /**********************************************************************/
468 int attribute_hidden _ppfs_init(register ppfs_t *ppfs, const char *fmt0)
472 /* First, zero out everything... argnumber[], argtype[], argptr[] */
473 memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */
475 --ppfs->maxposarg; /* set to -1 */
478 #ifdef __UCLIBC_MJN3_ONLY__
479 # warning TODO: Make checking of the format string in C locale an option.
481 #ifdef __UCLIBC_HAS_LOCALE__
482 /* To support old programs, don't check mb validity if in C locale. */
483 if (__UCLIBC_CURLOCALE->encoding != __ctype_encoding_7_bit) {
484 /* ANSI/ISO C99 requires format string to be a valid multibyte string
485 * beginning and ending in its initial shift state. */
486 static const char invalid_mbs[] = "Invalid multibyte format string.";
489 mbstate.__mask = 0; /* Initialize the mbstate. */
491 if (mbsrtowcs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) {
492 ppfs->fmtpos = invalid_mbs;
496 #endif /* __UCLIBC_HAS_LOCALE__ */
497 /* now set all argtypes to no-arg */
500 /* TODO - use memset here since already "paid for"? */
501 register int *p = ppfs->argtype;
508 /* TODO -- get rid of this?? */
509 register char *p = (char *) ((MAX_ARGS-1) * sizeof(int));
512 *((int *)(((char *)ppfs) + ((int)p) + offsetof(ppfs_t,argtype))) = __PA_NOARG;
519 * Run through the entire format string to validate it and initialize
520 * the positional arg numbers (if any).
523 register const char *fmt = fmt0;
526 if ((*fmt == '%') && (*++fmt != '%')) {
527 ppfs->fmtpos = fmt; /* back up to the '%' */
528 r = _ppfs_parsespec(ppfs);
532 fmt = ppfs->fmtpos; /* update to one past end of spec */
537 ppfs->fmtpos = fmt0; /* rewind */
541 /* If we have positional args, make sure we know all the types. */
543 register int *p = ppfs->argtype;
546 if ( *p == __PA_NOARG ) { /* missing arg type!!! */
552 #endif /* NL_ARGMAX */
557 /**********************************************************************/
558 #ifdef L__ppfs_prepargs
559 void attribute_hidden _ppfs_prepargs(register ppfs_t *ppfs, va_list arg)
563 va_copy(ppfs->arg, arg);
566 i = ppfs->maxposarg; /* init for positional args */
568 ppfs->num_data_args = i;
569 ppfs->info.width = ppfs->info.prec = ppfs->maxposarg = 0;
576 /**********************************************************************/
577 #ifdef L__ppfs_setargs
579 void attribute_hidden _ppfs_setargs(register ppfs_t *ppfs)
582 register void **p = ppfs->argptr;
584 register argvalue_t *p = ppfs->argvalue;
589 if (ppfs->maxposarg == 0) { /* initing for or no pos args */
591 if (ppfs->info.width == INT_MIN) {
596 GET_VA_ARG(p,u,unsigned int,ppfs->arg);
598 if (ppfs->info.prec == INT_MIN) {
603 GET_VA_ARG(p,u,unsigned int,ppfs->arg);
606 while (i < ppfs->num_data_args) {
607 switch(ppfs->argtype[i++]) {
608 case (PA_INT|PA_FLAG_LONG_LONG):
610 GET_VA_ARG(p,ull,unsigned long long,ppfs->arg);
613 case (PA_INT|PA_FLAG_LONG):
614 #if ULONG_MAX != UINT_MAX
615 GET_VA_ARG(p,ul,unsigned long,ppfs->arg);
618 case PA_CHAR: /* TODO - be careful */
619 /* ... users could use above and really want below!! */
620 case (PA_INT|__PA_FLAG_CHAR):/* TODO -- translate this!!! */
621 case (PA_INT|PA_FLAG_SHORT):
623 GET_VA_ARG(p,u,unsigned int,ppfs->arg);
625 case PA_WCHAR: /* TODO -- assume int? */
626 /* we're assuming wchar_t is at least an int */
627 GET_VA_ARG(p,wc,wchar_t,ppfs->arg);
629 #ifdef __UCLIBC_HAS_FLOATS__
632 GET_VA_ARG(p,d,double,ppfs->arg);
634 case (PA_DOUBLE|PA_FLAG_LONG_DOUBLE):
635 GET_VA_ARG(p,ld,long double,ppfs->arg);
637 #else /* __UCLIBC_HAS_FLOATS__ */
639 case (PA_DOUBLE|PA_FLAG_LONG_DOUBLE):
642 #endif /* __UCLIBC_HAS_FLOATS__ */
644 /* TODO -- really need to ensure this can't happen */
645 assert(ppfs->argtype[i-1] & PA_FLAG_PTR);
649 GET_VA_ARG(p,p,void *,ppfs->arg);
658 if (ppfs->info.width == INT_MIN) {
660 = (int) GET_ARG_VALUE(p + ppfs->argnumber[0] - 1,u,unsigned int);
662 if (ppfs->info.prec == INT_MIN) {
664 = (int) GET_ARG_VALUE(p + ppfs->argnumber[1] - 1,u,unsigned int);
667 #endif /* NL_ARGMAX */
669 /* Now we know the width and precision. */
670 if (ppfs->info.width < 0) {
671 ppfs->info.width = -ppfs->info.width;
672 PRINT_INFO_SET_FLAG(&(ppfs->info),left);
673 PRINT_INFO_CLR_FLAG(&(ppfs->info),space);
674 ppfs->info.pad = ' ';
677 /* NOTE -- keep neg for now so float knows! */
678 if (ppfs->info.prec < 0) { /* spec says treat as omitted. */
679 /* so use default prec... 1 for everything but floats and strings. */
685 /**********************************************************************/
686 #ifdef L__ppfs_parsespec
688 /* Notes: argtype differs from glibc for the following:
690 * lc PA_WCHAR PA_CHAR the standard says %lc means %C
691 * ls PA_WSTRING PA_STRING the standard says %ls means %S
692 * {*}n {*}|PA_FLAG_PTR PA_FLAG_PTR size of n can be qualified
695 /* TODO: store positions of positional args */
697 /* TODO -- WARNING -- assumes aligned on integer boundaries!!! */
699 /* TODO -- disable if not using positional args!!! */
700 #define _OVERLAPPING_DIFFERENT_ARGS
702 /* TODO -- rethink this -- perhaps we should set to largest type??? */
704 #ifdef _OVERLAPPING_DIFFERENT_ARGS
706 #define PROMOTED_SIZE_OF(X) ((sizeof(X) + sizeof(int) - 1) / sizeof(X))
708 static const short int type_codes[] = {
709 __PA_NOARG, /* must be first entry */
714 PA_INT|PA_FLAG_SHORT,
717 PA_INT|PA_FLAG_LONG_LONG,
719 #ifdef __UCLIBC_HAS_FLOATS__
722 PA_DOUBLE|PA_FLAG_LONG_DOUBLE,
726 static const unsigned char type_sizes[] = {
727 /* unknown type consumes no arg */
728 0, /* must be first entry */
729 PROMOTED_SIZE_OF(void *),
730 PROMOTED_SIZE_OF(char *),
731 PROMOTED_SIZE_OF(wchar_t *),
732 PROMOTED_SIZE_OF(char),
733 PROMOTED_SIZE_OF(short),
734 PROMOTED_SIZE_OF(int),
735 PROMOTED_SIZE_OF(long),
737 PROMOTED_SIZE_OF(long long),
739 PROMOTED_SIZE_OF(long), /* TODO -- is this correct? (above too) */
741 PROMOTED_SIZE_OF(wchar_t),
742 #ifdef __UCLIBC_HAS_FLOATS__
743 /* PROMOTED_SIZE_OF(float), */
744 PROMOTED_SIZE_OF(double),
745 PROMOTED_SIZE_OF(long double),
749 static int _promoted_size(int argtype)
751 register const short int *p;
753 /* note -- since any unrecognized type is treated as a pointer */
754 p = type_codes + sizeof(type_codes)/sizeof(type_codes[0]);
756 if (*--p == argtype) {
759 } while (p > type_codes);
761 return type_sizes[(int)(p - type_codes)];
764 static int _is_equal_or_bigger_arg(int curtype, int newtype)
767 if (newtype == __PA_NOARG) {
770 if ((curtype == __PA_NOARG) || (curtype == newtype)) {
773 /* Ok... slot is already filled and types are different in name. */
774 /* So, compare promoted sizes of curtype and newtype args. */
775 return _promoted_size(curtype) <= _promoted_size(newtype);
780 #define _is_equal_or_bigger_arg(C,N) (((C) == __PA_NOARG) || ((C) == (N)))
784 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
785 /* TODO - do this differently? */
786 static char _bss_custom_printf_spec[MAX_USER_SPEC]; /* 0-init'd for us. */
788 attribute_hidden char *_custom_printf_spec = _bss_custom_printf_spec;
789 attribute_hidden printf_arginfo_function *_custom_printf_arginfo[MAX_USER_SPEC];
790 attribute_hidden printf_function _custom_printf_handler[MAX_USER_SPEC];
791 #endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
793 int attribute_hidden _ppfs_parsespec(ppfs_t *ppfs)
795 register const char *fmt;
796 register const char *p;
808 int argtype[MAX_ARGS_PER_SPEC+2];
809 int argnumber[3]; /* width, precision, 1st data arg */
810 static const char spec_flags[] = SPEC_FLAGS;
811 static const char spec_chars[] = SPEC_CHARS;/* TODO: b? */
812 static const char spec_ranges[] = SPEC_RANGES;
813 static const short spec_or_mask[] = SPEC_OR_MASK;
814 static const short spec_and_mask[] = SPEC_AND_MASK;
815 static const char qual_chars[] = QUAL_CHARS;
816 #ifdef __UCLIBC_HAS_WCHAR__
820 /* WIDE note: we can test against '%' here since we don't allow */
821 /* WIDE note: other mappings of '%' in the wide char set. */
825 argtype[0] = __PA_NOARG;
826 argtype[1] = __PA_NOARG;
828 maxposarg = ppfs->maxposarg;
831 #ifdef __UCLIBC_HAS_WCHAR__
832 /* This is somewhat lame, but saves a lot of code. If we're dealing with
833 * a wide stream, that means the format is a wchar string. So, copy it
834 * char-by-char into a normal char buffer for processing. Make the buffer
835 * (buf) big enough so that any reasonable format specifier will fit.
836 * While there a legal specifiers that won't, the all involve duplicate
837 * flags or outrageous field widths/precisions. */
839 flags = ppfs->info._flags & FLAG_WIDESTREAM;
846 buf[i] = (char) (((wchar_t *) ppfs->fmtpos)[i-1]);
847 if (buf[i] != (((wchar_t *) ppfs->fmtpos)[i-1])) {
850 } while (buf[i++] && (i < sizeof(buf)));
851 buf[sizeof(buf)-1] = 0;
853 #else /* __UCLIBC_HAS_WCHAR__ */
854 width = flags = dpoint = 0;
858 assert(fmt[-1] == '%');
859 assert(fmt[0] != '%');
861 /* Process arg pos and/or flags and/or width and/or precision. */
865 argtype[-dpoint] = PA_INT;
869 while (isdigit(*fmt)) {
871 || (i == INT_MAX / 10 && (*fmt - '0') <= INT_MAX % 10)) {
872 i = (i * 10) + (*fmt - '0');
874 i = INT_MAX; /* best we can do... */
878 if (p[-1] == '%') { /* Check for a position. */
880 /* TODO: if val not in range, then error */
883 if ((*fmt == '$') && (i > 0)) {/* Positional spec. */
885 if (maxposarg == 0) {
889 if (argnumber[2] > maxposarg) {
892 /* Now fall through to check flags. */
895 # ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
896 # ifdef __UCLIBC_MJN3_ONLY__
897 # warning TODO: Support prec and width for %m when positional args used
898 /* Actually, positional arg processing will fail in general
899 * for specifiers that don't require an arg. */
904 # endif /* __UCLIBC_HAS_PRINTF_M_SPEC__ */
907 maxposarg = 0; /* Possible redundant store, but cuts size. */
909 if ((fmt > p) && (*p != '0')) {
913 fmt = p; /* Back up for possible '0's flag. */
914 /* Now fall through to check flags. */
916 #else /* NL_ARGMAX */
917 if (*fmt == '$') { /* Positional spec. */
921 if ((fmt > p) && (*p != '0')) {
925 fmt = p; /* Back up for possible '0's flag. */
926 /* Now fall through to check flags. */
927 #endif /* NL_ARGMAX */
929 restart_flags: /* Process flags. */
939 i += i; /* Better than i <<= 1 for bcc */
943 /* If '+' then ignore ' ', and if '-' then ignore '0'. */
944 /* Note: Need to ignore '0' when prec is an arg with val < 0, */
945 /* but that test needs to wait until the arg is retrieved. */
946 flags &= ~((flags & (FLAG_PLUS|FLAG_MINUS)) >> 1);
947 /* Note: Ignore '0' when prec is specified < 0 too (in printf). */
949 if (fmt[-1] != '%') { /* If we've done anything, loop for width. */
950 goto width_precision;
954 if (*p == '*') { /* Prec or width takes an arg. */
957 if ((*fmt++ != '$') || (i <= 0)) {
958 /* Using pos args and no $ or invalid arg number. */
961 argnumber[-dpoint] = i;
965 /* Not using pos args but digits followed *. */
975 dpoint = -1; /* To use as default precison. */
976 goto width_precision;
982 /* Process qualifier. */
990 if ((p - qual_chars < 2) && (*fmt == *p)) {
991 p += ((sizeof(qual_chars)-2) / 2);
994 dataargtype = ((int)(p[(sizeof(qual_chars)-2) / 2])) << 8;
996 /* Process conversion specifier. */
1005 p_m_spec_chars = p - spec_chars;
1007 if ((p_m_spec_chars >= CONV_c)
1008 && (dataargtype & PA_FLAG_LONG)) {
1009 p_m_spec_chars -= 2; /* lc -> C and ls -> S */
1012 ppfs->conv_num = p_m_spec_chars;
1014 while (p_m_spec_chars > *++p) {}
1016 i = p - spec_ranges;
1017 argtype[2] = (dataargtype | spec_or_mask[i]) & spec_and_mask[i];
1023 ppfs->info.spec = *fmt;
1024 ppfs->info.prec = preci;
1025 ppfs->info.width = width;
1026 ppfs->info.pad = ((flags & FLAG_ZERO) ? '0' : ' ');
1027 ppfs->info._flags = (flags & ~FLAG_ZERO) | (dataargtype & __PA_INTMASK);
1028 ppfs->num_data_args = 1;
1031 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1033 ppfs->conv_num = CONV_m;
1034 ppfs->num_data_args = 0;
1038 #ifndef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
1039 return -1; /* Error */
1041 /* Handle custom arg -- WARNING -- overwrites p!!! */
1042 ppfs->conv_num = CONV_custom0;
1043 p = _custom_printf_spec;
1046 printf_arginfo_function *fp = _custom_printf_arginfo[(int)(p - _custom_printf_spec)];
1047 ppfs->num_data_args = fp(&(ppfs->info), MAX_ARGS_PER_SPEC, argtype + 2);
1048 if (ppfs->num_data_args > MAX_ARGS_PER_SPEC) {
1049 return -1; /* Error -- too many args! */
1053 if (++p >= (_custom_printf_spec + MAX_USER_SPEC))
1054 return -1; /* Error */
1061 if (maxposarg > 0) {
1064 /* Update maxposarg and check that NL_ARGMAX is not exceeded. */
1066 ? (ppfs->argnumber[i] = argnumber[i])
1067 : argnumber[2] + (i-2));
1068 if (n > maxposarg) {
1070 if (maxposarg > NL_ARGMAX) {
1075 /* Record argtype with largest size (current, new). */
1076 if (_is_equal_or_bigger_arg(ppfs->argtype[n], argtype[i])) {
1077 ppfs->argtype[n] = argtype[i];
1079 } while (++i < ppfs->num_data_args + 2);
1081 #endif /* NL_ARGMAX */
1083 ppfs->argnumber[2] = 1;
1084 memcpy(ppfs->argtype, argtype + 2, ppfs->num_data_args * sizeof(int));
1088 ppfs->maxposarg = maxposarg;
1091 #ifdef __UCLIBC_HAS_WCHAR__
1092 flags = ppfs->info._flags & FLAG_WIDESTREAM;
1094 ppfs->fmtpos = ++fmt;
1096 ppfs->fmtpos = (const char *) (((const wchar_t *)(ppfs->fmtpos))
1099 #else /* __UCLIBC_HAS_WCHAR__ */
1100 ppfs->fmtpos = ++fmt;
1103 return ppfs->num_data_args + 2;
1107 /**********************************************************************/
1108 #ifdef L_register_printf_function
1110 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
1112 int register_printf_function(int spec, printf_function handler,
1113 printf_arginfo_function arginfo)
1118 if (spec && (arginfo != NULL)) { /* TODO -- check if spec is valid char */
1120 p = _custom_printf_spec + MAX_USER_SPEC;
1127 else /* bcc generates less code with fall-through */
1131 p = _custom_printf_spec;
1133 } while (p > _custom_printf_spec);
1138 _custom_printf_handler[(int)(r - p)] = handler;
1139 _custom_printf_arginfo[(int)(r - p)] = arginfo;
1145 /* TODO -- if asked to unregister a non-existent spec, return what? */
1153 /**********************************************************************/
1154 #if defined(L__vfprintf_internal) || defined(L__vfwprintf_internal)
1156 /* We only support ascii digits (or their USC equivalent codes) in
1157 * precision and width settings in *printf (wide) format strings.
1158 * In other words, we don't currently support glibc's 'I' flag.
1159 * We do accept it, but it is currently ignored. */
1161 static size_t _charpad(FILE * __restrict stream, int padchar, size_t numpad);
1163 #ifdef L__vfprintf_internal
1165 #define VFPRINTF_internal _vfprintf_internal
1166 #define FMT_TYPE char
1167 #define OUTNSTR _outnstr
1168 #define STRLEN strlen
1169 #define _PPFS_init _ppfs_init
1170 #define OUTPUT(F,S) fputs_unlocked(S,F)
1171 /* #define _outnstr(stream, string, len) __stdio_fwrite(string, len, stream) */
1172 #define _outnstr(stream, string, len) ((len > 0) ? __stdio_fwrite((const unsigned char *)(string), len, stream) : 0)
1173 #define FP_OUT _fp_out_narrow
1175 #ifdef __UCLIBC_HAS_FLOATS__
1177 static size_t _fp_out_narrow(FILE *fp, intptr_t type, intptr_t len, intptr_t buf)
1181 if (type & 0x80) { /* Some type of padding needed. */
1182 int buflen = strlen((const char *) buf);
1185 r = _charpad(fp, (type & 0x7f), len);
1192 return r + OUTNSTR(fp, (const char *) buf, len);
1195 #endif /* __UCLIBC_HAS_FLOATS__ */
1197 #else /* L__vfprintf_internal */
1199 #define VFPRINTF_internal _vfwprintf_internal
1200 #define FMT_TYPE wchar_t
1201 #define OUTNSTR _outnwcs
1202 #define STRLEN wcslen
1203 #define _PPFS_init _ppwfs_init
1204 /* Pulls in fseek: */
1205 #define OUTPUT(F,S) fputws(S,F)
1206 /* TODO: #define OUTPUT(F,S) _wstdio_fwrite((S),wcslen(S),(F)) */
1207 #define _outnwcs(stream, wstring, len) _wstdio_fwrite((const wchar_t *)(wstring), len, stream)
1208 #define FP_OUT _fp_out_wide
1210 static size_t _outnstr(FILE *stream, const char *s, size_t wclen)
1212 /* NOTE!!! len here is the number of wchars we want to generate!!! */
1221 r = mbsrtowcs(wbuf, &s,
1222 ((todo <= sizeof(wbuf)/sizeof(wbuf[0]))
1224 : sizeof(wbuf)/sizeof(wbuf[0])),
1226 assert(((ssize_t)r) > 0);
1227 n = _outnwcs(stream, wbuf, r);
1234 return wclen - todo;
1237 #ifdef __UCLIBC_HAS_FLOATS__
1239 static size_t _fp_out_wide(FILE *fp, intptr_t type, intptr_t len, intptr_t buf)
1241 wchar_t wbuf[BUF_SIZE];
1242 const char *s = (const char *) buf;
1246 if (type & 0x80) { /* Some type of padding needed */
1247 int buflen = strlen(s);
1250 r = _charpad(fp, (type & 0x7f), len);
1261 #ifdef __LOCALE_C_ONLY
1265 # ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
1267 wbuf[i] = __UCLIBC_CURLOCALE->thousands_sep_wc;
1271 wbuf[i] = __UCLIBC_CURLOCALE->decimal_point_wc;
1275 #endif /* __LOCALE_C_ONLY */
1277 } while (++i < len);
1279 r += OUTNSTR(fp, wbuf, len);
1285 #endif /* __UCLIBC_HAS_FLOATS__ */
1287 static int _ppwfs_init(register ppfs_t *ppfs, const wchar_t *fmt0)
1289 static const wchar_t invalid_wcs[] = L"Invalid wide format string.";
1292 /* First, zero out everything... argnumber[], argtype[], argptr[] */
1293 memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */
1295 --ppfs->maxposarg; /* set to -1 */
1297 ppfs->fmtpos = (const char *) fmt0;
1298 ppfs->info._flags = FLAG_WIDESTREAM;
1303 mbstate.__mask = 0; /* Initialize the mbstate. */
1305 if (wcsrtombs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) {
1306 ppfs->fmtpos = (const char *) invalid_wcs;
1311 /* now set all argtypes to no-arg */
1314 /* TODO - use memset here since already "paid for"? */
1315 register int *p = ppfs->argtype;
1322 /* TODO -- get rid of this?? */
1323 register char *p = (char *) ((MAX_ARGS-1) * sizeof(int));
1326 *((int *)(((char *)ppfs) + ((int)p) + offsetof(ppfs_t,argtype))) = __PA_NOARG;
1333 * Run through the entire format string to validate it and initialize
1334 * the positional arg numbers (if any).
1337 register const wchar_t *fmt = fmt0;
1340 if ((*fmt == '%') && (*++fmt != '%')) {
1341 ppfs->fmtpos = (const char *) fmt; /* back up to the '%' */
1342 r = _ppfs_parsespec(ppfs);
1346 fmt = (const wchar_t *) ppfs->fmtpos; /* update to one past end of spec */
1351 ppfs->fmtpos = (const char *) fmt0; /* rewind */
1355 /* If we have positional args, make sure we know all the types. */
1357 register int *p = ppfs->argtype;
1358 r = ppfs->maxposarg;
1360 if ( *p == __PA_NOARG ) { /* missing arg type!!! */
1366 #endif /* NL_ARGMAX */
1371 #endif /* L__vfprintf_internal */
1374 static size_t _charpad(FILE * __restrict stream, int padchar, size_t numpad)
1376 size_t todo = numpad;
1378 /* TODO -- Use a buffer to cut down on function calls... */
1382 while (todo && (OUTNSTR(stream, (const char *) pad, 1) == 1)) {
1386 return numpad - todo;
1389 /* TODO -- Dynamically allocate work space to accomodate stack-poor archs? */
1390 static int _do_one_spec(FILE * __restrict stream,
1391 register ppfs_t *ppfs, int *count)
1393 static const char spec_base[] = SPEC_BASE;
1394 #ifdef L__vfprintf_internal
1395 static const char prefix[] = "+\0-\0 \0000x\0000X";
1398 static const wchar_t prefix[] = L"+\0-\0 \0000x\0000X";
1410 const void * const *argptr;
1412 const void * argptr[MAX_ARGS_PER_SPEC];
1415 #ifdef __UCLIBC_HAS_WCHAR__
1416 const wchar_t *ws = NULL;
1420 #ifdef L__vfprintf_internal
1429 int numfill = 0; /* TODO: fix */
1430 int prefix_num = PREFIX_NONE;
1432 #ifdef __UCLIBC_MJN3_ONLY__
1433 #warning TODO: Determine appropriate buf size.
1435 /* TODO: buf needs to be big enough for any possible error return strings
1436 * and also for any locale-grouped long long integer strings generated.
1437 * This should be large enough for any of the current archs/locales, but
1438 * eventually this should be handled robustly. */
1442 _ppfs_parsespec(ppfs);
1444 if (_ppfs_parsespec(ppfs) < 0) { /* TODO: just for debugging */
1448 _ppfs_setargs(ppfs);
1450 argtype = ppfs->argtype + ppfs->argnumber[2] - 1;
1451 /* Deal with the argptr vs argvalue issue. */
1453 argptr = (const void * const *) ppfs->argptr;
1455 if (ppfs->maxposarg > 0) { /* Using positional args... */
1456 argptr += ppfs->argnumber[2] - 1;
1460 /* Need to build a local copy... */
1462 register argvalue_t *p = ppfs->argvalue;
1465 if (ppfs->maxposarg > 0) { /* Using positional args... */
1466 p += ppfs->argnumber[2] - 1;
1469 for (i = 0 ; i < ppfs->num_data_args ; i++ ) {
1470 argptr[i] = (void *) p++;
1475 register char *s = NULL; /* TODO: Should s be unsigned char * ? */
1477 if (ppfs->conv_num == CONV_n) {
1478 _store_inttype(*(void **)*argptr,
1479 ppfs->info._flags & __PA_INTMASK,
1480 (intmax_t) (*count));
1483 if (ppfs->conv_num <= CONV_i) { /* pointer or (un)signed int */
1484 alphacase = __UIM_LOWER;
1486 #ifdef __UCLIBC_MJN3_ONLY__
1487 #ifdef L__vfprintf_internal
1488 #warning CONSIDER: Should we ignore these flags if stub locale? What about custom specs?
1491 base = spec_base[(int)(ppfs->conv_num - CONV_p)];
1493 if (PRINT_INFO_FLAG_VAL(&(ppfs->info),group)) {
1494 alphacase = __UIM_GROUP;
1496 if (PRINT_INFO_FLAG_VAL(&(ppfs->info),i18n)) {
1501 if (ppfs->conv_num <= CONV_u) { /* pointer or unsigned int */
1502 if (ppfs->conv_num == CONV_X) {
1503 alphacase = __UIM_UPPER;
1505 if (ppfs->conv_num == CONV_p) { /* pointer */
1506 prefix_num = PREFIX_LWR_X;
1507 } else { /* unsigned int */
1509 } else { /* signed int */
1512 if (ppfs->info.prec < 0) { /* Ignore '0' flag if prec specified. */
1513 padchar = ppfs->info.pad;
1515 #ifdef __UCLIBC_MJN3_ONLY__
1516 #ifdef L__vfprintf_internal
1517 #warning CONSIDER: If using outdigits and/or grouping, how should we interpret precision?
1520 s = _uintmaxtostr(buf + sizeof(buf) - 1,
1522 _load_inttype(ppfs->conv_num == CONV_p ? PA_FLAG_LONG : *argtype & __PA_INTMASK,
1523 *argptr, base), base, alphacase);
1524 if (ppfs->conv_num > CONV_u) { /* signed int */
1526 PRINT_INFO_SET_FLAG(&(ppfs->info),showsign);
1527 ++s; /* handle '-' in the prefix string */
1528 prefix_num = PREFIX_MINUS;
1529 } else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),showsign)) {
1530 prefix_num = PREFIX_PLUS;
1531 } else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),space)) {
1532 prefix_num = PREFIX_SPACE;
1535 slen = (char *)(buf + sizeof(buf) - 1) - s;
1536 #ifdef L__vfwprintf_internal
1539 mbstate.__mask = 0; /* Initialize the mbstate. */
1540 SLEN = mbsrtowcs(NULL, &q, 0, &mbstate);
1543 numfill = ((ppfs->info.prec < 0) ? 1 : ppfs->info.prec);
1544 if (PRINT_INFO_FLAG_VAL(&(ppfs->info),alt)) {
1545 if (ppfs->conv_num <= CONV_x) { /* x or p */
1546 prefix_num = PREFIX_LWR_X;
1548 if (ppfs->conv_num == CONV_X) {
1549 prefix_num = PREFIX_UPR_X;
1551 if ((ppfs->conv_num == CONV_o) && (numfill <= SLEN)) {
1552 numfill = ((*s == '0') ? 1 : SLEN + 1);
1556 if (prefix_num >= PREFIX_LWR_X) {
1557 prefix_num = PREFIX_NONE;
1559 if (ppfs->conv_num == CONV_p) {/* null pointer */
1561 #ifdef L__vfwprintf_internal
1566 } else if (numfill == 0) { /* if precision 0, no output */
1567 #ifdef L__vfwprintf_internal
1573 numfill = ((numfill > SLEN) ? numfill - SLEN : 0);
1574 } else if (ppfs->conv_num <= CONV_A) { /* floating point */
1575 #ifdef __UCLIBC_HAS_FLOATS__
1577 nf = _fpmaxtostr(stream,
1579 (PRINT_INFO_FLAG_VAL(&(ppfs->info),is_long_double)
1580 ? *(long double *) *argptr
1581 : (long double) (* (double *) *argptr)),
1582 &ppfs->info, FP_OUT );
1589 #else /* __UCLIBC_HAS_FLOATS__ */
1590 return -1; /* TODO -- try to continue? */
1592 } else if (ppfs->conv_num <= CONV_S) { /* wide char or string */
1593 #ifdef L__vfprintf_internal
1595 #ifdef __UCLIBC_HAS_WCHAR__
1596 mbstate.__mask = 0; /* Initialize the mbstate. */
1597 if (ppfs->conv_num == CONV_S) { /* wide string */
1598 ws = *((const wchar_t **) *argptr);
1602 /* We use an awful uClibc-specific hack here, passing
1603 * (char*) &ws as the conversion destination. This signals
1604 * uClibc's wcsrtombs that we want a "restricted" length
1605 * such that the mbs fits in a buffer of the specified
1606 * size with no partial conversions. */
1607 slen = wcsrtombs((char *) &ws, &ws, /* Use awful hack! */
1608 ((ppfs->info.prec >= 0)
1612 if (slen == ((size_t)-1)) {
1613 return -1; /* EILSEQ */
1615 } else { /* wide char */
1617 slen = wcrtomb(s, (*((const wchar_t *) *argptr)), &mbstate);
1618 if (slen == ((size_t)-1)) {
1619 return -1; /* EILSEQ */
1621 s[slen] = 0; /* TODO - Is this necessary? */
1623 #else /* __UCLIBC_HAS_WCHAR__ */
1626 } else if (ppfs->conv_num <= CONV_s) { /* char or string */
1627 if (ppfs->conv_num == CONV_s) { /* string */
1628 s = *((char **) (*argptr));
1630 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1633 slen = strnlen(s, ((ppfs->info.prec >= 0)
1634 ? ppfs->info.prec : SIZE_MAX));
1636 #ifdef __UCLIBC_HAS_WCHAR__
1641 /* Use an empty string rather than truncation if precision is too small. */
1642 if (ppfs->info.prec >= 0 && ppfs->info.prec < slen)
1647 *s = (unsigned char)(*((const int *) *argptr));
1652 #else /* L__vfprintf_internal */
1654 if (ppfs->conv_num == CONV_S) { /* wide string */
1655 ws = *((wchar_t **) (*argptr));
1659 SLEN = wcsnlen(ws, ((ppfs->info.prec >= 0)
1660 ? ppfs->info.prec : SIZE_MAX));
1661 } else { /* wide char */
1662 *wbuf = (wchar_t)(*((const wint_t *) *argptr));
1669 } else if (ppfs->conv_num <= CONV_s) { /* char or string */
1671 if (ppfs->conv_num == CONV_s) { /* string */
1672 #ifdef __UCLIBC_MJN3_ONLY__
1673 #warning TODO: Fix %s for _vfwprintf_internal... output upto illegal sequence?
1675 s = *((char **) (*argptr));
1677 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1680 /* We use an awful uClibc-specific hack here, passing
1681 * (wchar_t*) &mbstate as the conversion destination.
1682 * This signals uClibc's mbsrtowcs that we want a
1683 * "restricted" length such that the mbs fits in a buffer
1684 * of the specified size with no partial conversions. */
1687 mbstate.__mask = 0; /* Initialize the mbstate. */
1688 SLEN = mbsrtowcs((wchar_t *) &mbstate, &q,
1689 ((ppfs->info.prec >= 0)
1690 ? ppfs->info.prec : SIZE_MAX),
1693 if (SLEN == ((size_t)(-1))) {
1694 return -1; /* EILSEQ */
1700 /* Use an empty string rather than truncation if precision is too small. */
1701 if (ppfs->info.prec >= 0 && ppfs->info.prec < slen)
1705 *wbuf = btowc( (unsigned char)(*((const int *) *argptr)) );
1709 #endif /* L__vfprintf_internal */
1711 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1712 } else if (ppfs->conv_num == CONV_m) {
1713 s = __glibc_strerror_r(errno, buf, sizeof(buf));
1714 goto SET_STRING_LEN;
1717 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
1718 assert(ppfs->conv_num == CONV_custom0);
1720 s = _custom_printf_spec;
1722 if (*s == ppfs->info.spec) {
1724 /* TODO -- check return value for sanity? */
1725 rv = (*_custom_printf_handler
1726 [(int)(s-_custom_printf_spec)])
1727 (stream, &ppfs->info, argptr);
1734 } while (++s < (_custom_printf_spec + MAX_USER_SPEC));
1735 #endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
1740 #ifdef __UCLIBC_MJN3_ONLY__
1741 #ifdef L__vfprintf_internal
1742 #warning CONSIDER: If using outdigits and/or grouping, how should we pad?
1749 if (prefix_num != PREFIX_NONE) {
1750 t += ((prefix_num < PREFIX_LWR_X) ? 1 : 2);
1752 numpad = ((ppfs->info.width > t) ? (ppfs->info.width - t) : 0);
1753 *count += t + numpad;
1755 if (padchar == '0') { /* TODO: check this */
1760 /* Now handle the output itself. */
1761 if (!PRINT_INFO_FLAG_VAL(&(ppfs->info),left)) {
1762 if (_charpad(stream, ' ', numpad) != numpad) {
1767 OUTPUT(stream, prefix + prefix_num);
1769 if (_charpad(stream, '0', numfill) != numfill) {
1773 #ifdef L__vfprintf_internal
1775 # ifdef __UCLIBC_HAS_WCHAR__
1778 if (_outnstr(stream, s, slen) != slen) {
1781 } else { /* wide string */
1783 mbstate.__mask = 0; /* Initialize the mbstate. */
1785 t = (slen <= sizeof(buf)) ? slen : sizeof(buf);
1786 t = wcsrtombs(buf, &ws, t, &mbstate);
1787 assert(t != ((size_t)(-1)));
1788 if (_outnstr(stream, buf, t) != t) {
1794 # else /* __UCLIBC_HAS_WCHAR__ */
1795 if (_outnstr(stream, (const unsigned char *) s, slen) != slen) {
1800 #else /* L__vfprintf_internal */
1804 if (_outnstr(stream, s, SLEN) != SLEN) {
1808 if (_outnwcs(stream, ws, SLEN) != SLEN) {
1813 #endif /* L__vfprintf_internal */
1814 if (_charpad(stream, ' ', numpad) != numpad) {
1823 int VFPRINTF_internal (FILE * __restrict stream,
1824 const FMT_TYPE * __restrict format,
1829 register const FMT_TYPE *s;
1834 if (_PPFS_init(&ppfs, format) < 0) { /* Bad format string. */
1835 OUTNSTR(stream, (const char *) ppfs.fmtpos,
1836 STRLEN((const FMT_TYPE *)(ppfs.fmtpos)));
1837 #if defined(L__vfprintf_internal) && !defined(NDEBUG)
1838 fprintf(stderr,"\nIMbS: \"%s\"\n\n", format);
1842 _ppfs_prepargs(&ppfs, arg); /* This did a va_copy!!! */
1845 while (*format && (*format != '%')) {
1849 if (format - s) { /* output any literal text in format string */
1850 r = OUTNSTR(stream, (const char *) s, format - s);
1851 if (r != (format - s)) {
1858 if (!*format) { /* we're done */
1862 if (format[1] != '%') { /* if we get here, *format == '%' */
1863 /* TODO: _do_one_spec needs to know what the output funcs are!!! */
1864 ppfs.fmtpos = (const char *)(++format);
1865 /* TODO: check -- should only fail on stream error */
1866 r = _do_one_spec(stream, &ppfs, &count);
1871 s = format = (const FMT_TYPE *) ppfs.fmtpos;
1872 } else { /* %% means literal %, so start new string */
1878 va_end(ppfs.arg); /* Need to clean up after va_copy! */
1881 /* #if defined(L__vfprintf_internal) && defined(__UCLIBC_HAS_WCHAR__) */
1887 #endif /* defined(L__vfprintf_internal) || defined(L__vfwprintf_internal) */
1890 /**********************************************************************/
1891 #if defined(L_vfprintf) || defined(L_vfwprintf)
1893 /* This is just a wrapper around VFPRINTF_internal.
1894 * Factoring out vfprintf internals allows:
1895 * (1) vdprintf and vsnprintf don't need to setup fake locking,
1896 * (2) __STDIO_STREAM_TRANS_TO_WRITE is not used in vfprintf internals,
1897 * and thus fseek etc is not pulled in by vdprintf and vsnprintf.
1899 * In order to not pull in fseek through fputs, OUTPUT() macro
1900 * is using __stdio_fwrite (TODO: do the same for wide functions).
1903 # define VFPRINTF vfprintf
1904 # define VFPRINTF_internal _vfprintf_internal
1905 # define FMT_TYPE char
1907 # define VFPRINTF vfwprintf
1908 # define VFPRINTF_internal _vfwprintf_internal
1909 # define FMT_TYPE wchar_t
1912 libc_hidden_proto(VFPRINTF)
1913 int VFPRINTF (FILE * __restrict stream,
1914 const FMT_TYPE * __restrict format,
1918 __STDIO_AUTO_THREADLOCK_VAR;
1920 __STDIO_AUTO_THREADLOCK(stream);
1924 (!__STDIO_STREAM_IS_NARROW_WRITING(stream)
1925 && __STDIO_STREAM_TRANS_TO_WRITE(stream, __FLAG_NARROW))
1927 (!__STDIO_STREAM_IS_WIDE_WRITING(stream)
1928 && __STDIO_STREAM_TRANS_TO_WRITE(stream, __FLAG_WIDE))
1933 count = VFPRINTF_internal(stream, format, arg);
1936 __STDIO_AUTO_THREADUNLOCK(stream);
1940 libc_hidden_def(VFPRINTF)
1941 #endif /* defined(L_vfprintf) || defined(L_vfwprintf) */
1943 /**********************************************************************/