OSDN Git Service

9c44a26a6811e484d47c4e84f5c377ee7f27da11
[uclinux-h8/uClibc.git] / libc / stdio / _vfprintf.c
1 /*  Copyright (C) 2002-2004     Manuel Novoa III
2  *  My stdio library for linux and (soon) elks.
3  *
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.
8  *
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.
13  *
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.
17  */
18
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.
23  */
24
25 /*  ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!
26  *
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
31  *
32  *  ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION! */
33
34
35 /* April 1, 2002
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>
40  *
41  * May 10, 2002
42  * Remove __isdigit and use new ctype.h version.
43  * Add conditional setting of QUAL_CHARS for size_t and ptrdiff_t.
44  *
45  * Aug 16, 2002
46  * Fix two problems that showed up with the python 2.2.1 tests; one
47  *    involving %o and one involving %f.
48  *
49  * Oct 28, 2002
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
52  *    a va_copy.
53  * Make sure each va_copy has a matching va_end, as required by C99.
54  *
55  * Nov 4, 2002
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.
62  *
63  * Nov 21, 2002
64  * Add *wprintf functions.  Currently they don't support floating point
65  *   conversions.  That will wait until the rewrite of _dtostr.
66  *
67  * Aug 1, 2003
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.
71  * Misc bug fixes.
72  *
73  * Aug 31, 2003
74  * Fix precision bug for %g conversion specifier when using %f style.
75  *
76  * Sep 5, 2003
77  * Implement *s*scanf for the non-buffered stdio case with old_vfprintf.
78  *
79  * Sep 23, 2003
80  * vfprintf was not always checking for narrow stream orientation.
81  */
82
83 /* TODO:
84  *
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.
89  */
90
91 #define _ISOC99_SOURCE                  /* for ULLONG primarily... */
92 #include <features.h>
93 #include "_stdio.h"
94 #include <stdlib.h>
95 #include <string.h>
96 #include <stddef.h>
97 #include <ctype.h>
98 #include <limits.h>
99 #include <stdarg.h>
100 #include <assert.h>
101 #include <stdint.h>
102 #include <errno.h>
103 #include <locale.h>
104
105 #define __PRINTF_INFO_NO_BITFIELD
106 #include <printf.h>
107
108 #ifdef __UCLIBC_HAS_THREADS__
109 #include <stdio_ext.h>
110 #include <pthread.h>
111 #endif /* __UCLIBC_HAS_THREADS__ */
112
113 #ifdef __UCLIBC_HAS_WCHAR__
114 #include <wchar.h>
115 #endif /* __UCLIBC_HAS_WCHAR__ */
116
117 #include <bits/uClibc_uintmaxtostr.h>
118 #include <bits/uClibc_va_copy.h>
119
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)
135 #endif
136
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.
140  */
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.
143 #endif
144
145 /**********************************************************************/
146 /* These provide some control over printf's feature set */
147
148 /* This is undefined below depeding on uClibc's configuration. */
149 #define __STDIO_PRINTF_FLOAT 1
150
151 /* Now controlled by uClibc_stdio.h. */
152 /* #define __UCLIBC_HAS_PRINTF_M_SPEC__ */
153
154
155 /**********************************************************************/
156
157 #if defined(__UCLIBC__) && !defined(__UCLIBC_HAS_FLOATS__)
158 #undef __STDIO_PRINTF_FLOAT
159 #endif
160
161 #ifdef __BCC__
162 #undef __STDIO_PRINTF_FLOAT
163 #endif
164
165 #ifdef __STDIO_PRINTF_FLOAT
166 #include <float.h>
167 #include <bits/uClibc_fpmax.h>
168 #else  /* __STDIO_PRINTF_FLOAT */
169 #undef L__fpmaxtostr
170 #endif /* __STDIO_PRINTF_FLOAT */
171
172
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
176 #endif
177
178 /**********************************************************************/
179
180 /* Now controlled by uClibc_stdio.h. */
181 /* #define __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
182
183 /* TODO -- move these to a configuration section? */
184 #define MAX_FIELD_WIDTH         4095
185
186 #ifdef __UCLIBC_MJN3_ONLY__
187 #ifdef L_register_printf_function
188 /* emit only once */
189 #warning WISHLIST: Make MAX_USER_SPEC configurable?
190 #warning WISHLIST: Make MAX_ARGS_PER_SPEC configurable?
191 #endif
192 #endif /* __UCLIBC_MJN3_ONLY__ */
193
194 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
195
196 #define MAX_USER_SPEC       10
197 #define MAX_ARGS_PER_SPEC    5
198
199 #else  /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
200
201 #undef MAX_USER_SPEC
202 #define MAX_ARGS_PER_SPEC    1
203
204 #endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
205
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
210 #endif
211
212 #if defined(NL_ARGMAX) && (NL_ARGMAX < 9)
213 #error NL_ARGMAX < 9!
214 #endif
215
216 #if defined(NL_ARGMAX) && (NL_ARGMAX >= (MAX_ARGS_PER_SPEC + 2))
217 #define MAX_ARGS        NL_ARGMAX
218 #else
219 /* N for spec itself, plus 1 each for width and precision */
220 #define MAX_ARGS        (MAX_ARGS_PER_SPEC + 2)
221 #endif
222
223 /**********************************************************************/
224
225 #define __PA_FLAG_INTMASK \
226         (__PA_FLAG_CHAR|PA_FLAG_SHORT|__PA_FLAG_INT|PA_FLAG_LONG|PA_FLAG_LONG_LONG)
227
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__ */
233
234 /**********************************************************************/
235
236 #define SPEC_FLAGS              " +0-#'I"
237 enum {
238         FLAG_SPACE              =       0x01,
239         FLAG_PLUS               =       0x02,   /* must be 2 * FLAG_SPACE */
240         FLAG_ZERO               =       0x04,
241         FLAG_MINUS              =       0x08,   /* must be 2 * FLAG_ZERO */
242         FLAG_HASH               =       0x10,
243         FLAG_THOUSANDS  =       0x20,
244         FLAG_I18N               =       0x40,   /* only works for d, i, u */
245         FLAG_WIDESTREAM =   0x80
246 };        
247
248 /**********************************************************************/
249
250 /* float layout          01234567890123456789   TODO: B?*/
251 #define SPEC_CHARS              "npxXoudifFeEgGaACScs"
252 enum {
253         CONV_n = 0,
254         CONV_p,
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__
259         CONV_m,
260 #endif
261         CONV_custom0                            /* must be last */
262 };
263
264 /*                         p   x   X  o   u   d   i */
265 #define SPEC_BASE               { 16, 16, 16, 8, 10, 10, 10 }
266
267 #define SPEC_RANGES             { CONV_n, CONV_p, CONV_i, CONV_A, \
268                                                   CONV_C, CONV_S, CONV_c, CONV_s, CONV_custom0 }
269
270 #define SPEC_OR_MASK             { \
271         /* n */                 (PA_FLAG_PTR|PA_INT), \
272         /* p */                 PA_POINTER, \
273         /* oxXudi */    PA_INT, \
274         /* fFeEgGaA */  PA_DOUBLE, \
275         /* C */                 PA_WCHAR, \
276         /* S */                 PA_WSTRING, \
277         /* c */                 PA_CHAR, \
278         /* s */                 PA_STRING, \
279 }
280
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), \
288         /* c */                 (PA_CHAR), \
289         /* s */                 (PA_STRING), \
290 }
291
292 /**********************************************************************/
293 /*
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)
297  */
298
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'. */
302 /*  #else */
303 /*  #if LLONG_MAX != INTMAX_MAX */
304 /*  #error fix QUAL_CHARS intmax_t entry 'j'! */
305 /*  #endif */
306 /*  #endif */
307
308 #ifdef PDS
309 #error PDS already defined!
310 #endif
311 #ifdef SS
312 #error SS already defined!
313 #endif
314 #ifdef IMS
315 #error IMS already defined!
316 #endif
317
318 #if PTRDIFF_MAX == INT_MAX
319 #define PDS             0
320 #elif PTRDIFF_MAX == LONG_MAX
321 #define PDS             4
322 #elif defined(LLONG_MAX) && (PTRDIFF_MAX == LLONG_MAX)
323 #define PDS             8
324 #else
325 #error fix QUAL_CHARS ptrdiff_t entry 't'!
326 #endif
327
328 #if SIZE_MAX == UINT_MAX
329 #define SS              0
330 #elif SIZE_MAX == ULONG_MAX
331 #define SS              4
332 #elif defined(LLONG_MAX) && (SIZE_MAX == ULLONG_MAX)
333 #define SS              8
334 #else
335 #error fix QUAL_CHARS size_t entries 'z', 'Z'!
336 #endif
337
338 #if INTMAX_MAX == INT_MAX
339 #define IMS             0
340 #elif INTMAX_MAX == LONG_MAX
341 #define IMS             4
342 #elif defined(LLONG_MAX) && (INTMAX_MAX == LLONG_MAX)
343 #define IMS             8
344 #else
345 #error fix QUAL_CHARS intmax_t entry 'j'!
346 #endif
347
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!!! */\
353      1,     8 \
354 }
355
356 /**********************************************************************/
357
358 #ifdef __STDIO_VA_ARG_PTR
359 #ifdef __BCC__
360 #define __va_arg_ptr(ap,type)           (((type *)(ap += sizeof(type))) - 1)
361 #endif
362
363 #if 1
364 #ifdef __GNUC__
365 /* TODO -- need other than for 386 as well! */
366
367 #ifndef __va_rounded_size
368 #define __va_rounded_size(TYPE)  \
369   (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
370 #endif
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))))
374 #endif
375 #endif
376 #endif /* __STDIO_VA_ARG_PTR */
377
378 #ifdef __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))))
381 #else
382 typedef union {
383         wchar_t wc;
384         unsigned int u;
385         unsigned long ul;
386 #ifdef ULLONG_MAX
387         unsigned long long ull;
388 #endif
389 #ifdef __STDIO_PRINTF_FLOAT
390         double d;
391         long double ld;
392 #endif /* __STDIO_PRINTF_FLOAT */
393         void *p;
394 } argvalue_t;
395
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))
398 #endif
399
400 typedef struct {
401         const char *fmtpos;                     /* TODO: move below struct?? */
402         struct printf_info info;
403 #ifdef NL_ARGMAX
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];
410         va_list arg;
411 #ifdef __va_arg_ptr
412         void *argptr[MAX_ARGS];
413 #else
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];
418 #endif
419 } ppfs_t;                                               /* parse printf format state */
420
421 /**********************************************************************/
422
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. */
425
426 #ifdef __STDIO_PRINTF_FLOAT
427 typedef size_t (__fp_outfunc_t)(FILE *fp, intptr_t type, intptr_t len,
428                                                                 intptr_t buf);
429
430 extern ssize_t _fpmaxtostr(FILE * fp, __fpmax_t x, struct printf_info *info,
431                                                    __fp_outfunc_t fp_outfunc) attribute_hidden;
432 #endif
433
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 */
438
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;
441
442 /**********************************************************************/
443 #ifdef L_parse_printf_format
444
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.
450  */
451
452 size_t parse_printf_format(register const char *template,
453                                                    size_t n, register int *argtypes)
454 {
455         ppfs_t ppfs;
456         size_t i;
457         size_t count = 0;
458
459         if (_ppfs_init(&ppfs, template) >= 0) {
460 #ifdef NL_ARGMAX
461                 if (ppfs.maxposarg > 0)  { /* Using positional args. */
462                         count = ppfs.maxposarg;
463                         if (n > count) {
464                                 n = count;
465                         }
466                         for (i = 0 ; i < n ; i++) {
467                                 *argtypes++ = ppfs.argtype[i];
468                         }
469                 } else {                                /* Not using positional args. */
470 #endif /* NL_ARGMAX */
471                         while (*template) {
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) {
477                                                 ++count;
478                                                 if (n > 0) {
479                                                         *argtypes++ = PA_INT;
480                                                         --n;
481                                                 }
482                                         }
483                                         if (ppfs.info.prec == INT_MIN) {
484                                                 ++count;
485                                                 if (n > 0) {
486                                                         *argtypes++ = PA_INT;
487                                                         --n;
488                                                 }
489                                         }
490                                         for (i = 0 ; i < ppfs.num_data_args ; i++) {
491                                                 if ((ppfs.argtype[i]) != __PA_NOARG) {
492                                                         ++count;
493                                                         if (n > 0) {
494                                                                 *argtypes++ = ppfs.argtype[i];
495                                                                 --n;
496                                                         }
497                                                 }
498                                         }
499                                 } else {
500                                         ++template;
501                                 }
502                         }
503 #ifdef NL_ARGMAX
504                 }
505 #endif /* NL_ARGMAX */
506         }
507
508         return count;
509 }
510
511 #endif
512 /**********************************************************************/
513 #ifdef L__ppfs_init
514
515 int attribute_hidden _ppfs_init(register ppfs_t *ppfs, const char *fmt0)
516 {
517         int r;
518
519         /* First, zero out everything... argnumber[], argtype[], argptr[] */
520         memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */
521 #ifdef NL_ARGMAX
522         --ppfs->maxposarg;                      /* set to -1 */
523 #endif /* NL_ARGMAX */
524         ppfs->fmtpos = fmt0;
525 #ifdef __UCLIBC_MJN3_ONLY__
526 #warning TODO: Make checking of the format string in C locale an option.
527 #endif
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.";
534                 mbstate_t mbstate;
535                 const char *p;
536                 mbstate.__mask = 0;     /* Initialize the mbstate. */
537                 p = fmt0;
538                 if (mbsrtowcs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) {
539                         ppfs->fmtpos = invalid_mbs;
540                         return -1;
541                 }
542         }
543 #endif /* __UCLIBC_HAS_LOCALE__ */
544         /* now set all argtypes to no-arg */
545         {
546 #if 1
547                 /* TODO - use memset here since already "paid for"? */
548                 register int *p = ppfs->argtype;
549                 
550                 r = MAX_ARGS;
551                 do {
552                         *p++ = __PA_NOARG;
553                 } while (--r);
554 #else
555                 /* TODO -- get rid of this?? */
556                 register char *p = (char *) ((MAX_ARGS-1) * sizeof(int));
557
558                 do {
559                         *((int *)(((char *)ppfs) + ((int)p) + offsetof(ppfs_t,argtype))) = __PA_NOARG;
560                         p -= sizeof(int);
561                 } while (p);
562 #endif
563         }
564
565         /*
566          * Run through the entire format string to validate it and initialize
567          * the positional arg numbers (if any).
568          */
569         {
570                 register const char *fmt = fmt0;
571
572                 while (*fmt) {
573                         if ((*fmt == '%') && (*++fmt != '%')) {
574                                 ppfs->fmtpos = fmt; /* back up to the '%' */
575                                 if ((r = _ppfs_parsespec(ppfs)) < 0) {
576                                         return -1;
577                                 }
578                                 fmt = ppfs->fmtpos;     /* update to one past end of spec */
579                         } else {
580                                 ++fmt;
581                         }
582                 }
583                 ppfs->fmtpos = fmt0;            /* rewind */
584         }
585
586 #ifdef NL_MAX_ARG
587         /* If we have positional args, make sure we know all the types. */
588         {
589                 register int *p = ppfs->argtype;
590                 r = ppfs->maxposarg;
591                 while (--r >= 0) {
592                         if ( *p == __PA_NOARG ) { /* missing arg type!!! */
593                                 return -1;
594                         }
595                         ++p;
596                 }
597         }
598 #endif /* NL_MAX_ARG */
599
600         return 0;
601 }
602 #endif
603 /**********************************************************************/
604 #ifdef L__ppfs_prepargs
605 void attribute_hidden _ppfs_prepargs(register ppfs_t *ppfs, va_list arg)
606 {
607         int i;
608
609         va_copy(ppfs->arg, arg);
610
611 #ifdef NL_ARGMAX
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;
615                 _ppfs_setargs(ppfs);
616                 ppfs->maxposarg = i;
617         }
618 #endif /* NL_ARGMAX */
619 }
620 #endif
621 /**********************************************************************/
622 #ifdef L__ppfs_setargs
623
624 void attribute_hidden _ppfs_setargs(register ppfs_t *ppfs)
625 {
626 #ifdef __va_arg_ptr
627         register void **p = ppfs->argptr;
628 #else
629         register argvalue_t *p = ppfs->argvalue;
630 #endif
631         int i;
632
633 #ifdef NL_ARGMAX
634         if (ppfs->maxposarg == 0) {     /* initing for or no pos args */
635 #endif /* NL_ARGMAX */
636                 if (ppfs->info.width == INT_MIN) {
637                         ppfs->info.width =
638 #ifdef __va_arg_ptr
639                                 *(int *)
640 #endif
641                                 GET_VA_ARG(p,u,unsigned int,ppfs->arg);
642                 } 
643                 if (ppfs->info.prec == INT_MIN) {
644                         ppfs->info.prec =
645 #ifdef __va_arg_ptr
646                                 *(int *)
647 #endif
648                                 GET_VA_ARG(p,u,unsigned int,ppfs->arg);
649                 }
650                 i = 0;
651                 while (i < ppfs->num_data_args) {
652                         switch(ppfs->argtype[i++]) {
653                                 case (PA_INT|PA_FLAG_LONG_LONG):
654 #ifdef ULLONG_MAX
655                                         GET_VA_ARG(p,ull,unsigned long long,ppfs->arg);
656                                         break;
657 #endif
658                                 case (PA_INT|PA_FLAG_LONG):
659 #if ULONG_MAX != UINT_MAX
660                                         GET_VA_ARG(p,ul,unsigned long,ppfs->arg);
661                                         break;
662 #endif
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):
667                                 case PA_INT:
668                                         GET_VA_ARG(p,u,unsigned int,ppfs->arg);
669                                         break;
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);
673                                         break;
674 #ifdef __STDIO_PRINTF_FLOAT
675                                         /* PA_FLOAT */
676                                 case PA_DOUBLE:
677                                         GET_VA_ARG(p,d,double,ppfs->arg);
678                                         break;
679                                 case (PA_DOUBLE|PA_FLAG_LONG_DOUBLE):
680                                         GET_VA_ARG(p,ld,long double,ppfs->arg);
681                                         break;
682 #else  /* __STDIO_PRINTF_FLOAT */
683                                 case PA_DOUBLE:
684                                 case (PA_DOUBLE|PA_FLAG_LONG_DOUBLE):
685                                         assert(0);
686                                         continue;
687 #endif /* __STDIO_PRINTF_FLOAT */
688                                 default:
689                                         /* TODO -- really need to ensure this can't happen */
690                                         assert(ppfs->argtype[i-1] & PA_FLAG_PTR);
691                                 case PA_POINTER:
692                                 case PA_STRING:
693                                 case PA_WSTRING:
694                                         GET_VA_ARG(p,p,void *,ppfs->arg);
695                                         break;                          
696                                 case __PA_NOARG:
697                                         continue;
698                         }
699                         ++p;
700                 }
701 #ifdef NL_ARGMAX
702         } else {
703                 if (ppfs->info.width == INT_MIN) {
704                         ppfs->info.width
705                                 = (int) GET_ARG_VALUE(p + ppfs->argnumber[0] - 1,u,unsigned int);
706                 } 
707                 if (ppfs->info.prec == INT_MIN) {
708                         ppfs->info.prec
709                                 = (int) GET_ARG_VALUE(p + ppfs->argnumber[1] - 1,u,unsigned int);
710                 }
711         }
712 #endif /* NL_ARGMAX */
713
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 = ' ';
720         }
721 #if 0
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. */
725                 ppfs->info.prec = 1;
726         }
727 #endif
728 }
729 #endif
730 /**********************************************************************/
731 #ifdef L__ppfs_parsespec
732
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)
737 #endif
738
739 /* Notes: argtype differs from glibc for the following:
740  *         mine              glibc
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
744  */
745
746 /* TODO: store positions of positional args */
747
748 /* TODO -- WARNING -- assumes aligned on integer boundaries!!! */
749
750 /* TODO -- disable if not using positional args!!! */
751 #define _OVERLAPPING_DIFFERENT_ARGS
752
753 /* TODO -- rethink this -- perhaps we should set to largest type??? */
754
755 #ifdef _OVERLAPPING_DIFFERENT_ARGS 
756
757 #define PROMOTED_SIZE_OF(X)             ((sizeof(X) + sizeof(int) - 1) / sizeof(X))
758
759 static const short int type_codes[] = {
760         __PA_NOARG,                                     /* must be first entry */
761         PA_POINTER,
762         PA_STRING,
763         PA_WSTRING,
764         PA_CHAR,
765         PA_INT|PA_FLAG_SHORT,
766         PA_INT,
767         PA_INT|PA_FLAG_LONG,
768         PA_INT|PA_FLAG_LONG_LONG,
769         PA_WCHAR,
770 #ifdef __STDIO_PRINTF_FLOAT
771         /* PA_FLOAT, */
772         PA_DOUBLE,
773         PA_DOUBLE|PA_FLAG_LONG_DOUBLE,
774 #endif /* __STDIO_PRINTF_FLOAT */
775 };
776
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),
787 #ifdef ULLONG_MAX
788         PROMOTED_SIZE_OF(long long),
789 #else
790         PROMOTED_SIZE_OF(long),         /* TODO -- is this correct? (above too) */
791 #endif
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 */
798 };
799
800 static int _promoted_size(int argtype)
801 {
802         register const short int *p;
803
804         /* note -- since any unrecognized type is treated as a pointer */
805         p = type_codes + sizeof(type_codes)/sizeof(type_codes[0]);
806         do {
807                 if (*--p == argtype) {
808                         break;
809                 }
810         } while (p > type_codes);
811
812         return type_sizes[(int)(p - type_codes)];
813 }
814
815 static int _is_equal_or_bigger_arg(int curtype, int newtype)
816 {
817         /* Quick test */
818         if (newtype == __PA_NOARG) {
819                 return 0;
820         }
821         if ((curtype == __PA_NOARG) || (curtype == newtype)) {
822                 return 1;
823         }
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);
827 }
828
829 #else
830
831 #define _is_equal_or_bigger_arg(C,N)    (((C) == __PA_NOARG) || ((C) == (N)))
832
833 #endif
834
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.  */
838
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__ */
843
844 int attribute_hidden _ppfs_parsespec(ppfs_t *ppfs)
845 {
846         register const char *fmt;
847         register const char *p;
848         int preci;
849         int width;
850         int flags;
851         int dataargtype;
852         int i;
853         int dpoint;
854 #ifdef NL_ARGMAX
855         int maxposarg;
856 #endif /* NL_ARGMAX */
857         int p_m_spec_chars;
858         int n;
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__
868         char buf[32];
869 #endif /* __UCLIBC_HAS_WCHAR__ */
870
871         /* WIDE note: we can test against '%' here since we don't allow */
872         /* WIDE note: other mappings of '%' in the wide char set. */
873         preci = -1;
874         argnumber[0] = 0;
875         argnumber[1] = 0;
876         argtype[0] = __PA_NOARG;
877         argtype[1] = __PA_NOARG;
878 #ifdef NL_ARGMAX
879         maxposarg = ppfs->maxposarg;
880 #endif /* NL_ARGMAX */
881
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. */
889         width = dpoint = 0;
890         if ((flags = ppfs->info._flags & FLAG_WIDESTREAM) == 0) {
891                 fmt = ppfs->fmtpos;
892         } else {
893                 fmt = buf + 1;
894                 i = 0;
895                 do {
896                         if ((buf[i] = (char) (((wchar_t *) ppfs->fmtpos)[i-1]))
897                                 != (((wchar_t *) ppfs->fmtpos)[i-1])
898                                 ) {
899                                 return -1;
900                         }
901                 } while (buf[i++] && (i < sizeof(buf)));
902                 buf[sizeof(buf)-1] = 0;
903         }
904 #else  /* __UCLIBC_HAS_WCHAR__ */
905         width = flags = dpoint = 0;
906         fmt = ppfs->fmtpos;
907 #endif /* __UCLIBC_HAS_WCHAR__ */
908
909         assert(fmt[-1] == '%');
910         assert(fmt[0] != '%');
911
912         /* Process arg pos and/or flags and/or width and/or precision. */
913  width_precision:
914         p = fmt;
915         if (*fmt == '*') {
916                 argtype[-dpoint] = PA_INT;
917                 ++fmt;
918         }
919         i = 0;
920         while (isdigit(*fmt)) {
921                 if (i < MAX_FIELD_WIDTH) { /* Avoid overflow. */
922                         i = (i * 10) + (*fmt - '0');
923                 }
924                 ++fmt;
925         }
926         if (p[-1] == '%') { /* Check for a position. */
927
928                 /* TODO: if val not in range, then error */
929
930 #ifdef NL_ARGMAX
931                 if ((*fmt == '$') && (i > 0)) {/* Positional spec. */
932                         ++fmt;
933                         if (maxposarg == 0) {
934                                 return -1;
935                         }
936                         if ((argnumber[2] = i) > maxposarg) {
937                                 maxposarg = i;
938                         }
939                         /* Now fall through to check flags. */
940                 } else {
941                         if (maxposarg > 0) {
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__ */
948                                 if (*fmt == 'm') {
949                                         goto PREC_WIDTH;
950                                 }
951 #endif /* __UCLIBC_HAS_PRINTF_M_SPEC__ */
952                                 return -1;
953                         }
954                         maxposarg = 0;          /* Possible redundant store, but cuts size. */
955
956                         if ((fmt > p) && (*p != '0')) {
957                                 goto PREC_WIDTH;
958                         }
959
960                         fmt = p;                        /* Back up for possible '0's flag. */
961                         /* Now fall through to check flags. */
962                 }
963 #else  /* NL_ARGMAX */
964                 if (*fmt == '$') {              /* Positional spec. */
965                         return -1;
966                 }
967
968                 if ((fmt > p) && (*p != '0')) {
969                         goto PREC_WIDTH;
970                 }
971
972                 fmt = p;                        /* Back up for possible '0's flag. */
973                 /* Now fall through to check flags. */
974 #endif /* NL_ARGMAX */
975
976         restart_flags:          /* Process flags. */
977                 i = 1;
978                 p = spec_flags;
979         
980                 do {
981                         if (*fmt == *p++) {
982                                 ++fmt;
983                                 flags |= i;
984                                 goto restart_flags;
985                         }
986                         i += i;                         /* Better than i <<= 1 for bcc */
987                 } while (*p);
988                 i = 0;
989
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). */
995
996                 if (fmt[-1] != '%') {   /* If we've done anything, loop for width. */
997                         goto width_precision;
998                 }
999         }
1000  PREC_WIDTH:
1001         if (*p == '*') {                        /* Prec or width takes an arg. */
1002 #ifdef NL_ARGMAX
1003                 if (maxposarg) {
1004                         if ((*fmt++ != '$') || (i <= 0)) {
1005                                 /* Using pos args and no $ or invalid arg number. */
1006                                 return -1;
1007                         }
1008                         argnumber[-dpoint] = i;
1009                 } else
1010 #endif /* NL_ARGMAX */
1011                 if (++p != fmt) {
1012                          /* Not using pos args but digits followed *. */
1013                         return -1;
1014                 }
1015                 i = INT_MIN;
1016         }
1017
1018         if (!dpoint) {
1019                 width = i;
1020                 if (*fmt == '.') {
1021                         ++fmt;
1022                         dpoint = -1;            /* To use as default precison. */
1023                         goto width_precision;
1024                 }
1025         } else {
1026                 preci = i;
1027         }
1028
1029         /* Process qualifier. */
1030         p = qual_chars;
1031         do {
1032                 if (*fmt == *p) {
1033                         ++fmt;
1034                         break;
1035                 }
1036         } while (*++p);
1037         if ((p - qual_chars < 2) && (*fmt == *p)) {
1038                 p += ((sizeof(qual_chars)-2) / 2);
1039                 ++fmt;
1040         }
1041         dataargtype = ((int)(p[(sizeof(qual_chars)-2) / 2])) << 8;
1042
1043         /* Process conversion specifier. */
1044         if (!*fmt) {
1045                 return -1;
1046         }
1047
1048         p = spec_chars;
1049
1050         do {
1051                 if (*fmt == *p) {
1052                         p_m_spec_chars = p - spec_chars;
1053
1054                         if ((p_m_spec_chars >= CONV_c)
1055                                 && (dataargtype & PA_FLAG_LONG)) {
1056                                 p_m_spec_chars -= 2; /* lc -> C and ls -> S */
1057                         }
1058
1059                         ppfs->conv_num = p_m_spec_chars;
1060                         p = spec_ranges-1;
1061                         while (p_m_spec_chars > *++p) {}
1062
1063                         i = p - spec_ranges;
1064                         argtype[2] = (dataargtype | spec_or_mask[i]) & spec_and_mask[i];
1065                         p = spec_chars;
1066                         break;
1067                 }
1068         } while(*++p);
1069
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;
1076
1077         if (!*p) {
1078 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1079                 if (*fmt == 'm') {
1080                         ppfs->conv_num = CONV_m;
1081                         ppfs->num_data_args = 0;
1082                         goto DONE;
1083                 }
1084 #endif
1085 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
1086
1087                 /* Handle custom arg -- WARNING -- overwrites p!!! */
1088                 ppfs->conv_num = CONV_custom0;
1089                 p = _custom_printf_spec;
1090                 do {
1091                         if (*p == *fmt) {
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! */
1097                                 }
1098                                 goto DONE;
1099                         }
1100                 } while (++p < (_custom_printf_spec + MAX_USER_SPEC));
1101 #endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
1102                 /* Otherwise error. */
1103                 return -1;
1104         }
1105                 
1106 #if defined(__UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__) || defined(__UCLIBC_HAS_PRINTF_M_SPEC__)
1107  DONE:
1108 #endif
1109
1110 #ifdef NL_ARGMAX
1111         if (maxposarg > 0) {
1112                 i = 0;
1113                 do {
1114                         /* Update maxposarg and check that NL_ARGMAX is not exceeded. */
1115                         n = ((i <= 2)
1116                                  ? (ppfs->argnumber[i] = argnumber[i])
1117                                  : argnumber[2] + (i-2));
1118                         if (n > maxposarg) {
1119                                 if ((maxposarg = n) > NL_ARGMAX) {
1120                                         return -1;
1121                                 }
1122                         }
1123                         --n;
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];
1127                         }
1128                 } while (++i < ppfs->num_data_args + 2);
1129         } else {
1130 #endif /* NL_ARGMAX */
1131                 ppfs->argnumber[2] = 1;
1132                 memcpy(ppfs->argtype, argtype + 2, ppfs->num_data_args * sizeof(int));
1133 #ifdef NL_ARGMAX
1134         }
1135
1136         ppfs->maxposarg = maxposarg;
1137 #endif /* NL_ARGMAX */
1138
1139 #ifdef __UCLIBC_HAS_WCHAR__
1140         if ((flags = ppfs->info._flags & FLAG_WIDESTREAM) == 0) {
1141                 ppfs->fmtpos = ++fmt;
1142         } else {
1143                 ppfs->fmtpos = (const char *) (((const wchar_t *)(ppfs->fmtpos))
1144                                                                            + (fmt - buf) );
1145         }
1146 #else  /* __UCLIBC_HAS_WCHAR__ */
1147         ppfs->fmtpos = ++fmt;
1148 #endif /* __UCLIBC_HAS_WCHAR__ */
1149
1150         return ppfs->num_data_args + 2;
1151 }
1152
1153 #endif
1154 /**********************************************************************/
1155 #ifdef L_register_printf_function
1156
1157 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
1158
1159 int register_printf_function(int spec, printf_function handler,
1160                                                          printf_arginfo_function arginfo)
1161 {
1162         register char *r;
1163         register char *p;
1164
1165         if (spec && (arginfo != NULL)) { /* TODO -- check if spec is valid char */
1166                 r = NULL;
1167                 p = _custom_printf_spec + MAX_USER_SPEC;
1168                 do {
1169                         --p;
1170                         if (!*p) {
1171                                 r = p;
1172                         }
1173 #ifdef __BCC__
1174                         else                            /* bcc generates less code with fall-through */
1175 #endif
1176                         if (*p == spec) {
1177                                 r = p;
1178                                 p = _custom_printf_spec;
1179                         }
1180                 } while (p > _custom_printf_spec);
1181
1182                 if (r) {
1183                         if (handler) {
1184                                 *r = spec;
1185                                 _custom_printf_handler[(int)(r - p)] = handler;
1186                                 _custom_printf_arginfo[(int)(r - p)] = arginfo;
1187                         } else {
1188                                 *r = 0;
1189                         }
1190                         return 0;
1191                 }
1192                 /* TODO -- if asked to unregister a non-existent spec, return what? */
1193         }
1194         return -1;
1195 }
1196
1197 #endif
1198
1199 #endif
1200 /**********************************************************************/
1201 #if defined(L__vfprintf_internal) || defined(L__vfwprintf_internal)
1202
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. */
1207
1208 static size_t _charpad(FILE * __restrict stream, int padchar, size_t numpad);
1209
1210 #ifdef L__vfprintf_internal
1211
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
1222
1223 #ifdef __STDIO_PRINTF_FLOAT
1224
1225 static size_t _fp_out_narrow(FILE *fp, intptr_t type, intptr_t len, intptr_t buf)
1226 {
1227         size_t r = 0;
1228
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) {
1233                                 return r;
1234                         }
1235                 }
1236                 len = buflen;
1237         }
1238         return r + OUTNSTR(fp, (const unsigned char *) buf, len);
1239 }
1240
1241 #endif /* __STDIO_PRINTF_FLOAT */
1242
1243 #else  /* L__vfprintf_internal */
1244
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
1255
1256 static size_t _outnstr(FILE *stream, const char *s, size_t wclen)
1257 {
1258         /* NOTE!!! len here is the number of wchars we want to generate!!! */
1259         wchar_t wbuf[64];
1260         mbstate_t mbstate;
1261         size_t todo, r, n;
1262
1263         mbstate.__mask = 0;
1264         todo = wclen;
1265         
1266         while (todo) {
1267                 r = mbsrtowcs(wbuf, &s,
1268                                           ((todo <= sizeof(wbuf)/sizeof(wbuf[0]))
1269                                            ? todo
1270                                            : sizeof(wbuf)/sizeof(wbuf[0])),
1271                                           &mbstate);
1272                 assert(((ssize_t)r) > 0);
1273                 n = _outnwcs(stream, wbuf, r);
1274                 todo -= n;
1275                 if (n != r) {
1276                         break;
1277                 }
1278         }
1279
1280         return wclen - todo;
1281 }
1282
1283 #ifdef __STDIO_PRINTF_FLOAT
1284
1285 #ifdef __UCLIBC_MJN3_ONLY__
1286 #warning TODO: Move defines from _fpmaxtostr.  Put them in a common header.
1287 #endif
1288
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 )
1293
1294 static size_t _fp_out_wide(FILE *fp, intptr_t type, intptr_t len, intptr_t buf)
1295 {
1296         wchar_t wbuf[BUF_SIZE];
1297         const char *s = (const char *) buf;
1298         size_t r = 0;
1299         int i;
1300
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) {
1305                                 return r;
1306                         }
1307                 }
1308                 len = buflen;
1309         }
1310
1311         if (len > 0) {
1312                 i = 0;
1313                 do {
1314 #ifdef __LOCALE_C_ONLY
1315                         wbuf[i] = s[i];
1316 #else  /* __LOCALE_C_ONLY */
1317
1318 #ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
1319                         if (s[i] == ',') {
1320                                 wbuf[i] = __UCLIBC_CURLOCALE_DATA.thousands_sep_wc;
1321                         } else
1322 #endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
1323                         if (s[i] == '.') {
1324                                 wbuf[i] = __UCLIBC_CURLOCALE_DATA.decimal_point_wc;
1325                         } else {
1326                                 wbuf[i] = s[i];
1327                         }
1328 #endif /* __LOCALE_C_ONLY */
1329
1330                 } while (++i < len);
1331
1332                 r += OUTNSTR(fp, wbuf, len);
1333         }
1334
1335         return r;
1336 }
1337
1338 #endif /* __STDIO_PRINTF_FLOAT */
1339
1340 static int _ppwfs_init(register ppfs_t *ppfs, const wchar_t *fmt0)
1341 {
1342         static const wchar_t invalid_wcs[] = L"Invalid wide format string.";
1343         int r;
1344
1345         /* First, zero out everything... argnumber[], argtype[], argptr[] */
1346         memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */
1347 #ifdef NL_ARGMAX
1348         --ppfs->maxposarg;                      /* set to -1 */
1349 #endif /* NL_ARGMAX */
1350         ppfs->fmtpos = (const char *) fmt0;
1351         ppfs->info._flags = FLAG_WIDESTREAM;
1352
1353         {
1354                 mbstate_t mbstate;
1355                 const wchar_t *p;
1356                 mbstate.__mask = 0;     /* Initialize the mbstate. */
1357                 p = fmt0;
1358                 if (wcsrtombs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) {
1359                         ppfs->fmtpos = (const char *) invalid_wcs;
1360                         return -1;
1361                 }
1362         }
1363
1364         /* now set all argtypes to no-arg */
1365         {
1366 #if 1
1367                 /* TODO - use memset here since already "paid for"? */
1368                 register int *p = ppfs->argtype;
1369                 
1370                 r = MAX_ARGS;
1371                 do {
1372                         *p++ = __PA_NOARG;
1373                 } while (--r);
1374 #else
1375                 /* TODO -- get rid of this?? */
1376                 register char *p = (char *) ((MAX_ARGS-1) * sizeof(int));
1377
1378                 do {
1379                         *((int *)(((char *)ppfs) + ((int)p) + offsetof(ppfs_t,argtype))) = __PA_NOARG;
1380                         p -= sizeof(int);
1381                 } while (p);
1382 #endif
1383         }
1384
1385         /*
1386          * Run through the entire format string to validate it and initialize
1387          * the positional arg numbers (if any).
1388          */
1389         {
1390                 register const wchar_t *fmt = fmt0;
1391
1392                 while (*fmt) {
1393                         if ((*fmt == '%') && (*++fmt != '%')) {
1394                                 ppfs->fmtpos = (const char *) fmt; /* back up to the '%' */
1395                                 if ((r = _ppfs_parsespec(ppfs)) < 0) {
1396                                         return -1;
1397                                 }
1398                                 fmt = (const wchar_t *) ppfs->fmtpos; /* update to one past end of spec */
1399                         } else {
1400                                 ++fmt;
1401                         }
1402                 }
1403                 ppfs->fmtpos = (const char *) fmt0; /* rewind */
1404         }
1405
1406 #ifdef NL_ARGMAX
1407         /* If we have positional args, make sure we know all the types. */
1408         {
1409                 register int *p = ppfs->argtype;
1410                 r = ppfs->maxposarg;
1411                 while (--r >= 0) {
1412                         if ( *p == __PA_NOARG ) { /* missing arg type!!! */
1413                                 return -1;
1414                         }
1415                         ++p;
1416                 }
1417         }
1418 #endif /* NL_ARGMAX */
1419
1420         return 0;
1421 }
1422
1423 #endif /* L__vfprintf_internal */
1424
1425
1426 static size_t _charpad(FILE * __restrict stream, int padchar, size_t numpad)
1427 {
1428         size_t todo = numpad;
1429
1430         /* TODO -- Use a buffer to cut down on function calls... */
1431         FMT_TYPE pad[1];
1432
1433         *pad = padchar;
1434         while (todo && (OUTNSTR(stream, (const unsigned char *) pad, 1) == 1)) {
1435                 --todo;
1436         }
1437
1438         return numpad - todo;
1439 }
1440
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)
1444 {
1445         static const char spec_base[] = SPEC_BASE;
1446 #ifdef L__vfprintf_internal
1447         static const char prefix[] = "+\0-\0 \0000x\0000X";
1448         /*                            0  2  4  6   9 11*/
1449 #else  /* L__vfprintf_internal */
1450         static const wchar_t prefix[] = L"+\0-\0 \0000x\0000X";
1451 #endif /* L__vfprintf_internal */
1452         enum {
1453                 PREFIX_PLUS = 0,
1454                 PREFIX_MINUS = 2,
1455                 PREFIX_SPACE = 4,
1456                 PREFIX_LWR_X = 6,
1457                 PREFIX_UPR_X = 9,
1458                 PREFIX_NONE = 11
1459         };
1460
1461 #ifdef __va_arg_ptr
1462         const void * const *argptr;
1463 #else
1464         const void * argptr[MAX_ARGS_PER_SPEC];
1465 #endif
1466         int *argtype;
1467 #ifdef __UCLIBC_HAS_WCHAR__
1468         const wchar_t *ws = NULL;
1469         mbstate_t mbstate;
1470 #endif /* __UCLIBC_HAS_WCHAR__ */
1471         size_t slen;
1472 #ifdef L__vfprintf_internal
1473 #define SLEN slen
1474 #else
1475         size_t SLEN;
1476         wchar_t wbuf[2];
1477 #endif
1478         int base;
1479         int numpad;
1480         int alphacase;
1481         int numfill = 0;                        /* TODO: fix */
1482         int prefix_num = PREFIX_NONE;
1483         char padchar = ' ';
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. */
1491         char buf[128];
1492
1493 #ifdef NDEBUG
1494         _ppfs_parsespec(ppfs);
1495 #else
1496         if (_ppfs_parsespec(ppfs) < 0) { /* TODO: just for debugging */
1497                 abort();
1498         }
1499 #endif
1500         _ppfs_setargs(ppfs);
1501
1502         argtype = ppfs->argtype + ppfs->argnumber[2] - 1;
1503         /* Deal with the argptr vs argvalue issue. */
1504 #ifdef __va_arg_ptr
1505         argptr = (const void * const *) ppfs->argptr;
1506 #ifdef NL_ARGMAX
1507         if (ppfs->maxposarg > 0) {      /* Using positional args... */
1508                 argptr += ppfs->argnumber[2] - 1;
1509         }
1510 #endif /* NL_ARGMAX */
1511 #else
1512         /* Need to build a local copy... */
1513         {
1514                 register argvalue_t *p = ppfs->argvalue;
1515                 int i;
1516 #ifdef NL_ARGMAX
1517                 if (ppfs->maxposarg > 0) {      /* Using positional args... */
1518                         p += ppfs->argnumber[2] - 1;
1519                 }
1520 #endif /* NL_ARGMAX */
1521                 for (i = 0 ; i < ppfs->num_data_args ; i++ ) {
1522                         argptr[i] = (void *) p++;
1523                 }
1524         }
1525 #endif
1526         {
1527                 register char *s = NULL; /* TODO: Should s be unsigned char * ? */
1528
1529                 if (ppfs->conv_num == CONV_n) {
1530                         _store_inttype(*(void **)*argptr,
1531                                                    ppfs->info._flags & __PA_INTMASK,
1532                                                    (intmax_t) (*count));
1533                         return 0;
1534                 }
1535                 if (ppfs->conv_num <= CONV_i) { /* pointer or (un)signed int */
1536                         alphacase = __UIM_LOWER;
1537
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?
1541 #endif
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;
1546                                 }
1547                                 if (PRINT_INFO_FLAG_VAL(&(ppfs->info),i18n)) {
1548                                         alphacase |= 0x80;
1549                                 }
1550                         }
1551
1552                         if (ppfs->conv_num <= CONV_u) { /* pointer or unsigned int */
1553                                 if (ppfs->conv_num == CONV_X) {
1554                                         alphacase = __UIM_UPPER;
1555                                 }
1556                                 if (ppfs->conv_num == CONV_p) { /* pointer */
1557                                         prefix_num = PREFIX_LWR_X;
1558                                 } else {                /* unsigned int */
1559                                 }
1560                         } else {                        /* signed int */
1561                                 base = -base;
1562                         }
1563                         if (ppfs->info.prec < 0) { /* Ignore '0' flag if prec specified. */
1564                                 padchar = ppfs->info.pad;
1565                         }
1566 #ifdef __UCLIBC_MJN3_ONLY__
1567 #ifdef L__vfprintf_internal
1568 #warning CONSIDER: If using outdigits and/or grouping, how should we interpret precision?
1569 #endif
1570 #endif /* __UCLIBC_MJN3_ONLY__ */
1571                         s = _uintmaxtostr(buf + sizeof(buf) - 1,
1572                                                           (uintmax_t)
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 */
1576                                 if (*s == '-') {
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;
1584                                 }
1585                         }
1586                         slen = (char *)(buf + sizeof(buf) - 1) - s;
1587 #ifdef L__vfwprintf_internal
1588                         {
1589                                 const char *q = s;
1590                                 mbstate.__mask = 0; /* Initialize the mbstate. */
1591                                 SLEN = mbsrtowcs(NULL, &q, 0, &mbstate);
1592                         }
1593 #endif
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;
1598                                 }
1599                                 if (ppfs->conv_num == CONV_X) {
1600                                         prefix_num = PREFIX_UPR_X;
1601                                 }
1602                                 if ((ppfs->conv_num == CONV_o) && (numfill <= SLEN)) {
1603                                         numfill = ((*s == '0') ? 1 : SLEN + 1);
1604                                 }
1605                         }
1606                         if (*s == '0') {
1607                                 if (prefix_num >= PREFIX_LWR_X) {
1608                                         prefix_num = PREFIX_NONE;
1609                                 }
1610                                 if (ppfs->conv_num == CONV_p) {/* null pointer */
1611                                         s = "(nil)";
1612 #ifdef L__vfwprintf_internal
1613                                         SLEN =
1614 #endif
1615                                         slen = 5;
1616                                         numfill = 0;
1617                                 } else if (numfill == 0) {      /* if precision 0, no output */
1618 #ifdef L__vfwprintf_internal
1619                                         SLEN =
1620 #endif
1621                                         slen = 0;
1622                                 }
1623                         }
1624                         numfill = ((numfill > SLEN) ? numfill - SLEN : 0);
1625                 } else if (ppfs->conv_num <= CONV_A) {  /* floating point */
1626 #ifdef __STDIO_PRINTF_FLOAT
1627                         ssize_t nf;
1628                         nf = _fpmaxtostr(stream,
1629                                                          (__fpmax_t)
1630                                                          (PRINT_INFO_FLAG_VAL(&(ppfs->info),is_long_double)
1631                                                           ? *(long double *) *argptr
1632                                                           : (long double) (* (double *) *argptr)),
1633                                                          &ppfs->info, FP_OUT );
1634                         if (nf < 0) {
1635                                 return -1;
1636                         }
1637                         *count += nf;
1638
1639                         return 0;
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
1645
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))) {
1650                                         goto NULL_STRING;
1651                                 }
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)
1659                                                                            ? ppfs->info.prec
1660                                                                            : SIZE_MAX), &mbstate))
1661                                         == ((size_t)-1)
1662                                         ) {
1663                                         return -1;      /* EILSEQ */
1664                                 }
1665                         } else {                        /* wide char */
1666                                 s = buf;
1667                                 slen = wcrtomb(s, (*((const wchar_t *) *argptr)), &mbstate);
1668                                 if (slen == ((size_t)-1)) {
1669                                         return -1;      /* EILSEQ */
1670                                 }
1671                                 s[slen] = 0;    /* TODO - Is this necessary? */
1672                         }
1673 #else  /* __UCLIBC_HAS_WCHAR__ */
1674                         return -1;
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));
1679                                 if (s) {
1680 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1681                                 SET_STRING_LEN:
1682 #endif
1683                                         slen = strnlen(s, ((ppfs->info.prec >= 0)
1684                                                                            ? ppfs->info.prec : SIZE_MAX));
1685                                 } else {
1686 #ifdef __UCLIBC_HAS_WCHAR__
1687                                 NULL_STRING:
1688 #endif
1689                                         s = "(null)";
1690                                         slen = 6;
1691                                 }
1692                         } else {                        /* char */
1693                                 s = buf;
1694                                 *s = (unsigned char)(*((const int *) *argptr));
1695                                 s[1] = 0;
1696                                 slen = 1;
1697                         }
1698
1699 #else  /* L__vfprintf_internal */
1700
1701                         if (ppfs->conv_num == CONV_S) { /* wide string */
1702                                 ws = *((wchar_t **) (*argptr));
1703                                 if (!ws) {
1704                                         goto NULL_STRING;
1705                                 }
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));
1710                         CHAR_CASE:
1711                                 ws = wbuf;
1712                                 wbuf[1] = 0;
1713                                 SLEN = 1;
1714                         }
1715
1716                 } else if (ppfs->conv_num <= CONV_s) {  /* char or string */
1717
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));
1723                                 if (s) {
1724 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1725                                 SET_STRING_LEN:
1726 #endif
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. */
1732                                         {
1733                                                 const char *q = s;
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),
1738                                                                                  &mbstate);
1739                                         }
1740                                         if (SLEN == ((size_t)(-1))) {
1741                                                 return -1;      /* EILSEQ */
1742                                         }
1743                                 } else {
1744                                 NULL_STRING:
1745                                         s = "(null)";
1746                                         SLEN = slen = 6;
1747                                 }
1748                         } else {                        /* char */
1749                                 *wbuf = btowc( (unsigned char)(*((const int *) *argptr)) );
1750                                 goto CHAR_CASE;
1751                         }
1752
1753 #endif /* L__vfprintf_internal */
1754
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;
1759 #endif
1760                 } else {
1761 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
1762                         assert(ppfs->conv_num == CONV_custom0);
1763
1764                         s = _custom_printf_spec;
1765                         do {
1766                                 if (*s == ppfs->info.spec) {
1767                                         int rv;
1768                                         /* TODO -- check return value for sanity? */
1769                                         rv = (*_custom_printf_handler
1770                                                   [(int)(s-_custom_printf_spec)])
1771                                                 (stream, &ppfs->info, argptr);
1772                                         if (rv < 0) {
1773                                                 return -1;
1774                                         }
1775                                         *count += rv;
1776                                         return 0;
1777                                 }
1778                         } while (++s < (_custom_printf_spec + MAX_USER_SPEC));
1779 #endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
1780                         assert(0);
1781                         return -1;
1782                 }
1783
1784 #ifdef __UCLIBC_MJN3_ONLY__
1785 #ifdef L__vfprintf_internal
1786 #warning CONSIDER: If using outdigits and/or grouping, how should we pad?
1787 #endif
1788 #endif /* __UCLIBC_MJN3_ONLY__ */
1789                 {
1790                         size_t t;
1791
1792                         t = SLEN + numfill;
1793                         if (prefix_num != PREFIX_NONE) {
1794                                 t += ((prefix_num < PREFIX_LWR_X) ? 1 : 2);
1795                         }
1796                         numpad = ((ppfs->info.width > t) ? (ppfs->info.width - t) : 0);
1797                         *count += t + numpad;
1798                 }
1799                 if (padchar == '0') { /* TODO: check this */
1800                         numfill += numpad;
1801                         numpad = 0;
1802                 }
1803
1804                 /* Now handle the output itself. */
1805                 if (!PRINT_INFO_FLAG_VAL(&(ppfs->info),left)) {
1806                         if (_charpad(stream, ' ', numpad) != numpad) {
1807                                 return -1;
1808                         }
1809                         numpad = 0;
1810                 }
1811                 OUTPUT(stream, prefix + prefix_num);
1812
1813                 if (_charpad(stream, '0', numfill) != numfill) {
1814                         return -1;
1815                 }
1816
1817 #ifdef L__vfprintf_internal
1818
1819 #ifdef __UCLIBC_HAS_WCHAR__
1820                 if (!ws) {
1821                         assert(s);
1822                         if (_outnstr(stream, s, slen) != slen) {
1823                                 return -1;
1824                         }
1825                 } else {                                /* wide string */
1826                         size_t t;
1827                         mbstate.__mask = 0;     /* Initialize the mbstate. */
1828                         while (slen) {
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) {
1833                                         return -1;
1834                                 }
1835                                 slen -= t;
1836                         }
1837                 }
1838 #else  /* __UCLIBC_HAS_WCHAR__ */
1839                 if (_outnstr(stream, (const unsigned char *) s, slen) != slen) {
1840                         return -1;
1841                 }
1842 #endif /* __UCLIBC_HAS_WCHAR__ */
1843
1844 #else  /* L__vfprintf_internal */
1845
1846                 if (!ws) {
1847                         assert(s);
1848                         if (_outnstr(stream, s, SLEN) != SLEN) {
1849                                 return -1;
1850                         }
1851                 } else {
1852                         if (_outnwcs(stream, ws, SLEN) != SLEN) {
1853                                 return -1;
1854                         }
1855                 }
1856
1857 #endif /* L__vfprintf_internal */
1858                 if (_charpad(stream, ' ', numpad) != numpad) {
1859                         return -1;
1860                 }
1861         }
1862
1863         return 0;
1864 }
1865
1866 libc_hidden_proto(fprintf)
1867
1868 int VFPRINTF_internal (FILE * __restrict stream,
1869                           const FMT_TYPE * __restrict format,
1870                           va_list arg)
1871 {
1872         ppfs_t ppfs;
1873         int count, r;
1874         register const FMT_TYPE *s;
1875
1876         count = 0;
1877         s = format;
1878
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);
1884 #endif
1885                 count = -1;
1886         } else {
1887                 _ppfs_prepargs(&ppfs, arg);     /* This did a va_copy!!! */
1888
1889                 do {
1890                         while (*format && (*format != '%')) {
1891                                 ++format;
1892                         }
1893
1894                         if (format-s) {         /* output any literal text in format string */
1895                                 if ( (r = OUTNSTR(stream, (const unsigned char *) s, format-s)) != (format-s)) {
1896                                         count = -1;
1897                                         break;
1898                                 }
1899                                 count += r;
1900                         }
1901
1902                         if (!*format) {                 /* we're done */
1903                                 break;
1904                         }
1905                 
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) {
1911                                         count = -1;
1912                                         break;
1913                                 }
1914                                 s = format = (const FMT_TYPE *) ppfs.fmtpos;
1915                         } else {                        /* %% means literal %, so start new string */
1916                                 s = ++format;
1917                                 ++format;
1918                         }
1919                 } while (1);
1920
1921                 va_end(ppfs.arg);               /* Need to clean up after va_copy! */
1922         }
1923
1924 /* #if defined(L__vfprintf_internal) && defined(__UCLIBC_HAS_WCHAR__) */
1925 /*  DONE: */
1926 /* #endif */
1927
1928         return count;
1929 }
1930 #endif /* defined(L__vfprintf_internal) || defined(L__vfwprintf_internal) */
1931
1932
1933 /**********************************************************************/
1934 #if defined(L_vfprintf) || defined(L_vfwprintf)
1935
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.
1941  *
1942  * In order to not pull in fseek through fputs, OUTPUT() macro
1943  * is using __stdio_fwrite (TODO: do the same for wide functions).
1944  */
1945 #ifdef L_vfprintf
1946 #define VFPRINTF vfprintf
1947 #define VFPRINTF_internal _vfprintf_internal
1948 #define FMT_TYPE char
1949 #else
1950 #define VFPRINTF vfwprintf
1951 #define VFPRINTF_internal _vfwprintf_internal
1952 #define FMT_TYPE wchar_t
1953 #endif
1954
1955 libc_hidden_proto(VFPRINTF)
1956 int VFPRINTF (FILE * __restrict stream,
1957                           const FMT_TYPE * __restrict format,
1958                           va_list arg)
1959 {
1960         int count;
1961         __STDIO_AUTO_THREADLOCK_VAR;
1962
1963         __STDIO_AUTO_THREADLOCK(stream);
1964
1965         if 
1966 #ifdef L_vfprintf
1967         (!__STDIO_STREAM_IS_NARROW_WRITING(stream)
1968          && __STDIO_STREAM_TRANS_TO_WRITE(stream, __FLAG_NARROW))
1969 #else
1970         (!__STDIO_STREAM_IS_WIDE_WRITING(stream)
1971          && __STDIO_STREAM_TRANS_TO_WRITE(stream, __FLAG_WIDE))
1972 #endif
1973         {
1974                 count = -1;
1975         } else {
1976                 count = VFPRINTF_internal(stream, format, arg);
1977         }
1978
1979         __STDIO_AUTO_THREADUNLOCK(stream);
1980
1981         return count;
1982 }
1983 libc_hidden_def(VFPRINTF)
1984 #endif /* defined(L_vfprintf) || defined(L_vfwprintf) */
1985
1986 /**********************************************************************/