OSDN Git Service

Remove __PRINTF_INFO_NO_BITFIELD hack, UCLIBC_INTERNAL can be used instead,
[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 #include <printf.h>
105
106 #ifdef __UCLIBC_HAS_THREADS__
107 #include <stdio_ext.h>
108 #include <pthread.h>
109 #endif /* __UCLIBC_HAS_THREADS__ */
110
111 #ifdef __UCLIBC_HAS_WCHAR__
112 #include <wchar.h>
113 #endif /* __UCLIBC_HAS_WCHAR__ */
114
115 #include <bits/uClibc_uintmaxtostr.h>
116 #include <bits/uClibc_va_copy.h>
117
118 /* Experimentally off - libc_hidden_proto(memcpy) */
119 /* Experimentally off - libc_hidden_proto(memset) */
120 /* Experimentally off - libc_hidden_proto(strlen) */
121 /* Experimentally off - libc_hidden_proto(strnlen) */
122 libc_hidden_proto(__glibc_strerror_r)
123 libc_hidden_proto(fputs_unlocked)
124 libc_hidden_proto(abort)
125 #ifdef __UCLIBC_HAS_WCHAR__
126 libc_hidden_proto(wcslen)
127 libc_hidden_proto(wcsnlen)
128 libc_hidden_proto(mbsrtowcs)
129 libc_hidden_proto(wcsrtombs)
130 libc_hidden_proto(btowc)
131 libc_hidden_proto(wcrtomb)
132 libc_hidden_proto(fputws)
133 #endif
134
135 /* Some older or broken gcc toolchains define LONG_LONG_MAX but not
136  * LLONG_MAX.  Since LLONG_MAX is part of the standard, that's what
137  * we use.  So complain if we do not have it but should.
138  */
139 #if !defined(LLONG_MAX) && defined(LONG_LONG_MAX)
140 #error Apparently, LONG_LONG_MAX is defined but LLONG_MAX is not.  You need to fix your toolchain headers to support the standard macros for (unsigned) long long.
141 #endif
142
143 /**********************************************************************/
144 /* These provide some control over printf's feature set */
145
146 /* This is undefined below depeding on uClibc's configuration. */
147 #define __STDIO_PRINTF_FLOAT 1
148
149 /* Now controlled by uClibc_stdio.h. */
150 /* #define __UCLIBC_HAS_PRINTF_M_SPEC__ */
151
152
153 /**********************************************************************/
154
155 #if defined(__UCLIBC__) && !defined(__UCLIBC_HAS_FLOATS__)
156 #undef __STDIO_PRINTF_FLOAT
157 #endif
158
159 #ifdef __BCC__
160 #undef __STDIO_PRINTF_FLOAT
161 #endif
162
163 #ifdef __STDIO_PRINTF_FLOAT
164 #include <float.h>
165 #include <bits/uClibc_fpmax.h>
166 #else  /* __STDIO_PRINTF_FLOAT */
167 #undef L__fpmaxtostr
168 #endif /* __STDIO_PRINTF_FLOAT */
169
170
171 #undef __STDIO_HAS_VSNPRINTF
172 #if defined(__STDIO_BUFFERS) || defined(__USE_OLD_VFPRINTF__) || defined(__UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__)
173 #define __STDIO_HAS_VSNPRINTF 1
174 #endif
175
176 /**********************************************************************/
177
178 /* Now controlled by uClibc_stdio.h. */
179 /* #define __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
180
181 /* TODO -- move these to a configuration section? */
182 #define MAX_FIELD_WIDTH         4095
183
184 #ifdef __UCLIBC_MJN3_ONLY__
185 #ifdef L_register_printf_function
186 /* emit only once */
187 #warning WISHLIST: Make MAX_USER_SPEC configurable?
188 #warning WISHLIST: Make MAX_ARGS_PER_SPEC configurable?
189 #endif
190 #endif /* __UCLIBC_MJN3_ONLY__ */
191
192 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
193
194 #define MAX_USER_SPEC       10
195 #define MAX_ARGS_PER_SPEC    5
196
197 #else  /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
198
199 #undef MAX_USER_SPEC
200 #define MAX_ARGS_PER_SPEC    1
201
202 #endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
203
204 #if MAX_ARGS_PER_SPEC < 1
205 #error MAX_ARGS_PER_SPEC < 1!
206 #undef MAX_ARGS_PER_SPEC
207 #define MAX_ARGS_PER_SPEC    1
208 #endif
209
210 #if defined(NL_ARGMAX) && (NL_ARGMAX < 9)
211 #error NL_ARGMAX < 9!
212 #endif
213
214 #if defined(NL_ARGMAX) && (NL_ARGMAX >= (MAX_ARGS_PER_SPEC + 2))
215 #define MAX_ARGS        NL_ARGMAX
216 #else
217 /* N for spec itself, plus 1 each for width and precision */
218 #define MAX_ARGS        (MAX_ARGS_PER_SPEC + 2)
219 #endif
220
221 /**********************************************************************/
222
223 #define __PA_FLAG_INTMASK \
224         (__PA_FLAG_CHAR|PA_FLAG_SHORT|__PA_FLAG_INT|PA_FLAG_LONG|PA_FLAG_LONG_LONG)
225
226 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
227 extern printf_function _custom_printf_handler[MAX_USER_SPEC] attribute_hidden;
228 extern printf_arginfo_function *_custom_printf_arginfo[MAX_USER_SPEC] attribute_hidden;
229 extern char *_custom_printf_spec attribute_hidden;
230 #endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
231
232 /**********************************************************************/
233
234 #define SPEC_FLAGS              " +0-#'I"
235 enum {
236         FLAG_SPACE              =       0x01,
237         FLAG_PLUS               =       0x02,   /* must be 2 * FLAG_SPACE */
238         FLAG_ZERO               =       0x04,
239         FLAG_MINUS              =       0x08,   /* must be 2 * FLAG_ZERO */
240         FLAG_HASH               =       0x10,
241         FLAG_THOUSANDS  =       0x20,
242         FLAG_I18N               =       0x40,   /* only works for d, i, u */
243         FLAG_WIDESTREAM =   0x80
244 };        
245
246 /**********************************************************************/
247
248 /* float layout          01234567890123456789   TODO: B?*/
249 #define SPEC_CHARS              "npxXoudifFeEgGaACScs"
250 enum {
251         CONV_n = 0,
252         CONV_p,
253         CONV_x, CONV_X, CONV_o, CONV_u, CONV_d, CONV_i,
254         CONV_f, CONV_F, CONV_e, CONV_E, CONV_g, CONV_G, CONV_a, CONV_A,
255         CONV_C, CONV_S, CONV_c, CONV_s,
256 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
257         CONV_m,
258 #endif
259         CONV_custom0                            /* must be last */
260 };
261
262 /*                         p   x   X  o   u   d   i */
263 #define SPEC_BASE               { 16, 16, 16, 8, 10, 10, 10 }
264
265 #define SPEC_RANGES             { CONV_n, CONV_p, CONV_i, CONV_A, \
266                                                   CONV_C, CONV_S, CONV_c, CONV_s, CONV_custom0 }
267
268 #define SPEC_OR_MASK             { \
269         /* n */                 (PA_FLAG_PTR|PA_INT), \
270         /* p */                 PA_POINTER, \
271         /* oxXudi */    PA_INT, \
272         /* fFeEgGaA */  PA_DOUBLE, \
273         /* C */                 PA_WCHAR, \
274         /* S */                 PA_WSTRING, \
275         /* c */                 PA_CHAR, \
276         /* s */                 PA_STRING, \
277 }
278
279 #define SPEC_AND_MASK           { \
280         /* n */                 (PA_FLAG_PTR|__PA_INTMASK), \
281         /* p */                 PA_POINTER, \
282         /* oxXudi */    (__PA_INTMASK), \
283         /* fFeEgGaA */  (PA_FLAG_LONG_DOUBLE|PA_DOUBLE), \
284         /* C */                 (PA_WCHAR), \
285         /* S */                 (PA_WSTRING), \
286         /* c */                 (PA_CHAR), \
287         /* s */                 (PA_STRING), \
288 }
289
290 /**********************************************************************/
291 /*
292  * In order to ease translation to what arginfo and _print_info._flags expect,
293  * we map:  0:int  1:char  2:longlong 4:long  8:short
294  * and then _flags |= (((q << 7) + q) & 0x701) and argtype |= (_flags & 0x701)
295  */
296
297 /* TODO -- Fix the table below to take into account stdint.h. */
298 /*  #ifndef LLONG_MAX */
299 /*  #error fix QUAL_CHARS for no long long!  Affects 'L', 'j', 'q', 'll'. */
300 /*  #else */
301 /*  #if LLONG_MAX != INTMAX_MAX */
302 /*  #error fix QUAL_CHARS intmax_t entry 'j'! */
303 /*  #endif */
304 /*  #endif */
305
306 #ifdef PDS
307 #error PDS already defined!
308 #endif
309 #ifdef SS
310 #error SS already defined!
311 #endif
312 #ifdef IMS
313 #error IMS already defined!
314 #endif
315
316 #if PTRDIFF_MAX == INT_MAX
317 #define PDS             0
318 #elif PTRDIFF_MAX == LONG_MAX
319 #define PDS             4
320 #elif defined(LLONG_MAX) && (PTRDIFF_MAX == LLONG_MAX)
321 #define PDS             8
322 #else
323 #error fix QUAL_CHARS ptrdiff_t entry 't'!
324 #endif
325
326 #if SIZE_MAX == UINT_MAX
327 #define SS              0
328 #elif SIZE_MAX == ULONG_MAX
329 #define SS              4
330 #elif defined(LLONG_MAX) && (SIZE_MAX == ULLONG_MAX)
331 #define SS              8
332 #else
333 #error fix QUAL_CHARS size_t entries 'z', 'Z'!
334 #endif
335
336 #if INTMAX_MAX == INT_MAX
337 #define IMS             0
338 #elif INTMAX_MAX == LONG_MAX
339 #define IMS             4
340 #elif defined(LLONG_MAX) && (INTMAX_MAX == LLONG_MAX)
341 #define IMS             8
342 #else
343 #error fix QUAL_CHARS intmax_t entry 'j'!
344 #endif
345
346 #define QUAL_CHARS              { \
347         /* j:(u)intmax_t z:(s)size_t  t:ptrdiff_t  \0:int */ \
348         /* q:long_long  Z:(s)size_t */ \
349         'h',   'l',  'L',  'j',  'z',  't',  'q', 'Z',  0, \
350          2,     4,    8,  IMS,   SS,  PDS,    8,  SS,   0, /* TODO -- fix!!! */\
351      1,     8 \
352 }
353
354 /**********************************************************************/
355
356 #ifdef __STDIO_VA_ARG_PTR
357 #ifdef __BCC__
358 #define __va_arg_ptr(ap,type)           (((type *)(ap += sizeof(type))) - 1)
359 #endif
360
361 #if 1
362 #ifdef __GNUC__
363 /* TODO -- need other than for 386 as well! */
364
365 #ifndef __va_rounded_size
366 #define __va_rounded_size(TYPE)  \
367   (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
368 #endif
369 #define __va_arg_ptr(AP, TYPE)                                          \
370  (AP = (va_list) ((char *) (AP) + __va_rounded_size (TYPE)),    \
371   ((void *) ((char *) (AP) - __va_rounded_size (TYPE))))
372 #endif
373 #endif
374 #endif /* __STDIO_VA_ARG_PTR */
375
376 #ifdef __va_arg_ptr
377 #define GET_VA_ARG(AP,F,TYPE,ARGS)      (*(AP) = __va_arg_ptr(ARGS,TYPE))
378 #define GET_ARG_VALUE(AP,F,TYPE)        (*((TYPE *)(*(AP))))
379 #else
380 typedef union {
381         wchar_t wc;
382         unsigned int u;
383         unsigned long ul;
384 #ifdef ULLONG_MAX
385         unsigned long long ull;
386 #endif
387 #ifdef __STDIO_PRINTF_FLOAT
388         double d;
389         long double ld;
390 #endif /* __STDIO_PRINTF_FLOAT */
391         void *p;
392 } argvalue_t;
393
394 #define GET_VA_ARG(AU,F,TYPE,ARGS)      (AU->F = va_arg(ARGS,TYPE))
395 #define GET_ARG_VALUE(AU,F,TYPE)        ((TYPE)((AU)->F))
396 #endif
397
398 typedef struct {
399         const char *fmtpos;                     /* TODO: move below struct?? */
400         struct printf_info info;
401 #ifdef NL_ARGMAX
402         int maxposarg;                          /* > 0 if args are positional, 0 if not, -1 if unknown */
403 #endif /* NL_ARGMAX */
404         int num_data_args;                      /* TODO: use sentinal??? */
405         unsigned int conv_num;
406         unsigned char argnumber[4]; /* width | prec | 1st data | unused */
407         int argtype[MAX_ARGS];
408         va_list arg;
409 #ifdef __va_arg_ptr
410         void *argptr[MAX_ARGS];
411 #else
412 /* if defined(NL_ARGMAX) || defined(__UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__) */
413         /* While this is wasteful of space in the case where pos args aren't
414          * enabled, it is also needed to support custom printf handlers. */
415         argvalue_t argvalue[MAX_ARGS];
416 #endif
417 } ppfs_t;                                               /* parse printf format state */
418
419 /**********************************************************************/
420
421 /* TODO: fix printf to return 0 and set errno if format error.  Standard says
422    only returns -1 if sets error indicator for the stream. */
423
424 #ifdef __STDIO_PRINTF_FLOAT
425 typedef size_t (__fp_outfunc_t)(FILE *fp, intptr_t type, intptr_t len,
426                                                                 intptr_t buf);
427
428 extern ssize_t _fpmaxtostr(FILE * fp, __fpmax_t x, struct printf_info *info,
429                                                    __fp_outfunc_t fp_outfunc) attribute_hidden;
430 #endif
431
432 extern int _ppfs_init(ppfs_t *ppfs, const char *fmt0) attribute_hidden; /* validates */
433 extern void _ppfs_prepargs(ppfs_t *ppfs, va_list arg) attribute_hidden; /* sets posargptrs */
434 extern void _ppfs_setargs(ppfs_t *ppfs) attribute_hidden; /* sets argptrs for current spec */
435 extern int _ppfs_parsespec(ppfs_t *ppfs) attribute_hidden; /* parses specifier */
436
437 extern void _store_inttype(void *dest, int desttype, uintmax_t val) attribute_hidden;
438 extern uintmax_t _load_inttype(int desttype, const void *src, int uflag) attribute_hidden;
439
440 /**********************************************************************/
441 #ifdef L_parse_printf_format
442
443 /* NOTE: This function differs from the glibc version in that parsing stops
444  * upon encountering an invalid conversion specifier.  Since this is the way
445  * my printf functions work, I think it makes sense to do it that way here.
446  * Unfortunately, since glibc sets the return type as size_t, we have no way
447  * of returning that the template is illegal, other than returning 0.
448  */
449
450 size_t parse_printf_format(register const char *template,
451                                                    size_t n, register int *argtypes)
452 {
453         ppfs_t ppfs;
454         size_t i;
455         size_t count = 0;
456
457         if (_ppfs_init(&ppfs, template) >= 0) {
458 #ifdef NL_ARGMAX
459                 if (ppfs.maxposarg > 0)  { /* Using positional args. */
460                         count = ppfs.maxposarg;
461                         if (n > count) {
462                                 n = count;
463                         }
464                         for (i = 0 ; i < n ; i++) {
465                                 *argtypes++ = ppfs.argtype[i];
466                         }
467                 } else {                                /* Not using positional args. */
468 #endif /* NL_ARGMAX */
469                         while (*template) {
470                                 if ((*template == '%') && (*++template != '%')) {
471                                         ppfs.fmtpos = template;
472                                         _ppfs_parsespec(&ppfs); /* Can't fail. */
473                                         template = ppfs.fmtpos; /* Update to one past spec end. */
474                                         if (ppfs.info.width == INT_MIN) {
475                                                 ++count;
476                                                 if (n > 0) {
477                                                         *argtypes++ = PA_INT;
478                                                         --n;
479                                                 }
480                                         }
481                                         if (ppfs.info.prec == INT_MIN) {
482                                                 ++count;
483                                                 if (n > 0) {
484                                                         *argtypes++ = PA_INT;
485                                                         --n;
486                                                 }
487                                         }
488                                         for (i = 0 ; i < ppfs.num_data_args ; i++) {
489                                                 if ((ppfs.argtype[i]) != __PA_NOARG) {
490                                                         ++count;
491                                                         if (n > 0) {
492                                                                 *argtypes++ = ppfs.argtype[i];
493                                                                 --n;
494                                                         }
495                                                 }
496                                         }
497                                 } else {
498                                         ++template;
499                                 }
500                         }
501 #ifdef NL_ARGMAX
502                 }
503 #endif /* NL_ARGMAX */
504         }
505
506         return count;
507 }
508
509 #endif
510 /**********************************************************************/
511 #ifdef L__ppfs_init
512
513 int attribute_hidden _ppfs_init(register ppfs_t *ppfs, const char *fmt0)
514 {
515         int r;
516
517         /* First, zero out everything... argnumber[], argtype[], argptr[] */
518         memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */
519 #ifdef NL_ARGMAX
520         --ppfs->maxposarg;                      /* set to -1 */
521 #endif /* NL_ARGMAX */
522         ppfs->fmtpos = fmt0;
523 #ifdef __UCLIBC_MJN3_ONLY__
524 #warning TODO: Make checking of the format string in C locale an option.
525 #endif
526 #ifdef __UCLIBC_HAS_LOCALE__
527         /* To support old programs, don't check mb validity if in C locale. */
528         if (((__UCLIBC_CURLOCALE_DATA).encoding) != __ctype_encoding_7_bit) {
529                 /* ANSI/ISO C99 requires format string to be a valid multibyte string
530                  * beginning and ending in its initial shift state. */
531                 static const char invalid_mbs[] = "Invalid multibyte format string.";
532                 mbstate_t mbstate;
533                 const char *p;
534                 mbstate.__mask = 0;     /* Initialize the mbstate. */
535                 p = fmt0;
536                 if (mbsrtowcs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) {
537                         ppfs->fmtpos = invalid_mbs;
538                         return -1;
539                 }
540         }
541 #endif /* __UCLIBC_HAS_LOCALE__ */
542         /* now set all argtypes to no-arg */
543         {
544 #if 1
545                 /* TODO - use memset here since already "paid for"? */
546                 register int *p = ppfs->argtype;
547                 
548                 r = MAX_ARGS;
549                 do {
550                         *p++ = __PA_NOARG;
551                 } while (--r);
552 #else
553                 /* TODO -- get rid of this?? */
554                 register char *p = (char *) ((MAX_ARGS-1) * sizeof(int));
555
556                 do {
557                         *((int *)(((char *)ppfs) + ((int)p) + offsetof(ppfs_t,argtype))) = __PA_NOARG;
558                         p -= sizeof(int);
559                 } while (p);
560 #endif
561         }
562
563         /*
564          * Run through the entire format string to validate it and initialize
565          * the positional arg numbers (if any).
566          */
567         {
568                 register const char *fmt = fmt0;
569
570                 while (*fmt) {
571                         if ((*fmt == '%') && (*++fmt != '%')) {
572                                 ppfs->fmtpos = fmt; /* back up to the '%' */
573                                 if ((r = _ppfs_parsespec(ppfs)) < 0) {
574                                         return -1;
575                                 }
576                                 fmt = ppfs->fmtpos;     /* update to one past end of spec */
577                         } else {
578                                 ++fmt;
579                         }
580                 }
581                 ppfs->fmtpos = fmt0;            /* rewind */
582         }
583
584 #ifdef NL_MAX_ARG
585         /* If we have positional args, make sure we know all the types. */
586         {
587                 register int *p = ppfs->argtype;
588                 r = ppfs->maxposarg;
589                 while (--r >= 0) {
590                         if ( *p == __PA_NOARG ) { /* missing arg type!!! */
591                                 return -1;
592                         }
593                         ++p;
594                 }
595         }
596 #endif /* NL_MAX_ARG */
597
598         return 0;
599 }
600 #endif
601 /**********************************************************************/
602 #ifdef L__ppfs_prepargs
603 void attribute_hidden _ppfs_prepargs(register ppfs_t *ppfs, va_list arg)
604 {
605         int i;
606
607         va_copy(ppfs->arg, arg);
608
609 #ifdef NL_ARGMAX
610         if ((i = ppfs->maxposarg) > 0)  { /* init for positional args */
611                 ppfs->num_data_args = i;
612                 ppfs->info.width = ppfs->info.prec = ppfs->maxposarg = 0;
613                 _ppfs_setargs(ppfs);
614                 ppfs->maxposarg = i;
615         }
616 #endif /* NL_ARGMAX */
617 }
618 #endif
619 /**********************************************************************/
620 #ifdef L__ppfs_setargs
621
622 void attribute_hidden _ppfs_setargs(register ppfs_t *ppfs)
623 {
624 #ifdef __va_arg_ptr
625         register void **p = ppfs->argptr;
626 #else
627         register argvalue_t *p = ppfs->argvalue;
628 #endif
629         int i;
630
631 #ifdef NL_ARGMAX
632         if (ppfs->maxposarg == 0) {     /* initing for or no pos args */
633 #endif /* NL_ARGMAX */
634                 if (ppfs->info.width == INT_MIN) {
635                         ppfs->info.width =
636 #ifdef __va_arg_ptr
637                                 *(int *)
638 #endif
639                                 GET_VA_ARG(p,u,unsigned int,ppfs->arg);
640                 } 
641                 if (ppfs->info.prec == INT_MIN) {
642                         ppfs->info.prec =
643 #ifdef __va_arg_ptr
644                                 *(int *)
645 #endif
646                                 GET_VA_ARG(p,u,unsigned int,ppfs->arg);
647                 }
648                 i = 0;
649                 while (i < ppfs->num_data_args) {
650                         switch(ppfs->argtype[i++]) {
651                                 case (PA_INT|PA_FLAG_LONG_LONG):
652 #ifdef ULLONG_MAX
653                                         GET_VA_ARG(p,ull,unsigned long long,ppfs->arg);
654                                         break;
655 #endif
656                                 case (PA_INT|PA_FLAG_LONG):
657 #if ULONG_MAX != UINT_MAX
658                                         GET_VA_ARG(p,ul,unsigned long,ppfs->arg);
659                                         break;
660 #endif
661                                 case PA_CHAR:   /* TODO - be careful */
662                                         /* ... users could use above and really want below!! */
663                                 case (PA_INT|__PA_FLAG_CHAR):/* TODO -- translate this!!! */
664                                 case (PA_INT|PA_FLAG_SHORT):
665                                 case PA_INT:
666                                         GET_VA_ARG(p,u,unsigned int,ppfs->arg);
667                                         break;
668                                 case PA_WCHAR:  /* TODO -- assume int? */
669                                         /* we're assuming wchar_t is at least an int */
670                                         GET_VA_ARG(p,wc,wchar_t,ppfs->arg);
671                                         break;
672 #ifdef __STDIO_PRINTF_FLOAT
673                                         /* PA_FLOAT */
674                                 case PA_DOUBLE:
675                                         GET_VA_ARG(p,d,double,ppfs->arg);
676                                         break;
677                                 case (PA_DOUBLE|PA_FLAG_LONG_DOUBLE):
678                                         GET_VA_ARG(p,ld,long double,ppfs->arg);
679                                         break;
680 #else  /* __STDIO_PRINTF_FLOAT */
681                                 case PA_DOUBLE:
682                                 case (PA_DOUBLE|PA_FLAG_LONG_DOUBLE):
683                                         assert(0);
684                                         continue;
685 #endif /* __STDIO_PRINTF_FLOAT */
686                                 default:
687                                         /* TODO -- really need to ensure this can't happen */
688                                         assert(ppfs->argtype[i-1] & PA_FLAG_PTR);
689                                 case PA_POINTER:
690                                 case PA_STRING:
691                                 case PA_WSTRING:
692                                         GET_VA_ARG(p,p,void *,ppfs->arg);
693                                         break;                          
694                                 case __PA_NOARG:
695                                         continue;
696                         }
697                         ++p;
698                 }
699 #ifdef NL_ARGMAX
700         } else {
701                 if (ppfs->info.width == INT_MIN) {
702                         ppfs->info.width
703                                 = (int) GET_ARG_VALUE(p + ppfs->argnumber[0] - 1,u,unsigned int);
704                 } 
705                 if (ppfs->info.prec == INT_MIN) {
706                         ppfs->info.prec
707                                 = (int) GET_ARG_VALUE(p + ppfs->argnumber[1] - 1,u,unsigned int);
708                 }
709         }
710 #endif /* NL_ARGMAX */
711
712         /* Now we know the width and precision. */
713         if (ppfs->info.width < 0) {
714                 ppfs->info.width = -ppfs->info.width;
715                 PRINT_INFO_SET_FLAG(&(ppfs->info),left);
716                 PRINT_INFO_CLR_FLAG(&(ppfs->info),space);
717                 ppfs->info.pad = ' ';
718         }
719 #if 0
720         /* NOTE -- keep neg for now so float knows! */
721         if (ppfs->info.prec < 0) {      /* spec says treat as omitted. */
722                 /* so use default prec... 1 for everything but floats and strings. */
723                 ppfs->info.prec = 1;
724         }
725 #endif
726 }
727 #endif
728 /**********************************************************************/
729 #ifdef L__ppfs_parsespec
730
731 #ifdef __UCLIBC_HAS_XLOCALE__
732 libc_hidden_proto(__ctype_b_loc)
733 #elif defined __UCLIBC_HAS_CTYPE_TABLES__
734 libc_hidden_proto(__ctype_b)
735 #endif
736
737 /* Notes: argtype differs from glibc for the following:
738  *         mine              glibc
739  *  lc     PA_WCHAR          PA_CHAR       the standard says %lc means %C
740  *  ls     PA_WSTRING        PA_STRING     the standard says %ls means %S
741  *  {*}n   {*}|PA_FLAG_PTR   PA_FLAG_PTR   size of n can be qualified
742  */
743
744 /* TODO: store positions of positional args */
745
746 /* TODO -- WARNING -- assumes aligned on integer boundaries!!! */
747
748 /* TODO -- disable if not using positional args!!! */
749 #define _OVERLAPPING_DIFFERENT_ARGS
750
751 /* TODO -- rethink this -- perhaps we should set to largest type??? */
752
753 #ifdef _OVERLAPPING_DIFFERENT_ARGS 
754
755 #define PROMOTED_SIZE_OF(X)             ((sizeof(X) + sizeof(int) - 1) / sizeof(X))
756
757 static const short int type_codes[] = {
758         __PA_NOARG,                                     /* must be first entry */
759         PA_POINTER,
760         PA_STRING,
761         PA_WSTRING,
762         PA_CHAR,
763         PA_INT|PA_FLAG_SHORT,
764         PA_INT,
765         PA_INT|PA_FLAG_LONG,
766         PA_INT|PA_FLAG_LONG_LONG,
767         PA_WCHAR,
768 #ifdef __STDIO_PRINTF_FLOAT
769         /* PA_FLOAT, */
770         PA_DOUBLE,
771         PA_DOUBLE|PA_FLAG_LONG_DOUBLE,
772 #endif /* __STDIO_PRINTF_FLOAT */
773 };
774
775 static const unsigned char type_sizes[] = {
776         /* unknown type consumes no arg */
777         0,                                                      /* must be first entry */
778         PROMOTED_SIZE_OF(void *),
779         PROMOTED_SIZE_OF(char *),
780         PROMOTED_SIZE_OF(wchar_t *),
781         PROMOTED_SIZE_OF(char),
782         PROMOTED_SIZE_OF(short),
783         PROMOTED_SIZE_OF(int),
784         PROMOTED_SIZE_OF(long),
785 #ifdef ULLONG_MAX
786         PROMOTED_SIZE_OF(long long),
787 #else
788         PROMOTED_SIZE_OF(long),         /* TODO -- is this correct? (above too) */
789 #endif
790         PROMOTED_SIZE_OF(wchar_t),
791 #ifdef __STDIO_PRINTF_FLOAT
792         /* PROMOTED_SIZE_OF(float), */
793         PROMOTED_SIZE_OF(double),
794         PROMOTED_SIZE_OF(long double),
795 #endif /* __STDIO_PRINTF_FLOAT */
796 };
797
798 static int _promoted_size(int argtype)
799 {
800         register const short int *p;
801
802         /* note -- since any unrecognized type is treated as a pointer */
803         p = type_codes + sizeof(type_codes)/sizeof(type_codes[0]);
804         do {
805                 if (*--p == argtype) {
806                         break;
807                 }
808         } while (p > type_codes);
809
810         return type_sizes[(int)(p - type_codes)];
811 }
812
813 static int _is_equal_or_bigger_arg(int curtype, int newtype)
814 {
815         /* Quick test */
816         if (newtype == __PA_NOARG) {
817                 return 0;
818         }
819         if ((curtype == __PA_NOARG) || (curtype == newtype)) {
820                 return 1;
821         }
822         /* Ok... slot is already filled and types are different in name. */
823         /* So, compare promoted sizes of curtype and newtype args. */
824         return _promoted_size(curtype) <= _promoted_size(newtype);
825 }
826
827 #else
828
829 #define _is_equal_or_bigger_arg(C,N)    (((C) == __PA_NOARG) || ((C) == (N)))
830
831 #endif
832
833 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
834 /* TODO - do this differently? */
835 static char _bss_custom_printf_spec[MAX_USER_SPEC]; /* 0-init'd for us.  */
836
837 attribute_hidden char *_custom_printf_spec = _bss_custom_printf_spec;
838 attribute_hidden printf_arginfo_function *_custom_printf_arginfo[MAX_USER_SPEC];
839 attribute_hidden printf_function _custom_printf_handler[MAX_USER_SPEC];
840 #endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
841
842 int attribute_hidden _ppfs_parsespec(ppfs_t *ppfs)
843 {
844         register const char *fmt;
845         register const char *p;
846         int preci;
847         int width;
848         int flags;
849         int dataargtype;
850         int i;
851         int dpoint;
852 #ifdef NL_ARGMAX
853         int maxposarg;
854 #endif /* NL_ARGMAX */
855         int p_m_spec_chars;
856         int n;
857         int argtype[MAX_ARGS_PER_SPEC+2];
858         int argnumber[3];                       /* width, precision, 1st data arg */
859         static const char spec_flags[] = SPEC_FLAGS;
860         static const char spec_chars[] = SPEC_CHARS;/* TODO: b? */
861         static const char spec_ranges[] = SPEC_RANGES;
862         static const short spec_or_mask[] = SPEC_OR_MASK;
863         static const short spec_and_mask[] = SPEC_AND_MASK;
864         static const char qual_chars[] = QUAL_CHARS;
865 #ifdef __UCLIBC_HAS_WCHAR__
866         char buf[32];
867 #endif /* __UCLIBC_HAS_WCHAR__ */
868
869         /* WIDE note: we can test against '%' here since we don't allow */
870         /* WIDE note: other mappings of '%' in the wide char set. */
871         preci = -1;
872         argnumber[0] = 0;
873         argnumber[1] = 0;
874         argtype[0] = __PA_NOARG;
875         argtype[1] = __PA_NOARG;
876 #ifdef NL_ARGMAX
877         maxposarg = ppfs->maxposarg;
878 #endif /* NL_ARGMAX */
879
880 #ifdef __UCLIBC_HAS_WCHAR__
881         /* This is somewhat lame, but saves a lot of code.  If we're dealing with
882          * a wide stream, that means the format is a wchar string.  So, copy it
883          * char-by-char into a normal char buffer for processing.  Make the buffer
884          * (buf) big enough so that any reasonable format specifier will fit.
885          * While there a legal specifiers that won't, the all involve duplicate
886          * flags or outrageous field widths/precisions. */
887         width = dpoint = 0;
888         if ((flags = ppfs->info._flags & FLAG_WIDESTREAM) == 0) {
889                 fmt = ppfs->fmtpos;
890         } else {
891                 fmt = buf + 1;
892                 i = 0;
893                 do {
894                         if ((buf[i] = (char) (((wchar_t *) ppfs->fmtpos)[i-1]))
895                                 != (((wchar_t *) ppfs->fmtpos)[i-1])
896                                 ) {
897                                 return -1;
898                         }
899                 } while (buf[i++] && (i < sizeof(buf)));
900                 buf[sizeof(buf)-1] = 0;
901         }
902 #else  /* __UCLIBC_HAS_WCHAR__ */
903         width = flags = dpoint = 0;
904         fmt = ppfs->fmtpos;
905 #endif /* __UCLIBC_HAS_WCHAR__ */
906
907         assert(fmt[-1] == '%');
908         assert(fmt[0] != '%');
909
910         /* Process arg pos and/or flags and/or width and/or precision. */
911  width_precision:
912         p = fmt;
913         if (*fmt == '*') {
914                 argtype[-dpoint] = PA_INT;
915                 ++fmt;
916         }
917         i = 0;
918         while (isdigit(*fmt)) {
919                 if (i < MAX_FIELD_WIDTH) { /* Avoid overflow. */
920                         i = (i * 10) + (*fmt - '0');
921                 }
922                 ++fmt;
923         }
924         if (p[-1] == '%') { /* Check for a position. */
925
926                 /* TODO: if val not in range, then error */
927
928 #ifdef NL_ARGMAX
929                 if ((*fmt == '$') && (i > 0)) {/* Positional spec. */
930                         ++fmt;
931                         if (maxposarg == 0) {
932                                 return -1;
933                         }
934                         if ((argnumber[2] = i) > maxposarg) {
935                                 maxposarg = i;
936                         }
937                         /* Now fall through to check flags. */
938                 } else {
939                         if (maxposarg > 0) {
940 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
941 #ifdef __UCLIBC_MJN3_ONLY__
942 #warning TODO: Support prec and width for %m when positional args used
943                                 /* Actually, positional arg processing will fail in general
944                                  * for specifiers that don't require an arg. */
945 #endif /* __UCLIBC_MJN3_ONLY__ */
946                                 if (*fmt == 'm') {
947                                         goto PREC_WIDTH;
948                                 }
949 #endif /* __UCLIBC_HAS_PRINTF_M_SPEC__ */
950                                 return -1;
951                         }
952                         maxposarg = 0;          /* Possible redundant store, but cuts size. */
953
954                         if ((fmt > p) && (*p != '0')) {
955                                 goto PREC_WIDTH;
956                         }
957
958                         fmt = p;                        /* Back up for possible '0's flag. */
959                         /* Now fall through to check flags. */
960                 }
961 #else  /* NL_ARGMAX */
962                 if (*fmt == '$') {              /* Positional spec. */
963                         return -1;
964                 }
965
966                 if ((fmt > p) && (*p != '0')) {
967                         goto PREC_WIDTH;
968                 }
969
970                 fmt = p;                        /* Back up for possible '0's flag. */
971                 /* Now fall through to check flags. */
972 #endif /* NL_ARGMAX */
973
974         restart_flags:          /* Process flags. */
975                 i = 1;
976                 p = spec_flags;
977         
978                 do {
979                         if (*fmt == *p++) {
980                                 ++fmt;
981                                 flags |= i;
982                                 goto restart_flags;
983                         }
984                         i += i;                         /* Better than i <<= 1 for bcc */
985                 } while (*p);
986                 i = 0;
987
988                 /* If '+' then ignore ' ', and if '-' then ignore '0'. */
989                 /* Note: Need to ignore '0' when prec is an arg with val < 0, */
990                 /*       but that test needs to wait until the arg is retrieved. */
991                 flags &= ~((flags & (FLAG_PLUS|FLAG_MINUS)) >> 1);
992                 /* Note: Ignore '0' when prec is specified < 0 too (in printf). */
993
994                 if (fmt[-1] != '%') {   /* If we've done anything, loop for width. */
995                         goto width_precision;
996                 }
997         }
998  PREC_WIDTH:
999         if (*p == '*') {                        /* Prec or width takes an arg. */
1000 #ifdef NL_ARGMAX
1001                 if (maxposarg) {
1002                         if ((*fmt++ != '$') || (i <= 0)) {
1003                                 /* Using pos args and no $ or invalid arg number. */
1004                                 return -1;
1005                         }
1006                         argnumber[-dpoint] = i;
1007                 } else
1008 #endif /* NL_ARGMAX */
1009                 if (++p != fmt) {
1010                          /* Not using pos args but digits followed *. */
1011                         return -1;
1012                 }
1013                 i = INT_MIN;
1014         }
1015
1016         if (!dpoint) {
1017                 width = i;
1018                 if (*fmt == '.') {
1019                         ++fmt;
1020                         dpoint = -1;            /* To use as default precison. */
1021                         goto width_precision;
1022                 }
1023         } else {
1024                 preci = i;
1025         }
1026
1027         /* Process qualifier. */
1028         p = qual_chars;
1029         do {
1030                 if (*fmt == *p) {
1031                         ++fmt;
1032                         break;
1033                 }
1034         } while (*++p);
1035         if ((p - qual_chars < 2) && (*fmt == *p)) {
1036                 p += ((sizeof(qual_chars)-2) / 2);
1037                 ++fmt;
1038         }
1039         dataargtype = ((int)(p[(sizeof(qual_chars)-2) / 2])) << 8;
1040
1041         /* Process conversion specifier. */
1042         if (!*fmt) {
1043                 return -1;
1044         }
1045
1046         p = spec_chars;
1047
1048         do {
1049                 if (*fmt == *p) {
1050                         p_m_spec_chars = p - spec_chars;
1051
1052                         if ((p_m_spec_chars >= CONV_c)
1053                                 && (dataargtype & PA_FLAG_LONG)) {
1054                                 p_m_spec_chars -= 2; /* lc -> C and ls -> S */
1055                         }
1056
1057                         ppfs->conv_num = p_m_spec_chars;
1058                         p = spec_ranges-1;
1059                         while (p_m_spec_chars > *++p) {}
1060
1061                         i = p - spec_ranges;
1062                         argtype[2] = (dataargtype | spec_or_mask[i]) & spec_and_mask[i];
1063                         p = spec_chars;
1064                         break;
1065                 }
1066         } while(*++p);
1067
1068         ppfs->info.spec = *fmt;
1069         ppfs->info.prec = preci;
1070         ppfs->info.width = width;
1071         ppfs->info.pad = ((flags & FLAG_ZERO) ? '0' : ' ');
1072         ppfs->info._flags = (flags & ~FLAG_ZERO) | (dataargtype & __PA_INTMASK);
1073         ppfs->num_data_args = 1;
1074
1075         if (!*p) {
1076 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1077                 if (*fmt == 'm') {
1078                         ppfs->conv_num = CONV_m;
1079                         ppfs->num_data_args = 0;
1080                         goto DONE;
1081                 }
1082 #endif
1083 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
1084
1085                 /* Handle custom arg -- WARNING -- overwrites p!!! */
1086                 ppfs->conv_num = CONV_custom0;
1087                 p = _custom_printf_spec;
1088                 do {
1089                         if (*p == *fmt) {
1090                                 if ((ppfs->num_data_args
1091                                          = ((*_custom_printf_arginfo[(int)(p-_custom_printf_spec)])
1092                                                 (&(ppfs->info), MAX_ARGS_PER_SPEC, argtype+2)))
1093                                         > MAX_ARGS_PER_SPEC) {
1094                                         break;          /* Error -- too many args! */
1095                                 }
1096                                 goto DONE;
1097                         }
1098                 } while (++p < (_custom_printf_spec + MAX_USER_SPEC));
1099 #endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
1100                 /* Otherwise error. */
1101                 return -1;
1102         }
1103                 
1104 #if defined(__UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__) || defined(__UCLIBC_HAS_PRINTF_M_SPEC__)
1105  DONE:
1106 #endif
1107
1108 #ifdef NL_ARGMAX
1109         if (maxposarg > 0) {
1110                 i = 0;
1111                 do {
1112                         /* Update maxposarg and check that NL_ARGMAX is not exceeded. */
1113                         n = ((i <= 2)
1114                                  ? (ppfs->argnumber[i] = argnumber[i])
1115                                  : argnumber[2] + (i-2));
1116                         if (n > maxposarg) {
1117                                 if ((maxposarg = n) > NL_ARGMAX) {
1118                                         return -1;
1119                                 }
1120                         }
1121                         --n;
1122                         /* Record argtype with largest size (current, new). */
1123                         if (_is_equal_or_bigger_arg(ppfs->argtype[n], argtype[i])) {
1124                                 ppfs->argtype[n] = argtype[i];
1125                         }
1126                 } while (++i < ppfs->num_data_args + 2);
1127         } else {
1128 #endif /* NL_ARGMAX */
1129                 ppfs->argnumber[2] = 1;
1130                 memcpy(ppfs->argtype, argtype + 2, ppfs->num_data_args * sizeof(int));
1131 #ifdef NL_ARGMAX
1132         }
1133
1134         ppfs->maxposarg = maxposarg;
1135 #endif /* NL_ARGMAX */
1136
1137 #ifdef __UCLIBC_HAS_WCHAR__
1138         if ((flags = ppfs->info._flags & FLAG_WIDESTREAM) == 0) {
1139                 ppfs->fmtpos = ++fmt;
1140         } else {
1141                 ppfs->fmtpos = (const char *) (((const wchar_t *)(ppfs->fmtpos))
1142                                                                            + (fmt - buf) );
1143         }
1144 #else  /* __UCLIBC_HAS_WCHAR__ */
1145         ppfs->fmtpos = ++fmt;
1146 #endif /* __UCLIBC_HAS_WCHAR__ */
1147
1148         return ppfs->num_data_args + 2;
1149 }
1150
1151 #endif
1152 /**********************************************************************/
1153 #ifdef L_register_printf_function
1154
1155 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
1156
1157 int register_printf_function(int spec, printf_function handler,
1158                                                          printf_arginfo_function arginfo)
1159 {
1160         register char *r;
1161         register char *p;
1162
1163         if (spec && (arginfo != NULL)) { /* TODO -- check if spec is valid char */
1164                 r = NULL;
1165                 p = _custom_printf_spec + MAX_USER_SPEC;
1166                 do {
1167                         --p;
1168                         if (!*p) {
1169                                 r = p;
1170                         }
1171 #ifdef __BCC__
1172                         else                            /* bcc generates less code with fall-through */
1173 #endif
1174                         if (*p == spec) {
1175                                 r = p;
1176                                 p = _custom_printf_spec;
1177                         }
1178                 } while (p > _custom_printf_spec);
1179
1180                 if (r) {
1181                         if (handler) {
1182                                 *r = spec;
1183                                 _custom_printf_handler[(int)(r - p)] = handler;
1184                                 _custom_printf_arginfo[(int)(r - p)] = arginfo;
1185                         } else {
1186                                 *r = 0;
1187                         }
1188                         return 0;
1189                 }
1190                 /* TODO -- if asked to unregister a non-existent spec, return what? */
1191         }
1192         return -1;
1193 }
1194
1195 #endif
1196
1197 #endif
1198 /**********************************************************************/
1199 #if defined(L__vfprintf_internal) || defined(L__vfwprintf_internal)
1200
1201 /* We only support ascii digits (or their USC equivalent codes) in
1202  * precision and width settings in *printf (wide) format strings.
1203  * In other words, we don't currently support glibc's 'I' flag.
1204  * We do accept it, but it is currently ignored. */
1205
1206 static size_t _charpad(FILE * __restrict stream, int padchar, size_t numpad);
1207
1208 #ifdef L__vfprintf_internal
1209
1210 #define VFPRINTF_internal _vfprintf_internal
1211 #define FMT_TYPE char
1212 #define OUTNSTR _outnstr
1213 #define STRLEN  strlen
1214 #define _PPFS_init _ppfs_init
1215 /* Pulls in fseek: #define OUTPUT(F,S)  fputs_unlocked(S,F) */
1216 #define OUTPUT(F,S)                     __stdio_fwrite((const unsigned char *)(S),strlen(S),(F))
1217 /* #define _outnstr(stream, string, len)        __stdio_fwrite(string, len, stream) */
1218 #define _outnstr(stream, string, len)   ((len > 0) ? __stdio_fwrite(string, len, stream) : 0)
1219 #define FP_OUT _fp_out_narrow
1220
1221 #ifdef __STDIO_PRINTF_FLOAT
1222
1223 static size_t _fp_out_narrow(FILE *fp, intptr_t type, intptr_t len, intptr_t buf)
1224 {
1225         size_t r = 0;
1226
1227         if (type & 0x80) {                      /* Some type of padding needed. */
1228                 int buflen = strlen((const char *) buf);
1229                 if ((len -= buflen) > 0) {
1230                         if ((r = _charpad(fp, (type & 0x7f), len)) != len) {
1231                                 return r;
1232                         }
1233                 }
1234                 len = buflen;
1235         }
1236         return r + OUTNSTR(fp, (const unsigned char *) buf, len);
1237 }
1238
1239 #endif /* __STDIO_PRINTF_FLOAT */
1240
1241 #else  /* L__vfprintf_internal */
1242
1243 #define VFPRINTF_internal _vfwprintf_internal
1244 #define FMT_TYPE wchar_t
1245 #define OUTNSTR _outnwcs
1246 #define STRLEN  wcslen
1247 #define _PPFS_init _ppwfs_init
1248 /* Pulls in fseek: */
1249 #define OUTPUT(F,S)                     fputws(S,F)
1250 /* TODO: #define OUTPUT(F,S)            _wstdio_fwrite((S),wcslen(S),(F)) */
1251 #define _outnwcs(stream, wstring, len)  _wstdio_fwrite(wstring, len, stream)
1252 #define FP_OUT _fp_out_wide
1253
1254 static size_t _outnstr(FILE *stream, const char *s, size_t wclen)
1255 {
1256         /* NOTE!!! len here is the number of wchars we want to generate!!! */
1257         wchar_t wbuf[64];
1258         mbstate_t mbstate;
1259         size_t todo, r, n;
1260
1261         mbstate.__mask = 0;
1262         todo = wclen;
1263         
1264         while (todo) {
1265                 r = mbsrtowcs(wbuf, &s,
1266                                           ((todo <= sizeof(wbuf)/sizeof(wbuf[0]))
1267                                            ? todo
1268                                            : sizeof(wbuf)/sizeof(wbuf[0])),
1269                                           &mbstate);
1270                 assert(((ssize_t)r) > 0);
1271                 n = _outnwcs(stream, wbuf, r);
1272                 todo -= n;
1273                 if (n != r) {
1274                         break;
1275                 }
1276         }
1277
1278         return wclen - todo;
1279 }
1280
1281 #ifdef __STDIO_PRINTF_FLOAT
1282
1283 #ifdef __UCLIBC_MJN3_ONLY__
1284 #warning TODO: Move defines from _fpmaxtostr.  Put them in a common header.
1285 #endif
1286
1287 /* The following defines are from _fpmaxtostr.*/
1288 #define DIGITS_PER_BLOCK     9
1289 #define NUM_DIGIT_BLOCKS   ((DECIMAL_DIG+DIGITS_PER_BLOCK-1)/DIGITS_PER_BLOCK)
1290 #define BUF_SIZE  ( 3 + NUM_DIGIT_BLOCKS * DIGITS_PER_BLOCK )
1291
1292 static size_t _fp_out_wide(FILE *fp, intptr_t type, intptr_t len, intptr_t buf)
1293 {
1294         wchar_t wbuf[BUF_SIZE];
1295         const char *s = (const char *) buf;
1296         size_t r = 0;
1297         int i;
1298
1299         if (type & 0x80) {                      /* Some type of padding needed */
1300                 int buflen = strlen(s);
1301                 if ((len -= buflen) > 0) {
1302                         if ((r = _charpad(fp, (type & 0x7f), len)) != len) {
1303                                 return r;
1304                         }
1305                 }
1306                 len = buflen;
1307         }
1308
1309         if (len > 0) {
1310                 i = 0;
1311                 do {
1312 #ifdef __LOCALE_C_ONLY
1313                         wbuf[i] = s[i];
1314 #else  /* __LOCALE_C_ONLY */
1315
1316 #ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
1317                         if (s[i] == ',') {
1318                                 wbuf[i] = __UCLIBC_CURLOCALE_DATA.thousands_sep_wc;
1319                         } else
1320 #endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
1321                         if (s[i] == '.') {
1322                                 wbuf[i] = __UCLIBC_CURLOCALE_DATA.decimal_point_wc;
1323                         } else {
1324                                 wbuf[i] = s[i];
1325                         }
1326 #endif /* __LOCALE_C_ONLY */
1327
1328                 } while (++i < len);
1329
1330                 r += OUTNSTR(fp, wbuf, len);
1331         }
1332
1333         return r;
1334 }
1335
1336 #endif /* __STDIO_PRINTF_FLOAT */
1337
1338 static int _ppwfs_init(register ppfs_t *ppfs, const wchar_t *fmt0)
1339 {
1340         static const wchar_t invalid_wcs[] = L"Invalid wide format string.";
1341         int r;
1342
1343         /* First, zero out everything... argnumber[], argtype[], argptr[] */
1344         memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */
1345 #ifdef NL_ARGMAX
1346         --ppfs->maxposarg;                      /* set to -1 */
1347 #endif /* NL_ARGMAX */
1348         ppfs->fmtpos = (const char *) fmt0;
1349         ppfs->info._flags = FLAG_WIDESTREAM;
1350
1351         {
1352                 mbstate_t mbstate;
1353                 const wchar_t *p;
1354                 mbstate.__mask = 0;     /* Initialize the mbstate. */
1355                 p = fmt0;
1356                 if (wcsrtombs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) {
1357                         ppfs->fmtpos = (const char *) invalid_wcs;
1358                         return -1;
1359                 }
1360         }
1361
1362         /* now set all argtypes to no-arg */
1363         {
1364 #if 1
1365                 /* TODO - use memset here since already "paid for"? */
1366                 register int *p = ppfs->argtype;
1367                 
1368                 r = MAX_ARGS;
1369                 do {
1370                         *p++ = __PA_NOARG;
1371                 } while (--r);
1372 #else
1373                 /* TODO -- get rid of this?? */
1374                 register char *p = (char *) ((MAX_ARGS-1) * sizeof(int));
1375
1376                 do {
1377                         *((int *)(((char *)ppfs) + ((int)p) + offsetof(ppfs_t,argtype))) = __PA_NOARG;
1378                         p -= sizeof(int);
1379                 } while (p);
1380 #endif
1381         }
1382
1383         /*
1384          * Run through the entire format string to validate it and initialize
1385          * the positional arg numbers (if any).
1386          */
1387         {
1388                 register const wchar_t *fmt = fmt0;
1389
1390                 while (*fmt) {
1391                         if ((*fmt == '%') && (*++fmt != '%')) {
1392                                 ppfs->fmtpos = (const char *) fmt; /* back up to the '%' */
1393                                 if ((r = _ppfs_parsespec(ppfs)) < 0) {
1394                                         return -1;
1395                                 }
1396                                 fmt = (const wchar_t *) ppfs->fmtpos; /* update to one past end of spec */
1397                         } else {
1398                                 ++fmt;
1399                         }
1400                 }
1401                 ppfs->fmtpos = (const char *) fmt0; /* rewind */
1402         }
1403
1404 #ifdef NL_ARGMAX
1405         /* If we have positional args, make sure we know all the types. */
1406         {
1407                 register int *p = ppfs->argtype;
1408                 r = ppfs->maxposarg;
1409                 while (--r >= 0) {
1410                         if ( *p == __PA_NOARG ) { /* missing arg type!!! */
1411                                 return -1;
1412                         }
1413                         ++p;
1414                 }
1415         }
1416 #endif /* NL_ARGMAX */
1417
1418         return 0;
1419 }
1420
1421 #endif /* L__vfprintf_internal */
1422
1423
1424 static size_t _charpad(FILE * __restrict stream, int padchar, size_t numpad)
1425 {
1426         size_t todo = numpad;
1427
1428         /* TODO -- Use a buffer to cut down on function calls... */
1429         FMT_TYPE pad[1];
1430
1431         *pad = padchar;
1432         while (todo && (OUTNSTR(stream, (const unsigned char *) pad, 1) == 1)) {
1433                 --todo;
1434         }
1435
1436         return numpad - todo;
1437 }
1438
1439 /* TODO -- Dynamically allocate work space to accomodate stack-poor archs? */
1440 static int _do_one_spec(FILE * __restrict stream,
1441                                                  register ppfs_t *ppfs, int *count)
1442 {
1443         static const char spec_base[] = SPEC_BASE;
1444 #ifdef L__vfprintf_internal
1445         static const char prefix[] = "+\0-\0 \0000x\0000X";
1446         /*                            0  2  4  6   9 11*/
1447 #else  /* L__vfprintf_internal */
1448         static const wchar_t prefix[] = L"+\0-\0 \0000x\0000X";
1449 #endif /* L__vfprintf_internal */
1450         enum {
1451                 PREFIX_PLUS = 0,
1452                 PREFIX_MINUS = 2,
1453                 PREFIX_SPACE = 4,
1454                 PREFIX_LWR_X = 6,
1455                 PREFIX_UPR_X = 9,
1456                 PREFIX_NONE = 11
1457         };
1458
1459 #ifdef __va_arg_ptr
1460         const void * const *argptr;
1461 #else
1462         const void * argptr[MAX_ARGS_PER_SPEC];
1463 #endif
1464         int *argtype;
1465 #ifdef __UCLIBC_HAS_WCHAR__
1466         const wchar_t *ws = NULL;
1467         mbstate_t mbstate;
1468 #endif /* __UCLIBC_HAS_WCHAR__ */
1469         size_t slen;
1470 #ifdef L__vfprintf_internal
1471 #define SLEN slen
1472 #else
1473         size_t SLEN;
1474         wchar_t wbuf[2];
1475 #endif
1476         int base;
1477         int numpad;
1478         int alphacase;
1479         int numfill = 0;                        /* TODO: fix */
1480         int prefix_num = PREFIX_NONE;
1481         char padchar = ' ';
1482 #ifdef __UCLIBC_MJN3_ONLY__
1483 #warning TODO: Determine appropriate buf size.
1484 #endif /* __UCLIBC_MJN3_ONLY__ */
1485         /* TODO: buf needs to be big enough for any possible error return strings
1486          * and also for any locale-grouped long long integer strings generated.
1487          * This should be large enough for any of the current archs/locales, but
1488          * eventually this should be handled robustly. */
1489         char buf[128];
1490
1491 #ifdef NDEBUG
1492         _ppfs_parsespec(ppfs);
1493 #else
1494         if (_ppfs_parsespec(ppfs) < 0) { /* TODO: just for debugging */
1495                 abort();
1496         }
1497 #endif
1498         _ppfs_setargs(ppfs);
1499
1500         argtype = ppfs->argtype + ppfs->argnumber[2] - 1;
1501         /* Deal with the argptr vs argvalue issue. */
1502 #ifdef __va_arg_ptr
1503         argptr = (const void * const *) ppfs->argptr;
1504 #ifdef NL_ARGMAX
1505         if (ppfs->maxposarg > 0) {      /* Using positional args... */
1506                 argptr += ppfs->argnumber[2] - 1;
1507         }
1508 #endif /* NL_ARGMAX */
1509 #else
1510         /* Need to build a local copy... */
1511         {
1512                 register argvalue_t *p = ppfs->argvalue;
1513                 int i;
1514 #ifdef NL_ARGMAX
1515                 if (ppfs->maxposarg > 0) {      /* Using positional args... */
1516                         p += ppfs->argnumber[2] - 1;
1517                 }
1518 #endif /* NL_ARGMAX */
1519                 for (i = 0 ; i < ppfs->num_data_args ; i++ ) {
1520                         argptr[i] = (void *) p++;
1521                 }
1522         }
1523 #endif
1524         {
1525                 register char *s = NULL; /* TODO: Should s be unsigned char * ? */
1526
1527                 if (ppfs->conv_num == CONV_n) {
1528                         _store_inttype(*(void **)*argptr,
1529                                                    ppfs->info._flags & __PA_INTMASK,
1530                                                    (intmax_t) (*count));
1531                         return 0;
1532                 }
1533                 if (ppfs->conv_num <= CONV_i) { /* pointer or (un)signed int */
1534                         alphacase = __UIM_LOWER;
1535
1536 #ifdef __UCLIBC_MJN3_ONLY__
1537 #ifdef L__vfprintf_internal
1538 #warning CONSIDER: Should we ignore these flags if stub locale?  What about custom specs?
1539 #endif
1540 #endif /* __UCLIBC_MJN3_ONLY__ */
1541                         if ((base = spec_base[(int)(ppfs->conv_num - CONV_p)]) == 10) {
1542                                 if (PRINT_INFO_FLAG_VAL(&(ppfs->info),group)) {
1543                                         alphacase = __UIM_GROUP;
1544                                 }
1545                                 if (PRINT_INFO_FLAG_VAL(&(ppfs->info),i18n)) {
1546                                         alphacase |= 0x80;
1547                                 }
1548                         }
1549
1550                         if (ppfs->conv_num <= CONV_u) { /* pointer or unsigned int */
1551                                 if (ppfs->conv_num == CONV_X) {
1552                                         alphacase = __UIM_UPPER;
1553                                 }
1554                                 if (ppfs->conv_num == CONV_p) { /* pointer */
1555                                         prefix_num = PREFIX_LWR_X;
1556                                 } else {                /* unsigned int */
1557                                 }
1558                         } else {                        /* signed int */
1559                                 base = -base;
1560                         }
1561                         if (ppfs->info.prec < 0) { /* Ignore '0' flag if prec specified. */
1562                                 padchar = ppfs->info.pad;
1563                         }
1564 #ifdef __UCLIBC_MJN3_ONLY__
1565 #ifdef L__vfprintf_internal
1566 #warning CONSIDER: If using outdigits and/or grouping, how should we interpret precision?
1567 #endif
1568 #endif /* __UCLIBC_MJN3_ONLY__ */
1569                         s = _uintmaxtostr(buf + sizeof(buf) - 1,
1570                                                           (uintmax_t)
1571                                                           _load_inttype(ppfs->conv_num == CONV_p ? PA_FLAG_LONG : *argtype & __PA_INTMASK,
1572                                                                                         *argptr, base), base, alphacase);
1573                         if (ppfs->conv_num > CONV_u) { /* signed int */
1574                                 if (*s == '-') {
1575                                         PRINT_INFO_SET_FLAG(&(ppfs->info),showsign);
1576                                         ++s;            /* handle '-' in the prefix string */
1577                                         prefix_num = PREFIX_MINUS;
1578                                 } else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),showsign)) {
1579                                         prefix_num = PREFIX_PLUS;
1580                                 } else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),space)) {
1581                                         prefix_num = PREFIX_SPACE;
1582                                 }
1583                         }
1584                         slen = (char *)(buf + sizeof(buf) - 1) - s;
1585 #ifdef L__vfwprintf_internal
1586                         {
1587                                 const char *q = s;
1588                                 mbstate.__mask = 0; /* Initialize the mbstate. */
1589                                 SLEN = mbsrtowcs(NULL, &q, 0, &mbstate);
1590                         }
1591 #endif
1592                         numfill = ((ppfs->info.prec < 0) ? 1 : ppfs->info.prec);
1593                         if (PRINT_INFO_FLAG_VAL(&(ppfs->info),alt)) {
1594                                 if (ppfs->conv_num <= CONV_x) { /* x or p */
1595                                         prefix_num = PREFIX_LWR_X;
1596                                 }
1597                                 if (ppfs->conv_num == CONV_X) {
1598                                         prefix_num = PREFIX_UPR_X;
1599                                 }
1600                                 if ((ppfs->conv_num == CONV_o) && (numfill <= SLEN)) {
1601                                         numfill = ((*s == '0') ? 1 : SLEN + 1);
1602                                 }
1603                         }
1604                         if (*s == '0') {
1605                                 if (prefix_num >= PREFIX_LWR_X) {
1606                                         prefix_num = PREFIX_NONE;
1607                                 }
1608                                 if (ppfs->conv_num == CONV_p) {/* null pointer */
1609                                         s = "(nil)";
1610 #ifdef L__vfwprintf_internal
1611                                         SLEN =
1612 #endif
1613                                         slen = 5;
1614                                         numfill = 0;
1615                                 } else if (numfill == 0) {      /* if precision 0, no output */
1616 #ifdef L__vfwprintf_internal
1617                                         SLEN =
1618 #endif
1619                                         slen = 0;
1620                                 }
1621                         }
1622                         numfill = ((numfill > SLEN) ? numfill - SLEN : 0);
1623                 } else if (ppfs->conv_num <= CONV_A) {  /* floating point */
1624 #ifdef __STDIO_PRINTF_FLOAT
1625                         ssize_t nf;
1626                         nf = _fpmaxtostr(stream,
1627                                                          (__fpmax_t)
1628                                                          (PRINT_INFO_FLAG_VAL(&(ppfs->info),is_long_double)
1629                                                           ? *(long double *) *argptr
1630                                                           : (long double) (* (double *) *argptr)),
1631                                                          &ppfs->info, FP_OUT );
1632                         if (nf < 0) {
1633                                 return -1;
1634                         }
1635                         *count += nf;
1636
1637                         return 0;
1638 #else  /* __STDIO_PRINTF_FLOAT */
1639                         return -1;                      /* TODO -- try to continue? */
1640 #endif /* __STDIO_PRINTF_FLOAT */
1641                 } else if (ppfs->conv_num <= CONV_S) {  /* wide char or string */
1642 #ifdef L__vfprintf_internal
1643
1644 #ifdef __UCLIBC_HAS_WCHAR__
1645                         mbstate.__mask = 0;     /* Initialize the mbstate. */
1646                         if (ppfs->conv_num == CONV_S) { /* wide string */
1647                                 if (!(ws = *((const wchar_t **) *argptr))) {
1648                                         goto NULL_STRING;
1649                                 }
1650                                 /* We use an awful uClibc-specific hack here, passing
1651                                  * (char*) &ws as the conversion destination.  This signals
1652                                  * uClibc's wcsrtombs that we want a "restricted" length
1653                                  * such that the mbs fits in a buffer of the specified
1654                                  * size with no partial conversions. */
1655                                 if ((slen = wcsrtombs((char *) &ws, &ws, /* Use awful hack! */
1656                                                                           ((ppfs->info.prec >= 0)
1657                                                                            ? ppfs->info.prec
1658                                                                            : SIZE_MAX), &mbstate))
1659                                         == ((size_t)-1)
1660                                         ) {
1661                                         return -1;      /* EILSEQ */
1662                                 }
1663                         } else {                        /* wide char */
1664                                 s = buf;
1665                                 slen = wcrtomb(s, (*((const wchar_t *) *argptr)), &mbstate);
1666                                 if (slen == ((size_t)-1)) {
1667                                         return -1;      /* EILSEQ */
1668                                 }
1669                                 s[slen] = 0;    /* TODO - Is this necessary? */
1670                         }
1671 #else  /* __UCLIBC_HAS_WCHAR__ */
1672                         return -1;
1673 #endif /* __UCLIBC_HAS_WCHAR__ */
1674                 } else if (ppfs->conv_num <= CONV_s) {  /* char or string */
1675                         if (ppfs->conv_num == CONV_s) { /* string */
1676                                 s = *((char **) (*argptr));
1677                                 if (s) {
1678 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1679                                 SET_STRING_LEN:
1680 #endif
1681                                         slen = strnlen(s, ((ppfs->info.prec >= 0)
1682                                                                            ? ppfs->info.prec : SIZE_MAX));
1683                                 } else {
1684 #ifdef __UCLIBC_HAS_WCHAR__
1685                                 NULL_STRING:
1686 #endif
1687                                         s = "(null)";
1688                                         slen = 6;
1689                                 }
1690                         } else {                        /* char */
1691                                 s = buf;
1692                                 *s = (unsigned char)(*((const int *) *argptr));
1693                                 s[1] = 0;
1694                                 slen = 1;
1695                         }
1696
1697 #else  /* L__vfprintf_internal */
1698
1699                         if (ppfs->conv_num == CONV_S) { /* wide string */
1700                                 ws = *((wchar_t **) (*argptr));
1701                                 if (!ws) {
1702                                         goto NULL_STRING;
1703                                 }
1704                                 SLEN = wcsnlen(ws, ((ppfs->info.prec >= 0)
1705                                                                         ? ppfs->info.prec : SIZE_MAX));
1706                         } else {                        /* wide char */
1707                                 *wbuf = (wchar_t)(*((const wint_t *) *argptr));
1708                         CHAR_CASE:
1709                                 ws = wbuf;
1710                                 wbuf[1] = 0;
1711                                 SLEN = 1;
1712                         }
1713
1714                 } else if (ppfs->conv_num <= CONV_s) {  /* char or string */
1715
1716                         if (ppfs->conv_num == CONV_s) { /* string */
1717 #ifdef __UCLIBC_MJN3_ONLY__
1718 #warning TODO: Fix %s for _vfwprintf_internal... output upto illegal sequence?
1719 #endif /* __UCLIBC_MJN3_ONLY__ */
1720                                 s = *((char **) (*argptr));
1721                                 if (s) {
1722 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1723                                 SET_STRING_LEN:
1724 #endif
1725                                         /* We use an awful uClibc-specific hack here, passing
1726                                          * (wchar_t*) &mbstate as the conversion destination.
1727                                          *  This signals uClibc's mbsrtowcs that we want a
1728                                          * "restricted" length such that the mbs fits in a buffer
1729                                          * of the specified size with no partial conversions. */
1730                                         {
1731                                                 const char *q = s;
1732                                                 mbstate.__mask = 0;     /* Initialize the mbstate. */
1733                                                 SLEN = mbsrtowcs((wchar_t *) &mbstate, &q,
1734                                                                                  ((ppfs->info.prec >= 0)
1735                                                                                   ? ppfs->info.prec : SIZE_MAX),
1736                                                                                  &mbstate);
1737                                         }
1738                                         if (SLEN == ((size_t)(-1))) {
1739                                                 return -1;      /* EILSEQ */
1740                                         }
1741                                 } else {
1742                                 NULL_STRING:
1743                                         s = "(null)";
1744                                         SLEN = slen = 6;
1745                                 }
1746                         } else {                        /* char */
1747                                 *wbuf = btowc( (unsigned char)(*((const int *) *argptr)) );
1748                                 goto CHAR_CASE;
1749                         }
1750
1751 #endif /* L__vfprintf_internal */
1752
1753 #ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
1754                 } else if (ppfs->conv_num == CONV_m) {
1755                         s = __glibc_strerror_r(errno, buf, sizeof(buf));
1756                         goto SET_STRING_LEN;
1757 #endif
1758                 } else {
1759 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
1760                         assert(ppfs->conv_num == CONV_custom0);
1761
1762                         s = _custom_printf_spec;
1763                         do {
1764                                 if (*s == ppfs->info.spec) {
1765                                         int rv;
1766                                         /* TODO -- check return value for sanity? */
1767                                         rv = (*_custom_printf_handler
1768                                                   [(int)(s-_custom_printf_spec)])
1769                                                 (stream, &ppfs->info, argptr);
1770                                         if (rv < 0) {
1771                                                 return -1;
1772                                         }
1773                                         *count += rv;
1774                                         return 0;
1775                                 }
1776                         } while (++s < (_custom_printf_spec + MAX_USER_SPEC));
1777 #endif /* __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ */
1778                         assert(0);
1779                         return -1;
1780                 }
1781
1782 #ifdef __UCLIBC_MJN3_ONLY__
1783 #ifdef L__vfprintf_internal
1784 #warning CONSIDER: If using outdigits and/or grouping, how should we pad?
1785 #endif
1786 #endif /* __UCLIBC_MJN3_ONLY__ */
1787                 {
1788                         size_t t;
1789
1790                         t = SLEN + numfill;
1791                         if (prefix_num != PREFIX_NONE) {
1792                                 t += ((prefix_num < PREFIX_LWR_X) ? 1 : 2);
1793                         }
1794                         numpad = ((ppfs->info.width > t) ? (ppfs->info.width - t) : 0);
1795                         *count += t + numpad;
1796                 }
1797                 if (padchar == '0') { /* TODO: check this */
1798                         numfill += numpad;
1799                         numpad = 0;
1800                 }
1801
1802                 /* Now handle the output itself. */
1803                 if (!PRINT_INFO_FLAG_VAL(&(ppfs->info),left)) {
1804                         if (_charpad(stream, ' ', numpad) != numpad) {
1805                                 return -1;
1806                         }
1807                         numpad = 0;
1808                 }
1809                 OUTPUT(stream, prefix + prefix_num);
1810
1811                 if (_charpad(stream, '0', numfill) != numfill) {
1812                         return -1;
1813                 }
1814
1815 #ifdef L__vfprintf_internal
1816
1817 #ifdef __UCLIBC_HAS_WCHAR__
1818                 if (!ws) {
1819                         assert(s);
1820                         if (_outnstr(stream, s, slen) != slen) {
1821                                 return -1;
1822                         }
1823                 } else {                                /* wide string */
1824                         size_t t;
1825                         mbstate.__mask = 0;     /* Initialize the mbstate. */
1826                         while (slen) {
1827                                 t = (slen <= sizeof(buf)) ? slen : sizeof(buf);
1828                                 t = wcsrtombs(buf, &ws, t, &mbstate);
1829                                 assert (t != ((size_t)(-1)));
1830                                 if (_outnstr(stream, buf, t) != t) {
1831                                         return -1;
1832                                 }
1833                                 slen -= t;
1834                         }
1835                 }
1836 #else  /* __UCLIBC_HAS_WCHAR__ */
1837                 if (_outnstr(stream, (const unsigned char *) s, slen) != slen) {
1838                         return -1;
1839                 }
1840 #endif /* __UCLIBC_HAS_WCHAR__ */
1841
1842 #else  /* L__vfprintf_internal */
1843
1844                 if (!ws) {
1845                         assert(s);
1846                         if (_outnstr(stream, s, SLEN) != SLEN) {
1847                                 return -1;
1848                         }
1849                 } else {
1850                         if (_outnwcs(stream, ws, SLEN) != SLEN) {
1851                                 return -1;
1852                         }
1853                 }
1854
1855 #endif /* L__vfprintf_internal */
1856                 if (_charpad(stream, ' ', numpad) != numpad) {
1857                         return -1;
1858                 }
1859         }
1860
1861         return 0;
1862 }
1863
1864 libc_hidden_proto(fprintf)
1865
1866 int VFPRINTF_internal (FILE * __restrict stream,
1867                           const FMT_TYPE * __restrict format,
1868                           va_list arg)
1869 {
1870         ppfs_t ppfs;
1871         int count, r;
1872         register const FMT_TYPE *s;
1873
1874         count = 0;
1875         s = format;
1876
1877         if (_PPFS_init(&ppfs, format) < 0) {    /* Bad format string. */
1878                 OUTNSTR(stream, (const unsigned char *) ppfs.fmtpos,
1879                                 STRLEN((const FMT_TYPE *)(ppfs.fmtpos)));
1880 #if defined(L__vfprintf_internal) && !defined(NDEBUG)
1881                 fprintf(stderr,"\nIMbS: \"%s\"\n\n", format);
1882 #endif
1883                 count = -1;
1884         } else {
1885                 _ppfs_prepargs(&ppfs, arg);     /* This did a va_copy!!! */
1886
1887                 do {
1888                         while (*format && (*format != '%')) {
1889                                 ++format;
1890                         }
1891
1892                         if (format-s) {         /* output any literal text in format string */
1893                                 if ( (r = OUTNSTR(stream, (const unsigned char *) s, format-s)) != (format-s)) {
1894                                         count = -1;
1895                                         break;
1896                                 }
1897                                 count += r;
1898                         }
1899
1900                         if (!*format) {                 /* we're done */
1901                                 break;
1902                         }
1903                 
1904                         if (format[1] != '%') { /* if we get here, *format == '%' */
1905                                 /* TODO: _do_one_spec needs to know what the output funcs are!!! */
1906                                 ppfs.fmtpos = (const char *)(++format);
1907                                 /* TODO: check -- should only fail on stream error */
1908                                 if ( (r = _do_one_spec(stream, &ppfs, &count)) < 0) {
1909                                         count = -1;
1910                                         break;
1911                                 }
1912                                 s = format = (const FMT_TYPE *) ppfs.fmtpos;
1913                         } else {                        /* %% means literal %, so start new string */
1914                                 s = ++format;
1915                                 ++format;
1916                         }
1917                 } while (1);
1918
1919                 va_end(ppfs.arg);               /* Need to clean up after va_copy! */
1920         }
1921
1922 /* #if defined(L__vfprintf_internal) && defined(__UCLIBC_HAS_WCHAR__) */
1923 /*  DONE: */
1924 /* #endif */
1925
1926         return count;
1927 }
1928 #endif /* defined(L__vfprintf_internal) || defined(L__vfwprintf_internal) */
1929
1930
1931 /**********************************************************************/
1932 #if defined(L_vfprintf) || defined(L_vfwprintf)
1933
1934 /* This is just a wrapper around VFPRINTF_internal.
1935  * Factoring out vfprintf internals allows:
1936  * (1) vdprintf and vsnprintf don't need to setup fake locking,
1937  * (2) __STDIO_STREAM_TRANS_TO_WRITE is not used in vfprintf internals,
1938  * and thus fseek etc is not pulled in by vdprintf and vsnprintf.
1939  *
1940  * In order to not pull in fseek through fputs, OUTPUT() macro
1941  * is using __stdio_fwrite (TODO: do the same for wide functions).
1942  */
1943 #ifdef L_vfprintf
1944 #define VFPRINTF vfprintf
1945 #define VFPRINTF_internal _vfprintf_internal
1946 #define FMT_TYPE char
1947 #else
1948 #define VFPRINTF vfwprintf
1949 #define VFPRINTF_internal _vfwprintf_internal
1950 #define FMT_TYPE wchar_t
1951 #endif
1952
1953 libc_hidden_proto(VFPRINTF)
1954 int VFPRINTF (FILE * __restrict stream,
1955                           const FMT_TYPE * __restrict format,
1956                           va_list arg)
1957 {
1958         int count;
1959         __STDIO_AUTO_THREADLOCK_VAR;
1960
1961         __STDIO_AUTO_THREADLOCK(stream);
1962
1963         if 
1964 #ifdef L_vfprintf
1965         (!__STDIO_STREAM_IS_NARROW_WRITING(stream)
1966          && __STDIO_STREAM_TRANS_TO_WRITE(stream, __FLAG_NARROW))
1967 #else
1968         (!__STDIO_STREAM_IS_WIDE_WRITING(stream)
1969          && __STDIO_STREAM_TRANS_TO_WRITE(stream, __FLAG_WIDE))
1970 #endif
1971         {
1972                 count = -1;
1973         } else {
1974                 count = VFPRINTF_internal(stream, format, arg);
1975         }
1976
1977         __STDIO_AUTO_THREADUNLOCK(stream);
1978
1979         return count;
1980 }
1981 libc_hidden_def(VFPRINTF)
1982 #endif /* defined(L_vfprintf) || defined(L_vfwprintf) */
1983
1984 /**********************************************************************/