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... */
105 #define __PRINTF_INFO_NO_BITFIELD
108 #ifdef __UCLIBC_HAS_THREADS__
109 #include <stdio_ext.h>
111 #endif /* __UCLIBC_HAS_THREADS__ */
113 #ifdef __UCLIBC_HAS_WCHAR__
115 #endif /* __UCLIBC_HAS_WCHAR__ */
117 #include <bits/uClibc_uintmaxtostr.h>
118 #include <bits/uClibc_va_copy.h>
120 /* Experimentally off - libc_hidden_proto(memcpy) */
121 /* Experimentally off - libc_hidden_proto(memset) */
122 /* Experimentally off - libc_hidden_proto(strlen) */
123 /* Experimentally off - libc_hidden_proto(strnlen) */
124 libc_hidden_proto(__glibc_strerror_r)
125 libc_hidden_proto(fputs_unlocked)
126 libc_hidden_proto(abort)
127 #ifdef __UCLIBC_HAS_WCHAR__
128 libc_hidden_proto(wcslen)
129 libc_hidden_proto(wcsnlen)
130 libc_hidden_proto(mbsrtowcs)
131 libc_hidden_proto(wcsrtombs)
132 libc_hidden_proto(btowc)
133 libc_hidden_proto(wcrtomb)
134 libc_hidden_proto(fputws)
137 /* Some older or broken gcc toolchains define LONG_LONG_MAX but not
138 * LLONG_MAX. Since LLONG_MAX is part of the standard, that's what
139 * we use. So complain if we do not have it but should.
141 #if !defined(LLONG_MAX) && defined(LONG_LONG_MAX)
142 #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.
145 /**********************************************************************/
146 /* These provide some control over printf's feature set */
148 /* This is undefined below depeding on uClibc's configuration. */
149 #define __STDIO_PRINTF_FLOAT 1
151 /* Now controlled by uClibc_stdio.h. */
152 /* #define __UCLIBC_HAS_PRINTF_M_SPEC__ */
155 /**********************************************************************/
157 #if defined(__UCLIBC__) && !defined(__UCLIBC_HAS_FLOATS__)
158 #undef __STDIO_PRINTF_FLOAT
162 #undef __STDIO_PRINTF_FLOAT
165 #ifdef __STDIO_PRINTF_FLOAT
167 #include <bits/uClibc_fpmax.h>
168 #else /* __STDIO_PRINTF_FLOAT */
170 #endif /* __STDIO_PRINTF_FLOAT */
173 #undef __STDIO_HAS_VSNPRINTF
174 #if defined(__STDIO_BUFFERS) || defined(__USE_OLD_VFPRINTF__) || defined(__UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__)
175 #define __STDIO_HAS_VSNPRINTF 1
178 /**********************************************************************/
180 /* Now controlled by uClibc_stdio.h. */
181 /* #define __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
183 /* TODO -- move these to a configuration section? */
184 #define MAX_FIELD_WIDTH 4095
186 #ifdef __UCLIBC_MJN3_ONLY__
187 #ifdef L_register_printf_function
189 #warning WISHLIST: Make MAX_USER_SPEC configurable?
190 #warning WISHLIST: Make MAX_ARGS_PER_SPEC configurable?
192 #endif /* __UCLIBC_MJN3_ONLY__ */
194 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
196 #define MAX_USER_SPEC 10
197 #define MAX_ARGS_PER_SPEC 5
199 #else /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
202 #define MAX_ARGS_PER_SPEC 1
204 #endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
206 #if MAX_ARGS_PER_SPEC < 1
207 #error MAX_ARGS_PER_SPEC < 1!
208 #undef MAX_ARGS_PER_SPEC
209 #define MAX_ARGS_PER_SPEC 1
212 #if defined(NL_ARGMAX) && (NL_ARGMAX < 9)
213 #error NL_ARGMAX < 9!
216 #if defined(NL_ARGMAX) && (NL_ARGMAX >= (MAX_ARGS_PER_SPEC + 2))
217 #define MAX_ARGS NL_ARGMAX
219 /* N for spec itself, plus 1 each for width and precision */
220 #define MAX_ARGS (MAX_ARGS_PER_SPEC + 2)
223 /**********************************************************************/
225 #define __PA_FLAG_INTMASK \
226 (__PA_FLAG_CHAR|PA_FLAG_SHORT|__PA_FLAG_INT|PA_FLAG_LONG|PA_FLAG_LONG_LONG)
228 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
229 extern printf_function _custom_printf_handler[MAX_USER_SPEC] attribute_hidden;
230 extern printf_arginfo_function *_custom_printf_arginfo[MAX_USER_SPEC] attribute_hidden;
231 extern char *_custom_printf_spec attribute_hidden;
232 #endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
234 /**********************************************************************/
236 #define SPEC_FLAGS " +0-#'I"
239 FLAG_PLUS = 0x02, /* must be 2 * FLAG_SPACE */
241 FLAG_MINUS = 0x08, /* must be 2 * FLAG_ZERO */
243 FLAG_THOUSANDS = 0x20,
244 FLAG_I18N = 0x40, /* only works for d, i, u */
245 FLAG_WIDESTREAM = 0x80
248 /**********************************************************************/
250 /* float layout 01234567890123456789 TODO: B?*/
251 #define SPEC_CHARS "npxXoudifFeEgGaACScs"
255 CONV_x, CONV_X, CONV_o, CONV_u, CONV_d, CONV_i,
256 CONV_f, CONV_F, CONV_e, CONV_E, CONV_g, CONV_G, CONV_a, CONV_A,
257 CONV_C, CONV_S, CONV_c, CONV_s,
258 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
261 CONV_custom0 /* must be last */
265 #define SPEC_BASE { 16, 16, 16, 8, 10, 10, 10 }
267 #define SPEC_RANGES { CONV_n, CONV_p, CONV_i, CONV_A, \
268 CONV_C, CONV_S, CONV_c, CONV_s, CONV_custom0 }
270 #define SPEC_OR_MASK { \
271 /* n */ (PA_FLAG_PTR|PA_INT), \
272 /* p */ PA_POINTER, \
273 /* oxXudi */ PA_INT, \
274 /* fFeEgGaA */ PA_DOUBLE, \
276 /* S */ PA_WSTRING, \
281 #define SPEC_AND_MASK { \
282 /* n */ (PA_FLAG_PTR|__PA_INTMASK), \
283 /* p */ PA_POINTER, \
284 /* oxXudi */ (__PA_INTMASK), \
285 /* fFeEgGaA */ (PA_FLAG_LONG_DOUBLE|PA_DOUBLE), \
286 /* C */ (PA_WCHAR), \
287 /* S */ (PA_WSTRING), \
289 /* s */ (PA_STRING), \
292 /**********************************************************************/
294 * In order to ease translation to what arginfo and _print_info._flags expect,
295 * we map: 0:int 1:char 2:longlong 4:long 8:short
296 * and then _flags |= (((q << 7) + q) & 0x701) and argtype |= (_flags & 0x701)
299 /* TODO -- Fix the table below to take into account stdint.h. */
300 /* #ifndef LLONG_MAX */
301 /* #error fix QUAL_CHARS for no long long! Affects 'L', 'j', 'q', 'll'. */
303 /* #if LLONG_MAX != INTMAX_MAX */
304 /* #error fix QUAL_CHARS intmax_t entry 'j'! */
309 #error PDS already defined!
312 #error SS already defined!
315 #error IMS already defined!
318 #if PTRDIFF_MAX == INT_MAX
320 #elif PTRDIFF_MAX == LONG_MAX
322 #elif defined(LLONG_MAX) && (PTRDIFF_MAX == LLONG_MAX)
325 #error fix QUAL_CHARS ptrdiff_t entry 't'!
328 #if SIZE_MAX == UINT_MAX
330 #elif SIZE_MAX == ULONG_MAX
332 #elif defined(LLONG_MAX) && (SIZE_MAX == ULLONG_MAX)
335 #error fix QUAL_CHARS size_t entries 'z', 'Z'!
338 #if INTMAX_MAX == INT_MAX
340 #elif INTMAX_MAX == LONG_MAX
342 #elif defined(LLONG_MAX) && (INTMAX_MAX == LLONG_MAX)
345 #error fix QUAL_CHARS intmax_t entry 'j'!
348 #define QUAL_CHARS { \
349 /* j:(u)intmax_t z:(s)size_t t:ptrdiff_t \0:int */ \
350 /* q:long_long Z:(s)size_t */ \
351 'h', 'l', 'L', 'j', 'z', 't', 'q', 'Z', 0, \
352 2, 4, 8, IMS, SS, PDS, 8, SS, 0, /* TODO -- fix!!! */\
356 /**********************************************************************/
358 #ifdef __STDIO_VA_ARG_PTR
360 #define __va_arg_ptr(ap,type) (((type *)(ap += sizeof(type))) - 1)
365 /* TODO -- need other than for 386 as well! */
367 #ifndef __va_rounded_size
368 #define __va_rounded_size(TYPE) \
369 (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
371 #define __va_arg_ptr(AP, TYPE) \
372 (AP = (va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \
373 ((void *) ((char *) (AP) - __va_rounded_size (TYPE))))
376 #endif /* __STDIO_VA_ARG_PTR */
379 #define GET_VA_ARG(AP,F,TYPE,ARGS) (*(AP) = __va_arg_ptr(ARGS,TYPE))
380 #define GET_ARG_VALUE(AP,F,TYPE) (*((TYPE *)(*(AP))))
387 unsigned long long ull;
389 #ifdef __STDIO_PRINTF_FLOAT
392 #endif /* __STDIO_PRINTF_FLOAT */
396 #define GET_VA_ARG(AU,F,TYPE,ARGS) (AU->F = va_arg(ARGS,TYPE))
397 #define GET_ARG_VALUE(AU,F,TYPE) ((TYPE)((AU)->F))
401 const char *fmtpos; /* TODO: move below struct?? */
402 struct printf_info info;
404 int maxposarg; /* > 0 if args are positional, 0 if not, -1 if unknown */
405 #endif /* NL_ARGMAX */
406 int num_data_args; /* TODO: use sentinal??? */
407 unsigned int conv_num;
408 unsigned char argnumber[4]; /* width | prec | 1st data | unused */
409 int argtype[MAX_ARGS];
412 void *argptr[MAX_ARGS];
414 /* if defined(NL_ARGMAX) || defined(__UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__) */
415 /* While this is wasteful of space in the case where pos args aren't
416 * enabled, it is also needed to support custom printf handlers. */
417 argvalue_t argvalue[MAX_ARGS];
419 } ppfs_t; /* parse printf format state */
421 /**********************************************************************/
423 /* TODO: fix printf to return 0 and set errno if format error. Standard says
424 only returns -1 if sets error indicator for the stream. */
426 #ifdef __STDIO_PRINTF_FLOAT
427 typedef size_t (__fp_outfunc_t)(FILE *fp, intptr_t type, intptr_t len,
430 extern ssize_t _fpmaxtostr(FILE * fp, __fpmax_t x, struct printf_info *info,
431 __fp_outfunc_t fp_outfunc) attribute_hidden;
434 extern int _ppfs_init(ppfs_t *ppfs, const char *fmt0) attribute_hidden; /* validates */
435 extern void _ppfs_prepargs(ppfs_t *ppfs, va_list arg) attribute_hidden; /* sets posargptrs */
436 extern void _ppfs_setargs(ppfs_t *ppfs) attribute_hidden; /* sets argptrs for current spec */
437 extern int _ppfs_parsespec(ppfs_t *ppfs) attribute_hidden; /* parses specifier */
439 extern void _store_inttype(void *dest, int desttype, uintmax_t val) attribute_hidden;
440 extern uintmax_t _load_inttype(int desttype, const void *src, int uflag) attribute_hidden;
442 /**********************************************************************/
443 #ifdef L_parse_printf_format
445 /* NOTE: This function differs from the glibc version in that parsing stops
446 * upon encountering an invalid conversion specifier. Since this is the way
447 * my printf functions work, I think it makes sense to do it that way here.
448 * Unfortunately, since glibc sets the return type as size_t, we have no way
449 * of returning that the template is illegal, other than returning 0.
452 size_t parse_printf_format(register const char *template,
453 size_t n, register int *argtypes)
459 if (_ppfs_init(&ppfs, template) >= 0) {
461 if (ppfs.maxposarg > 0) { /* Using positional args. */
462 count = ppfs.maxposarg;
466 for (i = 0 ; i < n ; i++) {
467 *argtypes++ = ppfs.argtype[i];
469 } else { /* Not using positional args. */
470 #endif /* NL_ARGMAX */
472 if ((*template == '%') && (*++template != '%')) {
473 ppfs.fmtpos = template;
474 _ppfs_parsespec(&ppfs); /* Can't fail. */
475 template = ppfs.fmtpos; /* Update to one past spec end. */
476 if (ppfs.info.width == INT_MIN) {
479 *argtypes++ = PA_INT;
483 if (ppfs.info.prec == INT_MIN) {
486 *argtypes++ = PA_INT;
490 for (i = 0 ; i < ppfs.num_data_args ; i++) {
491 if ((ppfs.argtype[i]) != __PA_NOARG) {
494 *argtypes++ = ppfs.argtype[i];
505 #endif /* NL_ARGMAX */
512 /**********************************************************************/
515 int attribute_hidden _ppfs_init(register ppfs_t *ppfs, const char *fmt0)
519 /* First, zero out everything... argnumber[], argtype[], argptr[] */
520 memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */
522 --ppfs->maxposarg; /* set to -1 */
523 #endif /* NL_ARGMAX */
525 #ifdef __UCLIBC_MJN3_ONLY__
526 #warning TODO: Make checking of the format string in C locale an option.
528 #ifdef __UCLIBC_HAS_LOCALE__
529 /* To support old programs, don't check mb validity if in C locale. */
530 if (((__UCLIBC_CURLOCALE_DATA).encoding) != __ctype_encoding_7_bit) {
531 /* ANSI/ISO C99 requires format string to be a valid multibyte string
532 * beginning and ending in its initial shift state. */
533 static const char invalid_mbs[] = "Invalid multibyte format string.";
536 mbstate.__mask = 0; /* Initialize the mbstate. */
538 if (mbsrtowcs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) {
539 ppfs->fmtpos = invalid_mbs;
543 #endif /* __UCLIBC_HAS_LOCALE__ */
544 /* now set all argtypes to no-arg */
547 /* TODO - use memset here since already "paid for"? */
548 register int *p = ppfs->argtype;
555 /* TODO -- get rid of this?? */
556 register char *p = (char *) ((MAX_ARGS-1) * sizeof(int));
559 *((int *)(((char *)ppfs) + ((int)p) + offsetof(ppfs_t,argtype))) = __PA_NOARG;
566 * Run through the entire format string to validate it and initialize
567 * the positional arg numbers (if any).
570 register const char *fmt = fmt0;
573 if ((*fmt == '%') && (*++fmt != '%')) {
574 ppfs->fmtpos = fmt; /* back up to the '%' */
575 if ((r = _ppfs_parsespec(ppfs)) < 0) {
578 fmt = ppfs->fmtpos; /* update to one past end of spec */
583 ppfs->fmtpos = fmt0; /* rewind */
587 /* If we have positional args, make sure we know all the types. */
589 register int *p = ppfs->argtype;
592 if ( *p == __PA_NOARG ) { /* missing arg type!!! */
598 #endif /* NL_MAX_ARG */
603 /**********************************************************************/
604 #ifdef L__ppfs_prepargs
605 void attribute_hidden _ppfs_prepargs(register ppfs_t *ppfs, va_list arg)
609 va_copy(ppfs->arg, arg);
612 if ((i = ppfs->maxposarg) > 0) { /* init for positional args */
613 ppfs->num_data_args = i;
614 ppfs->info.width = ppfs->info.prec = ppfs->maxposarg = 0;
618 #endif /* NL_ARGMAX */
621 /**********************************************************************/
622 #ifdef L__ppfs_setargs
624 void attribute_hidden _ppfs_setargs(register ppfs_t *ppfs)
627 register void **p = ppfs->argptr;
629 register argvalue_t *p = ppfs->argvalue;
634 if (ppfs->maxposarg == 0) { /* initing for or no pos args */
635 #endif /* NL_ARGMAX */
636 if (ppfs->info.width == INT_MIN) {
641 GET_VA_ARG(p,u,unsigned int,ppfs->arg);
643 if (ppfs->info.prec == INT_MIN) {
648 GET_VA_ARG(p,u,unsigned int,ppfs->arg);
651 while (i < ppfs->num_data_args) {
652 switch(ppfs->argtype[i++]) {
653 case (PA_INT|PA_FLAG_LONG_LONG):
655 GET_VA_ARG(p,ull,unsigned long long,ppfs->arg);
658 case (PA_INT|PA_FLAG_LONG):
659 #if ULONG_MAX != UINT_MAX
660 GET_VA_ARG(p,ul,unsigned long,ppfs->arg);
663 case PA_CHAR: /* TODO - be careful */
664 /* ... users could use above and really want below!! */
665 case (PA_INT|__PA_FLAG_CHAR):/* TODO -- translate this!!! */
666 case (PA_INT|PA_FLAG_SHORT):
668 GET_VA_ARG(p,u,unsigned int,ppfs->arg);
670 case PA_WCHAR: /* TODO -- assume int? */
671 /* we're assuming wchar_t is at least an int */
672 GET_VA_ARG(p,wc,wchar_t,ppfs->arg);
674 #ifdef __STDIO_PRINTF_FLOAT
677 GET_VA_ARG(p,d,double,ppfs->arg);
679 case (PA_DOUBLE|PA_FLAG_LONG_DOUBLE):
680 GET_VA_ARG(p,ld,long double,ppfs->arg);
682 #else /* __STDIO_PRINTF_FLOAT */
684 case (PA_DOUBLE|PA_FLAG_LONG_DOUBLE):
687 #endif /* __STDIO_PRINTF_FLOAT */
689 /* TODO -- really need to ensure this can't happen */
690 assert(ppfs->argtype[i-1] & PA_FLAG_PTR);
694 GET_VA_ARG(p,p,void *,ppfs->arg);
703 if (ppfs->info.width == INT_MIN) {
705 = (int) GET_ARG_VALUE(p + ppfs->argnumber[0] - 1,u,unsigned int);
707 if (ppfs->info.prec == INT_MIN) {
709 = (int) GET_ARG_VALUE(p + ppfs->argnumber[1] - 1,u,unsigned int);
712 #endif /* NL_ARGMAX */
714 /* Now we know the width and precision. */
715 if (ppfs->info.width < 0) {
716 ppfs->info.width = -ppfs->info.width;
717 PRINT_INFO_SET_FLAG(&(ppfs->info),left);
718 PRINT_INFO_CLR_FLAG(&(ppfs->info),space);
719 ppfs->info.pad = ' ';
722 /* NOTE -- keep neg for now so float knows! */
723 if (ppfs->info.prec < 0) { /* spec says treat as omitted. */
724 /* so use default prec... 1 for everything but floats and strings. */
730 /**********************************************************************/
731 #ifdef L__ppfs_parsespec
733 #ifdef __UCLIBC_HAS_XLOCALE__
734 libc_hidden_proto(__ctype_b_loc)
735 #elif defined __UCLIBC_HAS_CTYPE_TABLES__
736 libc_hidden_proto(__ctype_b)
739 /* Notes: argtype differs from glibc for the following:
741 * lc PA_WCHAR PA_CHAR the standard says %lc means %C
742 * ls PA_WSTRING PA_STRING the standard says %ls means %S
743 * {*}n {*}|PA_FLAG_PTR PA_FLAG_PTR size of n can be qualified
746 /* TODO: store positions of positional args */
748 /* TODO -- WARNING -- assumes aligned on integer boundaries!!! */
750 /* TODO -- disable if not using positional args!!! */
751 #define _OVERLAPPING_DIFFERENT_ARGS
753 /* TODO -- rethink this -- perhaps we should set to largest type??? */
755 #ifdef _OVERLAPPING_DIFFERENT_ARGS
757 #define PROMOTED_SIZE_OF(X) ((sizeof(X) + sizeof(int) - 1) / sizeof(X))
759 static const short int type_codes[] = {
760 __PA_NOARG, /* must be first entry */
765 PA_INT|PA_FLAG_SHORT,
768 PA_INT|PA_FLAG_LONG_LONG,
770 #ifdef __STDIO_PRINTF_FLOAT
773 PA_DOUBLE|PA_FLAG_LONG_DOUBLE,
774 #endif /* __STDIO_PRINTF_FLOAT */
777 static const unsigned char type_sizes[] = {
778 /* unknown type consumes no arg */
779 0, /* must be first entry */
780 PROMOTED_SIZE_OF(void *),
781 PROMOTED_SIZE_OF(char *),
782 PROMOTED_SIZE_OF(wchar_t *),
783 PROMOTED_SIZE_OF(char),
784 PROMOTED_SIZE_OF(short),
785 PROMOTED_SIZE_OF(int),
786 PROMOTED_SIZE_OF(long),
788 PROMOTED_SIZE_OF(long long),
790 PROMOTED_SIZE_OF(long), /* TODO -- is this correct? (above too) */
792 PROMOTED_SIZE_OF(wchar_t),
793 #ifdef __STDIO_PRINTF_FLOAT
794 /* PROMOTED_SIZE_OF(float), */
795 PROMOTED_SIZE_OF(double),
796 PROMOTED_SIZE_OF(long double),
797 #endif /* __STDIO_PRINTF_FLOAT */
800 static int _promoted_size(int argtype)
802 register const short int *p;
804 /* note -- since any unrecognized type is treated as a pointer */
805 p = type_codes + sizeof(type_codes)/sizeof(type_codes[0]);
807 if (*--p == argtype) {
810 } while (p > type_codes);
812 return type_sizes[(int)(p - type_codes)];
815 static int _is_equal_or_bigger_arg(int curtype, int newtype)
818 if (newtype == __PA_NOARG) {
821 if ((curtype == __PA_NOARG) || (curtype == newtype)) {
824 /* Ok... slot is already filled and types are different in name. */
825 /* So, compare promoted sizes of curtype and newtype args. */
826 return _promoted_size(curtype) <= _promoted_size(newtype);
831 #define _is_equal_or_bigger_arg(C,N) (((C) == __PA_NOARG) || ((C) == (N)))
835 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
836 /* TODO - do this differently? */
837 static char _bss_custom_printf_spec[MAX_USER_SPEC]; /* 0-init'd for us. */
839 attribute_hidden char *_custom_printf_spec = _bss_custom_printf_spec;
840 attribute_hidden printf_arginfo_function *_custom_printf_arginfo[MAX_USER_SPEC];
841 attribute_hidden printf_function _custom_printf_handler[MAX_USER_SPEC];
842 #endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
844 int attribute_hidden _ppfs_parsespec(ppfs_t *ppfs)
846 register const char *fmt;
847 register const char *p;
856 #endif /* NL_ARGMAX */
859 int argtype[MAX_ARGS_PER_SPEC+2];
860 int argnumber[3]; /* width, precision, 1st data arg */
861 static const char spec_flags[] = SPEC_FLAGS;
862 static const char spec_chars[] = SPEC_CHARS;/* TODO: b? */
863 static const char spec_ranges[] = SPEC_RANGES;
864 static const short spec_or_mask[] = SPEC_OR_MASK;
865 static const short spec_and_mask[] = SPEC_AND_MASK;
866 static const char qual_chars[] = QUAL_CHARS;
867 #ifdef __UCLIBC_HAS_WCHAR__
869 #endif /* __UCLIBC_HAS_WCHAR__ */
871 /* WIDE note: we can test against '%' here since we don't allow */
872 /* WIDE note: other mappings of '%' in the wide char set. */
876 argtype[0] = __PA_NOARG;
877 argtype[1] = __PA_NOARG;
879 maxposarg = ppfs->maxposarg;
880 #endif /* NL_ARGMAX */
882 #ifdef __UCLIBC_HAS_WCHAR__
883 /* This is somewhat lame, but saves a lot of code. If we're dealing with
884 * a wide stream, that means the format is a wchar string. So, copy it
885 * char-by-char into a normal char buffer for processing. Make the buffer
886 * (buf) big enough so that any reasonable format specifier will fit.
887 * While there a legal specifiers that won't, the all involve duplicate
888 * flags or outrageous field widths/precisions. */
890 if ((flags = ppfs->info._flags & FLAG_WIDESTREAM) == 0) {
896 if ((buf[i] = (char) (((wchar_t *) ppfs->fmtpos)[i-1]))
897 != (((wchar_t *) ppfs->fmtpos)[i-1])
901 } while (buf[i++] && (i < sizeof(buf)));
902 buf[sizeof(buf)-1] = 0;
904 #else /* __UCLIBC_HAS_WCHAR__ */
905 width = flags = dpoint = 0;
907 #endif /* __UCLIBC_HAS_WCHAR__ */
909 assert(fmt[-1] == '%');
910 assert(fmt[0] != '%');
912 /* Process arg pos and/or flags and/or width and/or precision. */
916 argtype[-dpoint] = PA_INT;
920 while (isdigit(*fmt)) {
921 if (i < MAX_FIELD_WIDTH) { /* Avoid overflow. */
922 i = (i * 10) + (*fmt - '0');
926 if (p[-1] == '%') { /* Check for a position. */
928 /* TODO: if val not in range, then error */
931 if ((*fmt == '$') && (i > 0)) {/* Positional spec. */
933 if (maxposarg == 0) {
936 if ((argnumber[2] = i) > maxposarg) {
939 /* Now fall through to check flags. */
942 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
943 #ifdef __UCLIBC_MJN3_ONLY__
944 #warning TODO: Support prec and width for %m when positional args used
945 /* Actually, positional arg processing will fail in general
946 * for specifiers that don't require an arg. */
947 #endif /* __UCLIBC_MJN3_ONLY__ */
951 #endif /* __UCLIBC_HAS_PRINTF_M_SPEC__ */
954 maxposarg = 0; /* Possible redundant store, but cuts size. */
956 if ((fmt > p) && (*p != '0')) {
960 fmt = p; /* Back up for possible '0's flag. */
961 /* Now fall through to check flags. */
963 #else /* NL_ARGMAX */
964 if (*fmt == '$') { /* Positional spec. */
968 if ((fmt > p) && (*p != '0')) {
972 fmt = p; /* Back up for possible '0's flag. */
973 /* Now fall through to check flags. */
974 #endif /* NL_ARGMAX */
976 restart_flags: /* Process flags. */
986 i += i; /* Better than i <<= 1 for bcc */
990 /* If '+' then ignore ' ', and if '-' then ignore '0'. */
991 /* Note: Need to ignore '0' when prec is an arg with val < 0, */
992 /* but that test needs to wait until the arg is retrieved. */
993 flags &= ~((flags & (FLAG_PLUS|FLAG_MINUS)) >> 1);
994 /* Note: Ignore '0' when prec is specified < 0 too (in printf). */
996 if (fmt[-1] != '%') { /* If we've done anything, loop for width. */
997 goto width_precision;
1001 if (*p == '*') { /* Prec or width takes an arg. */
1004 if ((*fmt++ != '$') || (i <= 0)) {
1005 /* Using pos args and no $ or invalid arg number. */
1008 argnumber[-dpoint] = i;
1010 #endif /* NL_ARGMAX */
1012 /* Not using pos args but digits followed *. */
1022 dpoint = -1; /* To use as default precison. */
1023 goto width_precision;
1029 /* Process qualifier. */
1037 if ((p - qual_chars < 2) && (*fmt == *p)) {
1038 p += ((sizeof(qual_chars)-2) / 2);
1041 dataargtype = ((int)(p[(sizeof(qual_chars)-2) / 2])) << 8;
1043 /* Process conversion specifier. */
1052 p_m_spec_chars = p - spec_chars;
1054 if ((p_m_spec_chars >= CONV_c)
1055 && (dataargtype & PA_FLAG_LONG)) {
1056 p_m_spec_chars -= 2; /* lc -> C and ls -> S */
1059 ppfs->conv_num = p_m_spec_chars;
1061 while (p_m_spec_chars > *++p) {}
1063 i = p - spec_ranges;
1064 argtype[2] = (dataargtype | spec_or_mask[i]) & spec_and_mask[i];
1070 ppfs->info.spec = *fmt;
1071 ppfs->info.prec = preci;
1072 ppfs->info.width = width;
1073 ppfs->info.pad = ((flags & FLAG_ZERO) ? '0' : ' ');
1074 ppfs->info._flags = (flags & ~FLAG_ZERO) | (dataargtype & __PA_INTMASK);
1075 ppfs->num_data_args = 1;
1078 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1080 ppfs->conv_num = CONV_m;
1081 ppfs->num_data_args = 0;
1085 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
1087 /* Handle custom arg -- WARNING -- overwrites p!!! */
1088 ppfs->conv_num = CONV_custom0;
1089 p = _custom_printf_spec;
1092 if ((ppfs->num_data_args
1093 = ((*_custom_printf_arginfo[(int)(p-_custom_printf_spec)])
1094 (&(ppfs->info), MAX_ARGS_PER_SPEC, argtype+2)))
1095 > MAX_ARGS_PER_SPEC) {
1096 break; /* Error -- too many args! */
1100 } while (++p < (_custom_printf_spec + MAX_USER_SPEC));
1101 #endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
1102 /* Otherwise error. */
1106 #if defined(__UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__) || defined(__UCLIBC_HAS_PRINTF_M_SPEC__)
1111 if (maxposarg > 0) {
1114 /* Update maxposarg and check that NL_ARGMAX is not exceeded. */
1116 ? (ppfs->argnumber[i] = argnumber[i])
1117 : argnumber[2] + (i-2));
1118 if (n > maxposarg) {
1119 if ((maxposarg = n) > NL_ARGMAX) {
1124 /* Record argtype with largest size (current, new). */
1125 if (_is_equal_or_bigger_arg(ppfs->argtype[n], argtype[i])) {
1126 ppfs->argtype[n] = argtype[i];
1128 } while (++i < ppfs->num_data_args + 2);
1130 #endif /* NL_ARGMAX */
1131 ppfs->argnumber[2] = 1;
1132 memcpy(ppfs->argtype, argtype + 2, ppfs->num_data_args * sizeof(int));
1136 ppfs->maxposarg = maxposarg;
1137 #endif /* NL_ARGMAX */
1139 #ifdef __UCLIBC_HAS_WCHAR__
1140 if ((flags = ppfs->info._flags & FLAG_WIDESTREAM) == 0) {
1141 ppfs->fmtpos = ++fmt;
1143 ppfs->fmtpos = (const char *) (((const wchar_t *)(ppfs->fmtpos))
1146 #else /* __UCLIBC_HAS_WCHAR__ */
1147 ppfs->fmtpos = ++fmt;
1148 #endif /* __UCLIBC_HAS_WCHAR__ */
1150 return ppfs->num_data_args + 2;
1154 /**********************************************************************/
1155 #ifdef L_register_printf_function
1157 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
1159 int register_printf_function(int spec, printf_function handler,
1160 printf_arginfo_function arginfo)
1165 if (spec && (arginfo != NULL)) { /* TODO -- check if spec is valid char */
1167 p = _custom_printf_spec + MAX_USER_SPEC;
1174 else /* bcc generates less code with fall-through */
1178 p = _custom_printf_spec;
1180 } while (p > _custom_printf_spec);
1185 _custom_printf_handler[(int)(r - p)] = handler;
1186 _custom_printf_arginfo[(int)(r - p)] = arginfo;
1192 /* TODO -- if asked to unregister a non-existent spec, return what? */
1200 /**********************************************************************/
1201 #if defined(L__vfprintf_internal) || defined(L__vfwprintf_internal)
1203 /* We only support ascii digits (or their USC equivalent codes) in
1204 * precision and width settings in *printf (wide) format strings.
1205 * In other words, we don't currently support glibc's 'I' flag.
1206 * We do accept it, but it is currently ignored. */
1208 static size_t _charpad(FILE * __restrict stream, int padchar, size_t numpad);
1210 #ifdef L__vfprintf_internal
1212 #define VFPRINTF_internal _vfprintf_internal
1213 #define FMT_TYPE char
1214 #define OUTNSTR _outnstr
1215 #define STRLEN strlen
1216 #define _PPFS_init _ppfs_init
1217 /* Pulls in fseek: #define OUTPUT(F,S) fputs_unlocked(S,F) */
1218 #define OUTPUT(F,S) __stdio_fwrite((const unsigned char *)(S),strlen(S),(F))
1219 /* #define _outnstr(stream, string, len) __stdio_fwrite(string, len, stream) */
1220 #define _outnstr(stream, string, len) ((len > 0) ? __stdio_fwrite(string, len, stream) : 0)
1221 #define FP_OUT _fp_out_narrow
1223 #ifdef __STDIO_PRINTF_FLOAT
1225 static size_t _fp_out_narrow(FILE *fp, intptr_t type, intptr_t len, intptr_t buf)
1229 if (type & 0x80) { /* Some type of padding needed. */
1230 int buflen = strlen((const char *) buf);
1231 if ((len -= buflen) > 0) {
1232 if ((r = _charpad(fp, (type & 0x7f), len)) != len) {
1238 return r + OUTNSTR(fp, (const unsigned char *) buf, len);
1241 #endif /* __STDIO_PRINTF_FLOAT */
1243 #else /* L__vfprintf_internal */
1245 #define VFPRINTF_internal _vfwprintf_internal
1246 #define FMT_TYPE wchar_t
1247 #define OUTNSTR _outnwcs
1248 #define STRLEN wcslen
1249 #define _PPFS_init _ppwfs_init
1250 /* Pulls in fseek: */
1251 #define OUTPUT(F,S) fputws(S,F)
1252 /* TODO: #define OUTPUT(F,S) _wstdio_fwrite((S),wcslen(S),(F)) */
1253 #define _outnwcs(stream, wstring, len) _wstdio_fwrite(wstring, len, stream)
1254 #define FP_OUT _fp_out_wide
1256 static size_t _outnstr(FILE *stream, const char *s, size_t wclen)
1258 /* NOTE!!! len here is the number of wchars we want to generate!!! */
1267 r = mbsrtowcs(wbuf, &s,
1268 ((todo <= sizeof(wbuf)/sizeof(wbuf[0]))
1270 : sizeof(wbuf)/sizeof(wbuf[0])),
1272 assert(((ssize_t)r) > 0);
1273 n = _outnwcs(stream, wbuf, r);
1280 return wclen - todo;
1283 #ifdef __STDIO_PRINTF_FLOAT
1285 #ifdef __UCLIBC_MJN3_ONLY__
1286 #warning TODO: Move defines from _fpmaxtostr. Put them in a common header.
1289 /* The following defines are from _fpmaxtostr.*/
1290 #define DIGITS_PER_BLOCK 9
1291 #define NUM_DIGIT_BLOCKS ((DECIMAL_DIG+DIGITS_PER_BLOCK-1)/DIGITS_PER_BLOCK)
1292 #define BUF_SIZE ( 3 + NUM_DIGIT_BLOCKS * DIGITS_PER_BLOCK )
1294 static size_t _fp_out_wide(FILE *fp, intptr_t type, intptr_t len, intptr_t buf)
1296 wchar_t wbuf[BUF_SIZE];
1297 const char *s = (const char *) buf;
1301 if (type & 0x80) { /* Some type of padding needed */
1302 int buflen = strlen(s);
1303 if ((len -= buflen) > 0) {
1304 if ((r = _charpad(fp, (type & 0x7f), len)) != len) {
1314 #ifdef __LOCALE_C_ONLY
1316 #else /* __LOCALE_C_ONLY */
1318 #ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
1320 wbuf[i] = __UCLIBC_CURLOCALE_DATA.thousands_sep_wc;
1322 #endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
1324 wbuf[i] = __UCLIBC_CURLOCALE_DATA.decimal_point_wc;
1328 #endif /* __LOCALE_C_ONLY */
1330 } while (++i < len);
1332 r += OUTNSTR(fp, wbuf, len);
1338 #endif /* __STDIO_PRINTF_FLOAT */
1340 static int _ppwfs_init(register ppfs_t *ppfs, const wchar_t *fmt0)
1342 static const wchar_t invalid_wcs[] = L"Invalid wide format string.";
1345 /* First, zero out everything... argnumber[], argtype[], argptr[] */
1346 memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */
1348 --ppfs->maxposarg; /* set to -1 */
1349 #endif /* NL_ARGMAX */
1350 ppfs->fmtpos = (const char *) fmt0;
1351 ppfs->info._flags = FLAG_WIDESTREAM;
1356 mbstate.__mask = 0; /* Initialize the mbstate. */
1358 if (wcsrtombs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) {
1359 ppfs->fmtpos = (const char *) invalid_wcs;
1364 /* now set all argtypes to no-arg */
1367 /* TODO - use memset here since already "paid for"? */
1368 register int *p = ppfs->argtype;
1375 /* TODO -- get rid of this?? */
1376 register char *p = (char *) ((MAX_ARGS-1) * sizeof(int));
1379 *((int *)(((char *)ppfs) + ((int)p) + offsetof(ppfs_t,argtype))) = __PA_NOARG;
1386 * Run through the entire format string to validate it and initialize
1387 * the positional arg numbers (if any).
1390 register const wchar_t *fmt = fmt0;
1393 if ((*fmt == '%') && (*++fmt != '%')) {
1394 ppfs->fmtpos = (const char *) fmt; /* back up to the '%' */
1395 if ((r = _ppfs_parsespec(ppfs)) < 0) {
1398 fmt = (const wchar_t *) ppfs->fmtpos; /* update to one past end of spec */
1403 ppfs->fmtpos = (const char *) fmt0; /* rewind */
1407 /* If we have positional args, make sure we know all the types. */
1409 register int *p = ppfs->argtype;
1410 r = ppfs->maxposarg;
1412 if ( *p == __PA_NOARG ) { /* missing arg type!!! */
1418 #endif /* NL_ARGMAX */
1423 #endif /* L__vfprintf_internal */
1426 static size_t _charpad(FILE * __restrict stream, int padchar, size_t numpad)
1428 size_t todo = numpad;
1430 /* TODO -- Use a buffer to cut down on function calls... */
1434 while (todo && (OUTNSTR(stream, (const unsigned char *) pad, 1) == 1)) {
1438 return numpad - todo;
1441 /* TODO -- Dynamically allocate work space to accomodate stack-poor archs? */
1442 static int _do_one_spec(FILE * __restrict stream,
1443 register ppfs_t *ppfs, int *count)
1445 static const char spec_base[] = SPEC_BASE;
1446 #ifdef L__vfprintf_internal
1447 static const char prefix[] = "+\0-\0 \0000x\0000X";
1449 #else /* L__vfprintf_internal */
1450 static const wchar_t prefix[] = L"+\0-\0 \0000x\0000X";
1451 #endif /* L__vfprintf_internal */
1462 const void * const *argptr;
1464 const void * argptr[MAX_ARGS_PER_SPEC];
1467 #ifdef __UCLIBC_HAS_WCHAR__
1468 const wchar_t *ws = NULL;
1470 #endif /* __UCLIBC_HAS_WCHAR__ */
1472 #ifdef L__vfprintf_internal
1481 int numfill = 0; /* TODO: fix */
1482 int prefix_num = PREFIX_NONE;
1484 #ifdef __UCLIBC_MJN3_ONLY__
1485 #warning TODO: Determine appropriate buf size.
1486 #endif /* __UCLIBC_MJN3_ONLY__ */
1487 /* TODO: buf needs to be big enough for any possible error return strings
1488 * and also for any locale-grouped long long integer strings generated.
1489 * This should be large enough for any of the current archs/locales, but
1490 * eventually this should be handled robustly. */
1494 _ppfs_parsespec(ppfs);
1496 if (_ppfs_parsespec(ppfs) < 0) { /* TODO: just for debugging */
1500 _ppfs_setargs(ppfs);
1502 argtype = ppfs->argtype + ppfs->argnumber[2] - 1;
1503 /* Deal with the argptr vs argvalue issue. */
1505 argptr = (const void * const *) ppfs->argptr;
1507 if (ppfs->maxposarg > 0) { /* Using positional args... */
1508 argptr += ppfs->argnumber[2] - 1;
1510 #endif /* NL_ARGMAX */
1512 /* Need to build a local copy... */
1514 register argvalue_t *p = ppfs->argvalue;
1517 if (ppfs->maxposarg > 0) { /* Using positional args... */
1518 p += ppfs->argnumber[2] - 1;
1520 #endif /* NL_ARGMAX */
1521 for (i = 0 ; i < ppfs->num_data_args ; i++ ) {
1522 argptr[i] = (void *) p++;
1527 register char *s = NULL; /* TODO: Should s be unsigned char * ? */
1529 if (ppfs->conv_num == CONV_n) {
1530 _store_inttype(*(void **)*argptr,
1531 ppfs->info._flags & __PA_INTMASK,
1532 (intmax_t) (*count));
1535 if (ppfs->conv_num <= CONV_i) { /* pointer or (un)signed int */
1536 alphacase = __UIM_LOWER;
1538 #ifdef __UCLIBC_MJN3_ONLY__
1539 #ifdef L__vfprintf_internal
1540 #warning CONSIDER: Should we ignore these flags if stub locale? What about custom specs?
1542 #endif /* __UCLIBC_MJN3_ONLY__ */
1543 if ((base = spec_base[(int)(ppfs->conv_num - CONV_p)]) == 10) {
1544 if (PRINT_INFO_FLAG_VAL(&(ppfs->info),group)) {
1545 alphacase = __UIM_GROUP;
1547 if (PRINT_INFO_FLAG_VAL(&(ppfs->info),i18n)) {
1552 if (ppfs->conv_num <= CONV_u) { /* pointer or unsigned int */
1553 if (ppfs->conv_num == CONV_X) {
1554 alphacase = __UIM_UPPER;
1556 if (ppfs->conv_num == CONV_p) { /* pointer */
1557 prefix_num = PREFIX_LWR_X;
1558 } else { /* unsigned int */
1560 } else { /* signed int */
1563 if (ppfs->info.prec < 0) { /* Ignore '0' flag if prec specified. */
1564 padchar = ppfs->info.pad;
1566 #ifdef __UCLIBC_MJN3_ONLY__
1567 #ifdef L__vfprintf_internal
1568 #warning CONSIDER: If using outdigits and/or grouping, how should we interpret precision?
1570 #endif /* __UCLIBC_MJN3_ONLY__ */
1571 s = _uintmaxtostr(buf + sizeof(buf) - 1,
1573 _load_inttype(ppfs->conv_num == CONV_p ? PA_FLAG_LONG : *argtype & __PA_INTMASK,
1574 *argptr, base), base, alphacase);
1575 if (ppfs->conv_num > CONV_u) { /* signed int */
1577 PRINT_INFO_SET_FLAG(&(ppfs->info),showsign);
1578 ++s; /* handle '-' in the prefix string */
1579 prefix_num = PREFIX_MINUS;
1580 } else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),showsign)) {
1581 prefix_num = PREFIX_PLUS;
1582 } else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),space)) {
1583 prefix_num = PREFIX_SPACE;
1586 slen = (char *)(buf + sizeof(buf) - 1) - s;
1587 #ifdef L__vfwprintf_internal
1590 mbstate.__mask = 0; /* Initialize the mbstate. */
1591 SLEN = mbsrtowcs(NULL, &q, 0, &mbstate);
1594 numfill = ((ppfs->info.prec < 0) ? 1 : ppfs->info.prec);
1595 if (PRINT_INFO_FLAG_VAL(&(ppfs->info),alt)) {
1596 if (ppfs->conv_num <= CONV_x) { /* x or p */
1597 prefix_num = PREFIX_LWR_X;
1599 if (ppfs->conv_num == CONV_X) {
1600 prefix_num = PREFIX_UPR_X;
1602 if ((ppfs->conv_num == CONV_o) && (numfill <= SLEN)) {
1603 numfill = ((*s == '0') ? 1 : SLEN + 1);
1607 if (prefix_num >= PREFIX_LWR_X) {
1608 prefix_num = PREFIX_NONE;
1610 if (ppfs->conv_num == CONV_p) {/* null pointer */
1612 #ifdef L__vfwprintf_internal
1617 } else if (numfill == 0) { /* if precision 0, no output */
1618 #ifdef L__vfwprintf_internal
1624 numfill = ((numfill > SLEN) ? numfill - SLEN : 0);
1625 } else if (ppfs->conv_num <= CONV_A) { /* floating point */
1626 #ifdef __STDIO_PRINTF_FLOAT
1628 nf = _fpmaxtostr(stream,
1630 (PRINT_INFO_FLAG_VAL(&(ppfs->info),is_long_double)
1631 ? *(long double *) *argptr
1632 : (long double) (* (double *) *argptr)),
1633 &ppfs->info, FP_OUT );
1640 #else /* __STDIO_PRINTF_FLOAT */
1641 return -1; /* TODO -- try to continue? */
1642 #endif /* __STDIO_PRINTF_FLOAT */
1643 } else if (ppfs->conv_num <= CONV_S) { /* wide char or string */
1644 #ifdef L__vfprintf_internal
1646 #ifdef __UCLIBC_HAS_WCHAR__
1647 mbstate.__mask = 0; /* Initialize the mbstate. */
1648 if (ppfs->conv_num == CONV_S) { /* wide string */
1649 if (!(ws = *((const wchar_t **) *argptr))) {
1652 /* We use an awful uClibc-specific hack here, passing
1653 * (char*) &ws as the conversion destination. This signals
1654 * uClibc's wcsrtombs that we want a "restricted" length
1655 * such that the mbs fits in a buffer of the specified
1656 * size with no partial conversions. */
1657 if ((slen = wcsrtombs((char *) &ws, &ws, /* Use awful hack! */
1658 ((ppfs->info.prec >= 0)
1660 : SIZE_MAX), &mbstate))
1663 return -1; /* EILSEQ */
1665 } else { /* wide char */
1667 slen = wcrtomb(s, (*((const wchar_t *) *argptr)), &mbstate);
1668 if (slen == ((size_t)-1)) {
1669 return -1; /* EILSEQ */
1671 s[slen] = 0; /* TODO - Is this necessary? */
1673 #else /* __UCLIBC_HAS_WCHAR__ */
1675 #endif /* __UCLIBC_HAS_WCHAR__ */
1676 } else if (ppfs->conv_num <= CONV_s) { /* char or string */
1677 if (ppfs->conv_num == CONV_s) { /* string */
1678 s = *((char **) (*argptr));
1680 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1683 slen = strnlen(s, ((ppfs->info.prec >= 0)
1684 ? ppfs->info.prec : SIZE_MAX));
1686 #ifdef __UCLIBC_HAS_WCHAR__
1694 *s = (unsigned char)(*((const int *) *argptr));
1699 #else /* L__vfprintf_internal */
1701 if (ppfs->conv_num == CONV_S) { /* wide string */
1702 ws = *((wchar_t **) (*argptr));
1706 SLEN = wcsnlen(ws, ((ppfs->info.prec >= 0)
1707 ? ppfs->info.prec : SIZE_MAX));
1708 } else { /* wide char */
1709 *wbuf = (wchar_t)(*((const wint_t *) *argptr));
1716 } else if (ppfs->conv_num <= CONV_s) { /* char or string */
1718 if (ppfs->conv_num == CONV_s) { /* string */
1719 #ifdef __UCLIBC_MJN3_ONLY__
1720 #warning TODO: Fix %s for _vfwprintf_internal... output upto illegal sequence?
1721 #endif /* __UCLIBC_MJN3_ONLY__ */
1722 s = *((char **) (*argptr));
1724 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1727 /* We use an awful uClibc-specific hack here, passing
1728 * (wchar_t*) &mbstate as the conversion destination.
1729 * This signals uClibc's mbsrtowcs that we want a
1730 * "restricted" length such that the mbs fits in a buffer
1731 * of the specified size with no partial conversions. */
1734 mbstate.__mask = 0; /* Initialize the mbstate. */
1735 SLEN = mbsrtowcs((wchar_t *) &mbstate, &q,
1736 ((ppfs->info.prec >= 0)
1737 ? ppfs->info.prec : SIZE_MAX),
1740 if (SLEN == ((size_t)(-1))) {
1741 return -1; /* EILSEQ */
1749 *wbuf = btowc( (unsigned char)(*((const int *) *argptr)) );
1753 #endif /* L__vfprintf_internal */
1755 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1756 } else if (ppfs->conv_num == CONV_m) {
1757 s = __glibc_strerror_r(errno, buf, sizeof(buf));
1758 goto SET_STRING_LEN;
1761 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
1762 assert(ppfs->conv_num == CONV_custom0);
1764 s = _custom_printf_spec;
1766 if (*s == ppfs->info.spec) {
1768 /* TODO -- check return value for sanity? */
1769 rv = (*_custom_printf_handler
1770 [(int)(s-_custom_printf_spec)])
1771 (stream, &ppfs->info, argptr);
1778 } while (++s < (_custom_printf_spec + MAX_USER_SPEC));
1779 #endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
1784 #ifdef __UCLIBC_MJN3_ONLY__
1785 #ifdef L__vfprintf_internal
1786 #warning CONSIDER: If using outdigits and/or grouping, how should we pad?
1788 #endif /* __UCLIBC_MJN3_ONLY__ */
1793 if (prefix_num != PREFIX_NONE) {
1794 t += ((prefix_num < PREFIX_LWR_X) ? 1 : 2);
1796 numpad = ((ppfs->info.width > t) ? (ppfs->info.width - t) : 0);
1797 *count += t + numpad;
1799 if (padchar == '0') { /* TODO: check this */
1804 /* Now handle the output itself. */
1805 if (!PRINT_INFO_FLAG_VAL(&(ppfs->info),left)) {
1806 if (_charpad(stream, ' ', numpad) != numpad) {
1811 OUTPUT(stream, prefix + prefix_num);
1813 if (_charpad(stream, '0', numfill) != numfill) {
1817 #ifdef L__vfprintf_internal
1819 #ifdef __UCLIBC_HAS_WCHAR__
1822 if (_outnstr(stream, s, slen) != slen) {
1825 } else { /* wide string */
1827 mbstate.__mask = 0; /* Initialize the mbstate. */
1829 t = (slen <= sizeof(buf)) ? slen : sizeof(buf);
1830 t = wcsrtombs(buf, &ws, t, &mbstate);
1831 assert (t != ((size_t)(-1)));
1832 if (_outnstr(stream, buf, t) != t) {
1838 #else /* __UCLIBC_HAS_WCHAR__ */
1839 if (_outnstr(stream, (const unsigned char *) s, slen) != slen) {
1842 #endif /* __UCLIBC_HAS_WCHAR__ */
1844 #else /* L__vfprintf_internal */
1848 if (_outnstr(stream, s, SLEN) != SLEN) {
1852 if (_outnwcs(stream, ws, SLEN) != SLEN) {
1857 #endif /* L__vfprintf_internal */
1858 if (_charpad(stream, ' ', numpad) != numpad) {
1866 libc_hidden_proto(fprintf)
1868 int VFPRINTF_internal (FILE * __restrict stream,
1869 const FMT_TYPE * __restrict format,
1874 register const FMT_TYPE *s;
1879 if (_PPFS_init(&ppfs, format) < 0) { /* Bad format string. */
1880 OUTNSTR(stream, (const unsigned char *) ppfs.fmtpos,
1881 STRLEN((const FMT_TYPE *)(ppfs.fmtpos)));
1882 #if defined(L__vfprintf_internal) && !defined(NDEBUG)
1883 fprintf(stderr,"\nIMbS: \"%s\"\n\n", format);
1887 _ppfs_prepargs(&ppfs, arg); /* This did a va_copy!!! */
1890 while (*format && (*format != '%')) {
1894 if (format-s) { /* output any literal text in format string */
1895 if ( (r = OUTNSTR(stream, (const unsigned char *) s, format-s)) != (format-s)) {
1902 if (!*format) { /* we're done */
1906 if (format[1] != '%') { /* if we get here, *format == '%' */
1907 /* TODO: _do_one_spec needs to know what the output funcs are!!! */
1908 ppfs.fmtpos = (const char *)(++format);
1909 /* TODO: check -- should only fail on stream error */
1910 if ( (r = _do_one_spec(stream, &ppfs, &count)) < 0) {
1914 s = format = (const FMT_TYPE *) ppfs.fmtpos;
1915 } else { /* %% means literal %, so start new string */
1921 va_end(ppfs.arg); /* Need to clean up after va_copy! */
1924 /* #if defined(L__vfprintf_internal) && defined(__UCLIBC_HAS_WCHAR__) */
1930 #endif /* defined(L__vfprintf_internal) || defined(L__vfwprintf_internal) */
1933 /**********************************************************************/
1934 #if defined(L_vfprintf) || defined(L_vfwprintf)
1936 /* This is just a wrapper around VFPRINTF_internal.
1937 * Factoring out vfprintf internals allows:
1938 * (1) vdprintf and vsnprintf don't need to setup fake locking,
1939 * (2) __STDIO_STREAM_TRANS_TO_WRITE is not used in vfprintf internals,
1940 * and thus fseek etc is not pulled in by vdprintf and vsnprintf.
1942 * In order to not pull in fseek through fputs, OUTPUT() macro
1943 * is using __stdio_fwrite (TODO: do the same for wide functions).
1946 #define VFPRINTF vfprintf
1947 #define VFPRINTF_internal _vfprintf_internal
1948 #define FMT_TYPE char
1950 #define VFPRINTF vfwprintf
1951 #define VFPRINTF_internal _vfwprintf_internal
1952 #define FMT_TYPE wchar_t
1955 libc_hidden_proto(VFPRINTF)
1956 int VFPRINTF (FILE * __restrict stream,
1957 const FMT_TYPE * __restrict format,
1961 __STDIO_AUTO_THREADLOCK_VAR;
1963 __STDIO_AUTO_THREADLOCK(stream);
1967 (!__STDIO_STREAM_IS_NARROW_WRITING(stream)
1968 && __STDIO_STREAM_TRANS_TO_WRITE(stream, __FLAG_NARROW))
1970 (!__STDIO_STREAM_IS_WIDE_WRITING(stream)
1971 && __STDIO_STREAM_TRANS_TO_WRITE(stream, __FLAG_WIDE))
1976 count = VFPRINTF_internal(stream, format, arg);
1979 __STDIO_AUTO_THREADUNLOCK(stream);
1983 libc_hidden_def(VFPRINTF)
1984 #endif /* defined(L_vfprintf) || defined(L_vfwprintf) */
1986 /**********************************************************************/