OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [uClibc/] [libc/] [stdio/] [printf.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1325 phoenix
/*  Copyright (C) 2002, 2003     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
 
92
#define _ISOC99_SOURCE                  /* for ULLONG primarily... */
93
#define _GNU_SOURCE
94
#define _STDIO_UTILITY                  /* We're using _uintmaxtostr. */
95
#include <stdio.h>
96
#include <stdlib.h>
97
#include <string.h>
98
#include <stddef.h>
99
#include <ctype.h>
100
#include <limits.h>
101
#include <stdarg.h>
102
#include <assert.h>
103
#include <stdint.h>
104
#include <errno.h>
105
#include <locale.h>
106
 
107
#define __PRINTF_INFO_NO_BITFIELD
108
#include <printf.h>
109
 
110
#ifdef __STDIO_THREADSAFE
111
#include <stdio_ext.h>
112
#include <pthread.h>
113
#endif /* __STDIO_THREADSAFE */
114
 
115
#ifdef __UCLIBC_HAS_WCHAR__
116
#include <wchar.h>
117
#endif /* __UCLIBC_HAS_WCHAR__ */
118
 
119
/* Some older or broken gcc toolchains define LONG_LONG_MAX but not
120
 * LLONG_MAX.  Since LLONG_MAX is part of the standard, that's what
121
 * we use.  So complain if we do not have it but should.
122
 */
123
#if !defined(LLONG_MAX) && defined(LONG_LONG_MAX)
124
#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.
125
#endif
126
 
127
/**********************************************************************/
128
/* These provide some control over printf's feature set */
129
 
130
/* This is undefined below depeding on uClibc's configuration. */
131
#define __STDIO_PRINTF_FLOAT 1
132
 
133
/* Now controlled by uClibc_stdio.h. */
134
/* #define __STDIO_PRINTF_M_SUPPORT */
135
 
136
 
137
/**********************************************************************/
138
 
139
#if defined(__UCLIBC__) && !defined(__UCLIBC_HAS_FLOATS__)
140
#undef __STDIO_PRINTF_FLOAT
141
#endif
142
 
143
#ifdef __BCC__
144
#undef __STDIO_PRINTF_FLOAT
145
#endif
146
 
147
#ifdef __STDIO_PRINTF_FLOAT
148
#include <float.h>
149
#include <bits/uClibc_fpmax.h>
150
#else  /* __STDIO_PRINTF_FLOAT */
151
#undef L__fpmaxtostr
152
#endif /* __STDIO_PRINTF_FLOAT */
153
 
154
 
155
#undef __STDIO_HAS_VSNPRINTF
156
#if defined(__STDIO_BUFFERS) || defined(__USE_OLD_VFPRINTF__) || defined(__STDIO_GLIBC_CUSTOM_STREAMS)
157
#define __STDIO_HAS_VSNPRINTF 1
158
#endif
159
 
160
/**********************************************************************/
161
 
162
/* Now controlled by uClibc_stdio.h. */
163
/* #define __STDIO_GLIBC_CUSTOM_PRINTF */
164
 
165
/* TODO -- move these to a configuration section? */
166
#define MAX_FIELD_WIDTH         4095
167
 
168
#ifdef __UCLIBC_MJN3_ONLY__
169
#ifdef L_register_printf_function
170
/* emit only once */
171
#warning WISHLIST: Make MAX_USER_SPEC configurable?
172
#warning WISHLIST: Make MAX_ARGS_PER_SPEC configurable?
173
#endif
174
#endif /* __UCLIBC_MJN3_ONLY__ */
175
 
176
#ifdef __STDIO_GLIBC_CUSTOM_PRINTF
177
 
178
#define MAX_USER_SPEC       10
179
#define MAX_ARGS_PER_SPEC    5
180
 
181
#else  /* __STDIO_GLIBC_CUSTOM_PRINTF */
182
 
183
#undef MAX_USER_SPEC
184
#define MAX_ARGS_PER_SPEC    1
185
 
186
#endif /* __STDIO_GLIBC_CUSTOM_PRINTF */
187
 
188
#if MAX_ARGS_PER_SPEC < 1
189
#error MAX_ARGS_PER_SPEC < 1!
190
#undef MAX_ARGS_PER_SPEC
191
#define MAX_ARGS_PER_SPEC    1
192
#endif
193
 
194
#if defined(NL_ARGMAX) && (NL_ARGMAX < 9)
195
#error NL_ARGMAX < 9!
196
#endif
197
 
198
#if defined(NL_ARGMAX) && (NL_ARGMAX >= (MAX_ARGS_PER_SPEC + 2))
199
#define MAX_ARGS        NL_ARGMAX
200
#else
201
/* N for spec itself, plus 1 each for width and precision */
202
#define MAX_ARGS        (MAX_ARGS_PER_SPEC + 2)
203
#endif
204
 
205
 
206
/**********************************************************************/
207
/* Deal with pre-C99 compilers. */
208
 
209
#ifndef va_copy
210
 
211
#ifdef __va_copy
212
#define va_copy(A,B)    __va_copy(A,B)
213
#else
214
        /* TODO -- maybe create a bits/vacopy.h for arch specific versions
215
         * to ensure we get the right behavior?  Either that or fall back
216
         * on the portable (but costly in size) method of using a va_list *.
217
         * That means a pointer derefs in the va_arg() invocations... */
218
#warning Neither va_copy (C99/SUSv3) or __va_copy is defined.  Using a simple copy instead.  But you should really check that this is appropriate...
219
        /* the glibc manual suggests that this will usually suffice when
220
        __va_copy doesn't exist.  */
221
#define va_copy(A,B)    A = B
222
#endif
223
 
224
#endif /* va_copy */
225
 
226
/**********************************************************************/
227
 
228
#define __PA_FLAG_INTMASK \
229
        (__PA_FLAG_CHAR|PA_FLAG_SHORT|__PA_FLAG_INT|PA_FLAG_LONG|PA_FLAG_LONG_LONG)
230
 
231
#ifdef __STDIO_GLIBC_CUSTOM_PRINTF
232
extern printf_function _custom_printf_handler[MAX_USER_SPEC];
233
extern printf_arginfo_function *_custom_printf_arginfo[MAX_USER_SPEC];
234
extern char *_custom_printf_spec;
235
#endif /* __STDIO_GLIBC_CUSTOM_PRINTF */
236
 
237
/**********************************************************************/
238
 
239
#define SPEC_FLAGS              " +0-#'I"
240
enum {
241
        FLAG_SPACE              =       0x01,
242
        FLAG_PLUS               =       0x02,   /* must be 2 * FLAG_SPACE */
243
        FLAG_ZERO               =       0x04,
244
        FLAG_MINUS              =       0x08,   /* must be 2 * FLAG_ZERO */
245
        FLAG_HASH               =       0x10,
246
        FLAG_THOUSANDS  =       0x20,
247
        FLAG_I18N               =       0x40,   /* only works for d, i, u */
248
        FLAG_WIDESTREAM =   0x80
249
};
250
 
251
/**********************************************************************/
252
 
253
/* float layout          01234567890123456789   TODO: B?*/
254
#define SPEC_CHARS              "npxXoudifFeEgGaACScs"
255
enum {
256
        CONV_n = 0,
257
        CONV_p,
258
        CONV_x, CONV_X, CONV_o, CONV_u, CONV_d, CONV_i,
259
        CONV_f, CONV_F, CONV_e, CONV_E, CONV_g, CONV_G, CONV_a, CONV_A,
260
        CONV_C, CONV_S, CONV_c, CONV_s,
261
#ifdef __STDIO_PRINTF_M_SUPPORT
262
        CONV_m,
263
#endif
264
        CONV_custom0                            /* must be last */
265
};
266
 
267
/*                         p   x   X  o   u   d   i */
268
#define SPEC_BASE               { 16, 16, 16, 8, 10, 10, 10 }
269
 
270
#define SPEC_RANGES             { CONV_n, CONV_p, CONV_i, CONV_A, \
271
                                                  CONV_C, CONV_S, CONV_c, CONV_s, CONV_custom0 }
272
 
273
#define SPEC_OR_MASK             { \
274
        /* n */                 (PA_FLAG_PTR|PA_INT), \
275
        /* p */                 PA_POINTER, \
276
        /* oxXudi */    PA_INT, \
277
        /* fFeEgGaA */  PA_DOUBLE, \
278
        /* C */                 PA_WCHAR, \
279
        /* S */                 PA_WSTRING, \
280
        /* c */                 PA_CHAR, \
281
        /* s */                 PA_STRING, \
282
}
283
 
284
#define SPEC_AND_MASK           { \
285
        /* n */                 (PA_FLAG_PTR|__PA_INTMASK), \
286
        /* p */                 PA_POINTER, \
287
        /* oxXudi */    (__PA_INTMASK), \
288
        /* fFeEgGaA */  (PA_FLAG_LONG_DOUBLE|PA_DOUBLE), \
289
        /* C */                 (PA_WCHAR), \
290
        /* S */                 (PA_WSTRING), \
291
        /* c */                 (PA_CHAR), \
292
        /* s */                 (PA_STRING), \
293
}
294
 
295
/**********************************************************************/
296
/*
297
 * In order to ease translation to what arginfo and _print_info._flags expect,
298
 * we map:  0:int  1:char  2:longlong 4:long  8:short
299
 * and then _flags |= (((q << 7) + q) & 0x701) and argtype |= (_flags & 0x701)
300
 */
301
 
302
/* TODO -- Fix the table below to take into account stdint.h. */
303
/*  #ifndef LLONG_MAX */
304
/*  #error fix QUAL_CHARS for no long long!  Affects 'L', 'j', 'q', 'll'. */
305
/*  #else */
306
/*  #if LLONG_MAX != INTMAX_MAX */
307
/*  #error fix QUAL_CHARS intmax_t entry 'j'! */
308
/*  #endif */
309
/*  #endif */
310
 
311
#ifdef PDS
312
#error PDS already defined!
313
#endif
314
#ifdef SS
315
#error SS already defined!
316
#endif
317
#ifdef IMS
318
#error IMS already defined!
319
#endif
320
 
321
#if PTRDIFF_MAX == INT_MAX
322
#define PDS             0
323
#elif PTRDIFF_MAX == LONG_MAX
324
#define PDS             4
325
#elif defined(LLONG_MAX) && (PTRDIFF_MAX == LLONG_MAX)
326
#define PDS             8
327
#else
328
#error fix QUAL_CHARS ptrdiff_t entry 't'!
329
#endif
330
 
331
#if SIZE_MAX == UINT_MAX
332
#define SS              0
333
#elif SIZE_MAX == ULONG_MAX
334
#define SS              4
335
#elif defined(LLONG_MAX) && (SIZE_MAX == ULLONG_MAX)
336
#define SS              8
337
#else
338
#error fix QUAL_CHARS size_t entries 'z', 'Z'!
339
#endif
340
 
341
#if INTMAX_MAX == INT_MAX
342
#define IMS             0
343
#elif INTMAX_MAX == LONG_MAX
344
#define IMS             4
345
#elif defined(LLONG_MAX) && (INTMAX_MAX == LLONG_MAX)
346
#define IMS             8
347
#else
348
#error fix QUAL_CHARS intmax_t entry 'j'!
349
#endif
350
 
351
#define QUAL_CHARS              { \
352
        /* j:(u)intmax_t z:(s)size_t  t:ptrdiff_t  \0:int */ \
353
        /* q:long_long  Z:(s)size_t */ \
354
        'h',   'l',  'L',  'j',  'z',  't',  'q', 'Z',  0, \
355
         2,     4,    8,  IMS,   SS,  PDS,    8,  SS,   0, /* TODO -- fix!!! */\
356
     1,     8 \
357
}
358
 
359
/**********************************************************************/
360
 
361
#ifdef __STDIO_VA_ARG_PTR
362
#ifdef __BCC__
363
#define __va_arg_ptr(ap,type)           (((type *)(ap += sizeof(type))) - 1)
364
#endif
365
 
366
#if 1
367
#ifdef __GNUC__
368
/* TODO -- need other than for 386 as well! */
369
 
370
#ifndef __va_rounded_size
371
#define __va_rounded_size(TYPE)  \
372
  (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
373
#endif
374
#define __va_arg_ptr(AP, TYPE)                                          \
375
 (AP = (va_list) ((char *) (AP) + __va_rounded_size (TYPE)),    \
376
  ((void *) ((char *) (AP) - __va_rounded_size (TYPE))))
377
#endif
378
#endif
379
#endif /* __STDIO_VA_ARG_PTR */
380
 
381
#ifdef __va_arg_ptr
382
#define GET_VA_ARG(AP,F,TYPE,ARGS)      (*(AP) = __va_arg_ptr(ARGS,TYPE))
383
#define GET_ARG_VALUE(AP,F,TYPE)        (*((TYPE *)(*(AP))))
384
#else
385
typedef union {
386
        wchar_t wc;
387
        unsigned int u;
388
        unsigned long ul;
389
#ifdef ULLONG_MAX
390
        unsigned long long ull;
391
#endif
392
#ifdef __STDIO_PRINTF_FLOAT
393
        double d;
394
        long double ld;
395
#endif /* __STDIO_PRINTF_FLOAT */
396
        void *p;
397
} argvalue_t;
398
 
399
#define GET_VA_ARG(AU,F,TYPE,ARGS)      (AU->F = va_arg(ARGS,TYPE))
400
#define GET_ARG_VALUE(AU,F,TYPE)        ((TYPE)((AU)->F))
401
#endif
402
 
403
typedef struct {
404
        const char *fmtpos;                     /* TODO: move below struct?? */
405
        struct printf_info info;
406
#ifdef NL_ARGMAX
407
        int maxposarg;                          /* > 0 if args are positional, 0 if not, -1 if unknown */
408
#endif /* NL_ARGMAX */
409
        int num_data_args;                      /* TODO: use sentinal??? */
410
        unsigned int conv_num;
411
        unsigned char argnumber[4]; /* width | prec | 1st data | unused */
412
        int argtype[MAX_ARGS];
413
        va_list arg;
414
#ifdef __va_arg_ptr
415
        void *argptr[MAX_ARGS];
416
#else
417
/* if defined(NL_ARGMAX) || defined(__STDIO_GLIBC_CUSTOM_PRINTF) */
418
        /* While this is wasteful of space in the case where pos args aren't
419
         * enabled, it is also needed to support custom printf handlers. */
420
        argvalue_t argvalue[MAX_ARGS];
421
#endif
422
} ppfs_t;                                               /* parse printf format state */
423
 
424
/**********************************************************************/
425
 
426
/* TODO: fix printf to return 0 and set errno if format error.  Standard says
427
   only returns -1 if sets error indicator for the stream. */
428
 
429
#ifdef __STDIO_PRINTF_FLOAT
430
typedef void (__fp_outfunc_t)(FILE *fp, intptr_t type, intptr_t len,
431
                                                          intptr_t buf);
432
 
433
extern size_t _fpmaxtostr(FILE * fp, __fpmax_t x, struct printf_info *info,
434
                                                  __fp_outfunc_t fp_outfunc);
435
#endif
436
 
437
extern int _ppfs_init(ppfs_t *ppfs, const char *fmt0); /* validates */
438
extern void _ppfs_prepargs(ppfs_t *ppfs, va_list arg); /* sets posargptrs */
439
extern void _ppfs_setargs(ppfs_t *ppfs); /* sets argptrs for current spec */
440
extern int _ppfs_parsespec(ppfs_t *ppfs); /* parses specifier */
441
 
442
extern void _store_inttype(void *dest, int desttype, uintmax_t val);
443
extern uintmax_t _load_inttype(int desttype, const void *src, int uflag);
444
 
445
/**********************************************************************/
446
#ifdef L_parse_printf_format
447
 
448
/* NOTE: This function differs from the glibc version in that parsing stops
449
 * upon encountering an invalid conversion specifier.  Since this is the way
450
 * my printf functions work, I think it makes sense to do it that way here.
451
 * Unfortunately, since glibc sets the return type as size_t, we have no way
452
 * of returning that the template is illegal, other than returning 0.
453
 */
454
 
455
size_t parse_printf_format(register const char *template,
456
                                                   size_t n, register int *argtypes)
457
{
458
        ppfs_t ppfs;
459
        size_t i;
460
        size_t count = 0;
461
 
462
        if (_ppfs_init(&ppfs, template) >= 0) {
463
#ifdef NL_ARGMAX
464
                if (ppfs.maxposarg > 0)  { /* Using positional args. */
465
                        count = ppfs.maxposarg;
466
                        if (n > count) {
467
                                n = count;
468
                        }
469
                        for (i = 0 ; i < n ; i++) {
470
                                *argtypes++ = ppfs.argtype[i];
471
                        }
472
                } else {                                /* Not using positional args. */
473
#endif /* NL_ARGMAX */
474
                        while (*template) {
475
                                if ((*template == '%') && (*++template != '%')) {
476
                                        ppfs.fmtpos = template;
477
                                        _ppfs_parsespec(&ppfs); /* Can't fail. */
478
                                        template = ppfs.fmtpos; /* Update to one past spec end. */
479
                                        if (ppfs.info.width == INT_MIN) {
480
                                                ++count;
481
                                                if (n > 0) {
482
                                                        *argtypes++ = PA_INT;
483
                                                        --n;
484
                                                }
485
                                        }
486
                                        if (ppfs.info.prec == INT_MIN) {
487
                                                ++count;
488
                                                if (n > 0) {
489
                                                        *argtypes++ = PA_INT;
490
                                                        --n;
491
                                                }
492
                                        }
493
                                        for (i = 0 ; i < ppfs.num_data_args ; i++) {
494
                                                if ((ppfs.argtype[i]) != __PA_NOARG) {
495
                                                        ++count;
496
                                                        if (n > 0) {
497
                                                                *argtypes++ = ppfs.argtype[i];
498
                                                                --n;
499
                                                        }
500
                                                }
501
                                        }
502
                                } else {
503
                                        ++template;
504
                                }
505
                        }
506
#ifdef NL_ARGMAX
507
                }
508
#endif /* NL_ARGMAX */
509
        }
510
 
511
        return count;
512
}
513
 
514
#endif
515
/**********************************************************************/
516
#ifdef L__ppfs_init
517
 
518
int _ppfs_init(register ppfs_t *ppfs, const char *fmt0)
519
{
520
        int r;
521
 
522
        /* First, zero out everything... argnumber[], argtype[], argptr[] */
523
        memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */
524
#ifdef NL_ARGMAX
525
        --ppfs->maxposarg;                      /* set to -1 */
526
#endif /* NL_ARGMAX */
527
        ppfs->fmtpos = fmt0;
528
#ifdef __UCLIBC_MJN3_ONLY__
529
#warning TODO: Make checking of the format string in C locale an option.
530
#endif
531
#ifdef __UCLIBC_HAS_LOCALE__
532
        /* To support old programs, don't check mb validity if in C locale. */
533
        if (((__UCLIBC_CURLOCALE_DATA).encoding) != __ctype_encoding_7_bit) {
534
                /* ANSI/ISO C99 requires format string to be a valid multibyte string
535
                 * beginning and ending in its initial shift state. */
536
                static const char invalid_mbs[] = "Invalid multibyte format string.";
537
                mbstate_t mbstate;
538
                const char *p;
539
                mbstate.mask = 0;        /* Initialize the mbstate. */
540
                p = fmt0;
541
                if (mbsrtowcs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) {
542
                        ppfs->fmtpos = invalid_mbs;
543
                        return -1;
544
                }
545
        }
546
#endif /* __UCLIBC_HAS_LOCALE__ */
547
        /* now set all argtypes to no-arg */
548
        {
549
#if 1
550
                /* TODO - use memset here since already "paid for"? */
551
                register int *p = ppfs->argtype;
552
 
553
                r = MAX_ARGS;
554
                do {
555
                        *p++ = __PA_NOARG;
556
                } while (--r);
557
#else
558
                /* TODO -- get rid of this?? */
559
                register char *p = (char *) ((MAX_ARGS-1) * sizeof(int));
560
 
561
                do {
562
                        *((int *)(((char *)ppfs) + ((int)p) + offsetof(ppfs_t,argtype))) = __PA_NOARG;
563
                        p -= sizeof(int);
564
                } while (p);
565
#endif
566
        }
567
 
568
        /*
569
         * Run through the entire format string to validate it and initialize
570
         * the positional arg numbers (if any).
571
         */
572
        {
573
                register const char *fmt = fmt0;
574
 
575
                while (*fmt) {
576
                        if ((*fmt == '%') && (*++fmt != '%')) {
577
                                ppfs->fmtpos = fmt; /* back up to the '%' */
578
                                if ((r = _ppfs_parsespec(ppfs)) < 0) {
579
                                        return -1;
580
                                }
581
                                fmt = ppfs->fmtpos;     /* update to one past end of spec */
582
                        } else {
583
                                ++fmt;
584
                        }
585
                }
586
                ppfs->fmtpos = fmt0;            /* rewind */
587
        }
588
 
589
#ifdef NL_MAX_ARG
590
        /* If we have positional args, make sure we know all the types. */
591
        {
592
                register int *p = ppfs->argtype;
593
                r = ppfs->maxposarg;
594
                while (--r >= 0) {
595
                        if ( *p == __PA_NOARG ) { /* missing arg type!!! */
596
                                return -1;
597
                        }
598
                        ++p;
599
                }
600
        }
601
#endif /* NL_MAX_ARG */
602
 
603
        return 0;
604
}
605
#endif
606
/**********************************************************************/
607
#ifdef L__ppfs_prepargs
608
void _ppfs_prepargs(register ppfs_t *ppfs, va_list arg)
609
{
610
        int i;
611
 
612
        va_copy(ppfs->arg, arg);
613
 
614
#ifdef NL_ARGMAX
615
        if ((i = ppfs->maxposarg) > 0)  { /* init for positional args */
616
                ppfs->num_data_args = i;
617
                ppfs->info.width = ppfs->info.prec = ppfs->maxposarg = 0;
618
                _ppfs_setargs(ppfs);
619
                ppfs->maxposarg = i;
620
        }
621
#endif /* NL_ARGMAX */
622
}
623
#endif
624
/**********************************************************************/
625
#ifdef L__ppfs_setargs
626
 
627
void _ppfs_setargs(register ppfs_t *ppfs)
628
{
629
#ifdef __va_arg_ptr
630
        register void **p = ppfs->argptr;
631
#else
632
        register argvalue_t *p = ppfs->argvalue;
633
#endif
634
        int i;
635
 
636
#ifdef NL_ARGMAX
637
        if (ppfs->maxposarg == 0) {      /* initing for or no pos args */
638
#endif /* NL_ARGMAX */
639
                if (ppfs->info.width == INT_MIN) {
640
                        ppfs->info.width =
641
#ifdef __va_arg_ptr
642
                                *(int *)
643
#endif
644
                                GET_VA_ARG(p,u,unsigned int,ppfs->arg);
645
                }
646
                if (ppfs->info.prec == INT_MIN) {
647
                        ppfs->info.prec =
648
#ifdef __va_arg_ptr
649
                                *(int *)
650
#endif
651
                                GET_VA_ARG(p,u,unsigned int,ppfs->arg);
652
                }
653
                i = 0;
654
                while (i < ppfs->num_data_args) {
655
                        switch(ppfs->argtype[i++]) {
656
                                case (PA_INT|PA_FLAG_LONG_LONG):
657
#ifdef ULLONG_MAX
658
                                        GET_VA_ARG(p,ull,unsigned long long,ppfs->arg);
659
                                        break;
660
#endif
661
                                case (PA_INT|PA_FLAG_LONG):
662
#if ULONG_MAX != UINT_MAX
663
                                        GET_VA_ARG(p,ul,unsigned long,ppfs->arg);
664
                                        break;
665
#endif
666
                                case PA_CHAR:   /* TODO - be careful */
667
                                        /* ... users could use above and really want below!! */
668
                                case (PA_INT|__PA_FLAG_CHAR):/* TODO -- translate this!!! */
669
                                case (PA_INT|PA_FLAG_SHORT):
670
                                case PA_INT:
671
                                        GET_VA_ARG(p,u,unsigned int,ppfs->arg);
672
                                        break;
673
                                case PA_WCHAR:  /* TODO -- assume int? */
674
                                        /* we're assuming wchar_t is at least an int */
675
                                        GET_VA_ARG(p,wc,wchar_t,ppfs->arg);
676
                                        break;
677
#ifdef __STDIO_PRINTF_FLOAT
678
                                        /* PA_FLOAT */
679
                                case PA_DOUBLE:
680
                                        GET_VA_ARG(p,d,double,ppfs->arg);
681
                                        break;
682
                                case (PA_DOUBLE|PA_FLAG_LONG_DOUBLE):
683
                                        GET_VA_ARG(p,ld,long double,ppfs->arg);
684
                                        break;
685
#else  /* __STDIO_PRINTF_FLOAT */
686
                                case PA_DOUBLE:
687
                                case (PA_DOUBLE|PA_FLAG_LONG_DOUBLE):
688
                                        assert(0);
689
                                        continue;
690
#endif /* __STDIO_PRINTF_FLOAT */
691
                                default:
692
                                        /* TODO -- really need to ensure this can't happen */
693
                                        assert(ppfs->argtype[i-1] & PA_FLAG_PTR);
694
                                case PA_POINTER:
695
                                case PA_STRING:
696
                                case PA_WSTRING:
697
                                        GET_VA_ARG(p,p,void *,ppfs->arg);
698
                                        break;
699
                                case __PA_NOARG:
700
                                        continue;
701
                        }
702
                        ++p;
703
                }
704
#ifdef NL_ARGMAX
705
        } else {
706
                if (ppfs->info.width == INT_MIN) {
707
                        ppfs->info.width
708
                                = (int) GET_ARG_VALUE(p + ppfs->argnumber[0] - 1,u,unsigned int);
709
                }
710
                if (ppfs->info.prec == INT_MIN) {
711
                        ppfs->info.prec
712
                                = (int) GET_ARG_VALUE(p + ppfs->argnumber[1] - 1,u,unsigned int);
713
                }
714
        }
715
#endif /* NL_ARGMAX */
716
 
717
        /* Now we know the width and precision. */
718
        if (ppfs->info.width < 0) {
719
                ppfs->info.width = -ppfs->info.width;
720
                PRINT_INFO_SET_FLAG(&(ppfs->info),left);
721
                PRINT_INFO_CLR_FLAG(&(ppfs->info),space);
722
                ppfs->info.pad = ' ';
723
        }
724
#if 0
725
        /* NOTE -- keep neg for now so float knows! */
726
        if (ppfs->info.prec < 0) {       /* spec says treat as omitted. */
727
                /* so use default prec... 1 for everything but floats and strings. */
728
                ppfs->info.prec = 1;
729
        }
730
#endif
731
}
732
#endif
733
/**********************************************************************/
734
#ifdef L__ppfs_parsespec
735
 
736
/* Notes: argtype differs from glibc for the following:
737
 *         mine              glibc
738
 *  lc     PA_WCHAR          PA_CHAR       the standard says %lc means %C
739
 *  ls     PA_WSTRING        PA_STRING     the standard says %ls means %S
740
 *  {*}n   {*}|PA_FLAG_PTR   PA_FLAG_PTR   size of n can be qualified
741
 */
742
 
743
/* TODO: store positions of positional args */
744
 
745
/* TODO -- WARNING -- assumes aligned on integer boundaries!!! */
746
 
747
/* TODO -- disable if not using positional args!!! */
748
#define _OVERLAPPING_DIFFERENT_ARGS
749
 
750
/* TODO -- rethink this -- perhaps we should set to largest type??? */
751
 
752
#ifdef _OVERLAPPING_DIFFERENT_ARGS 
753
 
754
#define PROMOTED_SIZE_OF(X)             ((sizeof(X) + sizeof(int) - 1) / sizeof(X))
755
 
756
static const short int type_codes[] = {
757
        __PA_NOARG,                                     /* must be first entry */
758
        PA_POINTER,
759
        PA_STRING,
760
        PA_WSTRING,
761
        PA_CHAR,
762
        PA_INT|PA_FLAG_SHORT,
763
        PA_INT,
764
        PA_INT|PA_FLAG_LONG,
765
        PA_INT|PA_FLAG_LONG_LONG,
766
        PA_WCHAR,
767
#ifdef __STDIO_PRINTF_FLOAT
768
        /* PA_FLOAT, */
769
        PA_DOUBLE,
770
        PA_DOUBLE|PA_FLAG_LONG_DOUBLE,
771
#endif /* __STDIO_PRINTF_FLOAT */
772
};
773
 
774
static const unsigned char type_sizes[] = {
775
        /* unknown type consumes no arg */
776
        0,                                                       /* must be first entry */
777
        PROMOTED_SIZE_OF(void *),
778
        PROMOTED_SIZE_OF(char *),
779
        PROMOTED_SIZE_OF(wchar_t *),
780
        PROMOTED_SIZE_OF(char),
781
        PROMOTED_SIZE_OF(short),
782
        PROMOTED_SIZE_OF(int),
783
        PROMOTED_SIZE_OF(long),
784
#ifdef ULLONG_MAX
785
        PROMOTED_SIZE_OF(long long),
786
#else
787
        PROMOTED_SIZE_OF(long),         /* TODO -- is this correct? (above too) */
788
#endif
789
        PROMOTED_SIZE_OF(wchar_t),
790
#ifdef __STDIO_PRINTF_FLOAT
791
        /* PROMOTED_SIZE_OF(float), */
792
        PROMOTED_SIZE_OF(double),
793
        PROMOTED_SIZE_OF(long double),
794
#endif /* __STDIO_PRINTF_FLOAT */
795
};
796
 
797
static int _promoted_size(int argtype)
798
{
799
        register const short int *p;
800
 
801
        /* note -- since any unrecognized type is treated as a pointer */
802
        p = type_codes + sizeof(type_codes)/sizeof(type_codes[0]);
803
        do {
804
                if (*--p == argtype) {
805
                        break;
806
                }
807
        } while (p > type_codes);
808
 
809
        return type_sizes[(int)(p - type_codes)];
810
}
811
 
812
static int _is_equal_or_bigger_arg(int curtype, int newtype)
813
{
814
        /* Quick test */
815
        if (newtype == __PA_NOARG) {
816
                return 0;
817
        }
818
        if ((curtype == __PA_NOARG) || (curtype == newtype)) {
819
                return 1;
820
        }
821
        /* Ok... slot is already filled and types are different in name. */
822
        /* So, compare promoted sizes of curtype and newtype args. */
823
        return _promoted_size(curtype) <= _promoted_size(newtype);
824
}
825
 
826
#else
827
 
828
#define _is_equal_or_bigger_arg(C,N)    (((C) == __PA_NOARG) || ((C) == (N)))
829
 
830
#endif
831
 
832
#ifdef __STDIO_GLIBC_CUSTOM_PRINTF
833
/* TODO - do this differently? */
834
static char _bss_custom_printf_spec[MAX_USER_SPEC]; /* 0-init'd for us.  */
835
 
836
char *_custom_printf_spec = _bss_custom_printf_spec;
837
printf_arginfo_function *_custom_printf_arginfo[MAX_USER_SPEC];
838
printf_function _custom_printf_handler[MAX_USER_SPEC];
839
#endif /* __STDIO_GLIBC_CUSTOM_PRINTF */
840
 
841
extern int _ppfs_parsespec(ppfs_t *ppfs)
842
{
843
        register const char *fmt;
844
        register const char *p;
845
        int preci;
846
        int width;
847
        int flags;
848
        int dataargtype;
849
        int i;
850
        int dpoint;
851
#ifdef NL_ARGMAX
852
        int maxposarg;
853
#endif /* NL_ARGMAX */
854
        int p_m_spec_chars;
855
        int n;
856
        int argtype[MAX_ARGS_PER_SPEC+2];
857
        int argnumber[3];                       /* width, precision, 1st data arg */
858
        static const char spec_flags[] = SPEC_FLAGS;
859
        static const char spec_chars[] = SPEC_CHARS;/* TODO: b? */
860
        static const char spec_ranges[] = SPEC_RANGES;
861
        static const short spec_or_mask[] = SPEC_OR_MASK;
862
        static const short spec_and_mask[] = SPEC_AND_MASK;
863
        static const char qual_chars[] = QUAL_CHARS;
864
#ifdef __UCLIBC_HAS_WCHAR__
865
        char buf[32];
866
#endif /* __UCLIBC_HAS_WCHAR__ */
867
 
868
        /* WIDE note: we can test against '%' here since we don't allow */
869
        /* WIDE note: other mappings of '%' in the wide char set. */
870
        preci = -1;
871
        argnumber[0] = 0;
872
        argnumber[1] = 0;
873
        argtype[0] = __PA_NOARG;
874
        argtype[1] = __PA_NOARG;
875
#ifdef NL_ARGMAX
876
        maxposarg = ppfs->maxposarg;
877
#endif /* NL_ARGMAX */
878
 
879
#ifdef __UCLIBC_HAS_WCHAR__
880
        /* This is somewhat lame, but saves a lot of code.  If we're dealing with
881
         * a wide stream, that means the format is a wchar string.  So, copy it
882
         * char-by-char into a normal char buffer for processing.  Make the buffer
883
         * (buf) big enough so that any reasonable format specifier will fit.
884
         * While there a legal specifiers that won't, the all involve duplicate
885
         * flags or outrageous field widths/precisions. */
886
        width = dpoint = 0;
887
        if ((flags = ppfs->info._flags & FLAG_WIDESTREAM) == 0) {
888
                fmt = ppfs->fmtpos;
889
        } else {
890
                fmt = buf + 1;
891
                i = 0;
892
                do {
893
                        if ((buf[i] = (char) (((wchar_t *) ppfs->fmtpos)[i-1]))
894
                                != (((wchar_t *) ppfs->fmtpos)[i-1])
895
                                ) {
896
                                return -1;
897
                        }
898
                } while (buf[i++]);
899
                buf[sizeof(buf)-1] = 0;
900
        }
901
#else  /* __UCLIBC_HAS_WCHAR__ */
902
        width = flags = dpoint = 0;
903
        fmt = ppfs->fmtpos;
904
#endif /* __UCLIBC_HAS_WCHAR__ */
905
 
906
        assert(fmt[-1] == '%');
907
        assert(fmt[0] != '%');
908
 
909
        /* Process arg pos and/or flags and/or width and/or precision. */
910
 width_precision:
911
        p = fmt;
912
        if (*fmt == '*') {
913
                argtype[-dpoint] = PA_INT;
914
                ++fmt;
915
        }
916
        i = 0;
917
        while (isdigit(*fmt)) {
918
                if (i < MAX_FIELD_WIDTH) { /* Avoid overflow. */
919
                        i = (i * 10) + (*fmt - '0');
920
                }
921
                ++fmt;
922
        }
923
        if (p[-1] == '%') { /* Check for a position. */
924
 
925
                /* TODO: if val not in range, then error */
926
 
927
#ifdef NL_ARGMAX
928
                if ((*fmt == '$') && (i > 0)) {/* Positional spec. */
929
                        ++fmt;
930
                        if (maxposarg == 0) {
931
                                return -1;
932
                        }
933
                        if ((argnumber[2] = i) > maxposarg) {
934
                                maxposarg = i;
935
                        }
936
                        /* Now fall through to check flags. */
937
                } else {
938
                        if (maxposarg > 0) {
939
#ifdef __STDIO_PRINTF_M_SUPPORT
940
#ifdef __UCLIBC_MJN3_ONLY__
941
#warning TODO: Support prec and width for %m when positional args used
942
                                /* Actually, positional arg processing will fail in general
943
                                 * for specifiers that don't require an arg. */
944
#endif /* __UCLIBC_MJN3_ONLY__ */
945
                                if (*fmt == 'm') {
946
                                        goto PREC_WIDTH;
947
                                }
948
#endif /* __STDIO_PRINTF_M_SUPPORT */
949
                                return -1;
950
                        }
951
                        maxposarg = 0;           /* Possible redundant store, but cuts size. */
952
 
953
                        if ((fmt > p) && (*p != '0')) {
954
                                goto PREC_WIDTH;
955
                        }
956
 
957
                        fmt = p;                        /* Back up for possible '0's flag. */
958
                        /* Now fall through to check flags. */
959
                }
960
#else  /* NL_ARGMAX */
961
                if (*fmt == '$') {              /* Positional spec. */
962
                        return -1;
963
                }
964
 
965
                if ((fmt > p) && (*p != '0')) {
966
                        goto PREC_WIDTH;
967
                }
968
 
969
                fmt = p;                        /* Back up for possible '0's flag. */
970
                /* Now fall through to check flags. */
971
#endif /* NL_ARGMAX */
972
 
973
        restart_flags:          /* Process flags. */
974
                i = 1;
975
                p = spec_flags;
976
 
977
                do {
978
                        if (*fmt == *p++) {
979
                                ++fmt;
980
                                flags |= i;
981
                                goto restart_flags;
982
                        }
983
                        i += i;                         /* Better than i <<= 1 for bcc */
984
                } while (*p);
985
                i = 0;
986
 
987
                /* If '+' then ignore ' ', and if '-' then ignore '0'. */
988
                /* Note: Need to ignore '0' when prec is an arg with val < 0, */
989
                /*       but that test needs to wait until the arg is retrieved. */
990
                flags &= ~((flags & (FLAG_PLUS|FLAG_MINUS)) >> 1);
991
                /* Note: Ignore '0' when prec is specified < 0 too (in printf). */
992
 
993
                if (fmt[-1] != '%') {   /* If we've done anything, loop for width. */
994
                        goto width_precision;
995
                }
996
        }
997
 PREC_WIDTH:
998
        if (*p == '*') {                        /* Prec or width takes an arg. */
999
#ifdef NL_ARGMAX
1000
                if (maxposarg) {
1001
                        if ((*fmt++ != '$') || (i <= 0)) {
1002
                                /* Using pos args and no $ or invalid arg number. */
1003
                                return -1;
1004
                        }
1005
                        argnumber[-dpoint] = i;
1006
                } else
1007
#endif /* NL_ARGMAX */
1008
                if (++p != fmt) {
1009
                         /* Not using pos args but digits followed *. */
1010
                        return -1;
1011
                }
1012
                i = INT_MIN;
1013
        }
1014
 
1015
        if (!dpoint) {
1016
                width = i;
1017
                if (*fmt == '.') {
1018
                        ++fmt;
1019
                        dpoint = -1;            /* To use as default precison. */
1020
                        goto width_precision;
1021
                }
1022
        } else {
1023
                preci = i;
1024
        }
1025
 
1026
        /* Process qualifier. */
1027
        p = qual_chars;
1028
        do {
1029
                if (*fmt == *p) {
1030
                        ++fmt;
1031
                        break;
1032
                }
1033
        } while (*++p);
1034
        if ((p - qual_chars < 2) && (*fmt == *p)) {
1035
                p += ((sizeof(qual_chars)-2) / 2);
1036
                ++fmt;
1037
        }
1038
        dataargtype = ((int)(p[(sizeof(qual_chars)-2) / 2])) << 8;
1039
 
1040
        /* Process conversion specifier. */
1041
        if (!*fmt) {
1042
                return -1;
1043
        }
1044
 
1045
        p = spec_chars;
1046
 
1047
        do {
1048
                if (*fmt == *p) {
1049
                        p_m_spec_chars = p - spec_chars;
1050
 
1051
                        if ((p_m_spec_chars >= CONV_c)
1052
                                && (dataargtype & PA_FLAG_LONG)) {
1053
                                p_m_spec_chars -= 2; /* lc -> C and ls -> S */
1054
                        }
1055
 
1056
                        ppfs->conv_num = p_m_spec_chars;
1057
                        p = spec_ranges-1;
1058
                        while (p_m_spec_chars > *++p) {}
1059
 
1060
                        i = p - spec_ranges;
1061
                        argtype[2] = (dataargtype | spec_or_mask[i]) & spec_and_mask[i];
1062
                        p = spec_chars;
1063
                        break;
1064
                }
1065
        } while(*++p);
1066
 
1067
        ppfs->info.spec = *fmt;
1068
        ppfs->info.prec = preci;
1069
        ppfs->info.width = width;
1070
        ppfs->info.pad = ((flags & FLAG_ZERO) ? '0' : ' ');
1071
        ppfs->info._flags = (flags & ~FLAG_ZERO) | (dataargtype & __PA_INTMASK);
1072
        ppfs->num_data_args = 1;
1073
 
1074
        if (!*p) {
1075
#ifdef __STDIO_PRINTF_M_SUPPORT
1076
                if (*fmt == 'm') {
1077
                        ppfs->conv_num = CONV_m;
1078
                        ppfs->num_data_args = 0;
1079
                        goto DONE;
1080
                }
1081
#endif
1082
#ifdef __STDIO_GLIBC_CUSTOM_PRINTF
1083
 
1084
                /* Handle custom arg -- WARNING -- overwrites p!!! */
1085
                ppfs->conv_num = CONV_custom0;
1086
                p = _custom_printf_spec;
1087
                do {
1088
                        if (*p == *fmt) {
1089
                                if ((ppfs->num_data_args
1090
                                         = ((*_custom_printf_arginfo[(int)(p-_custom_printf_spec)])
1091
                                                (&(ppfs->info), MAX_ARGS_PER_SPEC, argtype+2)))
1092
                                        > MAX_ARGS_PER_SPEC) {
1093
                                        break;          /* Error -- too many args! */
1094
                                }
1095
                                goto DONE;
1096
                        }
1097
                } while (++p < (_custom_printf_spec + MAX_USER_SPEC));
1098
#endif /* __STDIO_GLIBC_CUSTOM_PRINTF */
1099
                /* Otherwise error. */
1100
                return -1;
1101
        }
1102
 
1103
#if defined(__STDIO_GLIBC_CUSTOM_PRINTF) || defined(__STDIO_PRINTF_M_SUPPORT)
1104
 DONE:
1105
#endif
1106
 
1107
#ifdef NL_ARGMAX
1108
        if (maxposarg > 0) {
1109
                i = 0;
1110
                do {
1111
                        /* Update maxposarg and check that NL_ARGMAX is not exceeded. */
1112
                        n = ((i <= 2)
1113
                                 ? (ppfs->argnumber[i] = argnumber[i])
1114
                                 : argnumber[2] + (i-2));
1115
                        if (n > maxposarg) {
1116
                                if ((maxposarg = n) > NL_ARGMAX) {
1117
                                        return -1;
1118
                                }
1119
                        }
1120
                        --n;
1121
                        /* Record argtype with largest size (current, new). */
1122
                        if (_is_equal_or_bigger_arg(ppfs->argtype[n], argtype[i])) {
1123
                                ppfs->argtype[n] = argtype[i];
1124
                        }
1125
                } while (++i < ppfs->num_data_args + 2);
1126
        } else {
1127
#endif /* NL_ARGMAX */
1128
                ppfs->argnumber[2] = 1;
1129
                memcpy(ppfs->argtype, argtype + 2, ppfs->num_data_args * sizeof(int));
1130
#ifdef NL_ARGMAX
1131
        }
1132
 
1133
        ppfs->maxposarg = maxposarg;
1134
#endif /* NL_ARGMAX */
1135
 
1136
#ifdef __UCLIBC_HAS_WCHAR__
1137
        if ((flags = ppfs->info._flags & FLAG_WIDESTREAM) == 0) {
1138
                ppfs->fmtpos = ++fmt;
1139
        } else {
1140
                ppfs->fmtpos = (const char *) (((const wchar_t *)(ppfs->fmtpos))
1141
                                                                           + (fmt - buf) );
1142
        }
1143
#else  /* __UCLIBC_HAS_WCHAR__ */
1144
        ppfs->fmtpos = ++fmt;
1145
#endif /* __UCLIBC_HAS_WCHAR__ */
1146
 
1147
        return ppfs->num_data_args + 2;
1148
}
1149
 
1150
#endif
1151
/**********************************************************************/
1152
#ifdef L_register_printf_function
1153
 
1154
#ifdef __STDIO_GLIBC_CUSTOM_PRINTF
1155
 
1156
int register_printf_function(int spec, printf_function handler,
1157
                                                         printf_arginfo_function arginfo)
1158
{
1159
        register char *r;
1160
        register char *p;
1161
 
1162
        if (spec && (arginfo != NULL)) { /* TODO -- check if spec is valid char */
1163
                r = NULL;
1164
                p = _custom_printf_spec + MAX_USER_SPEC;
1165
                do {
1166
                        --p;
1167
                        if (!*p) {
1168
                                r = p;
1169
                        }
1170
#ifdef __BCC__
1171
                        else                            /* bcc generates less code with fall-through */
1172
#endif
1173
                        if (*p == spec) {
1174
                                r = p;
1175
                                p = _custom_printf_spec;
1176
                        }
1177
                } while (p > _custom_printf_spec);
1178
 
1179
                if (r) {
1180
                        if (handler) {
1181
                                *r = spec;
1182
                                _custom_printf_handler[(int)(r - p)] = handler;
1183
                                _custom_printf_arginfo[(int)(r - p)] = arginfo;
1184
                        } else {
1185
                                *r = 0;
1186
                        }
1187
                        return 0;
1188
                }
1189
                /* TODO -- if asked to unregister a non-existent spec, return what? */
1190
        }
1191
        return -1;
1192
}
1193
 
1194
#endif
1195
 
1196
#endif
1197
/**********************************************************************/
1198
#ifdef L_vsnprintf
1199
 
1200
#ifdef __UCLIBC_MJN3_ONLY__
1201
#warning WISHLIST: Implement vsnprintf for non-buffered and no custom stream case.
1202
#endif /* __UCLIBC_MJN3_ONLY__ */
1203
 
1204
#ifdef __STDIO_BUFFERS
1205
 
1206
int vsnprintf(char *__restrict buf, size_t size,
1207
                          const char * __restrict format, va_list arg)
1208
{
1209
        FILE f;
1210
        int rv;
1211
 
1212
#ifdef __STDIO_GETC_MACRO
1213
        f.bufgetc =
1214
#endif
1215
        f.bufpos = f.bufread = f.bufstart = buf;
1216
 
1217
        if (size > SIZE_MAX - (size_t) buf) {
1218
                size = SIZE_MAX - (size_t) buf;
1219
        }
1220
#ifdef __STDIO_PUTC_MACRO
1221
        f.bufputc =
1222
#endif
1223
        f.bufend = buf + size;
1224
 
1225
#if 0                                                   /* shouldn't be necessary */
1226
/*  #ifdef __STDIO_GLIBC_CUSTOM_STREAMS */
1227
        f.cookie = &(f.filedes);
1228
        f.gcs.read = 0;
1229
        f.gcs.write = 0;
1230
        f.gcs.seek = 0;
1231
        f.gcs.close = 0;
1232
#endif
1233
        f.filedes = -2;                         /* for debugging */
1234
        f.modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
1235
 
1236
#ifdef __STDIO_MBSTATE
1237
        __INIT_MBSTATE(&(f.state));
1238
#endif /* __STDIO_MBSTATE */
1239
 
1240
#ifdef __STDIO_THREADSAFE
1241
        f.user_locking = 0;
1242
        __stdio_init_mutex(&f.lock);
1243
#endif
1244
 
1245
        rv = vfprintf(&f, format, arg);
1246
        if (size) {
1247
                if (f.bufpos == f.bufend) {
1248
                        --f.bufpos;
1249
                }
1250
                *f.bufpos = 0;
1251
        }
1252
        return rv;
1253
}
1254
 
1255
#elif defined(__USE_OLD_VFPRINTF__)
1256
 
1257
typedef struct {
1258
        FILE f;
1259
        unsigned char *bufend;          /* pointer to 1 past end of buffer */
1260
        unsigned char *bufpos;
1261
} __FILE_vsnprintf;
1262
 
1263
int vsnprintf(char *__restrict buf, size_t size,
1264
                          const char * __restrict format, va_list arg)
1265
{
1266
        __FILE_vsnprintf f;
1267
        int rv;
1268
 
1269
        f.bufpos = buf;
1270
 
1271
        if (size > SIZE_MAX - (size_t) buf) {
1272
                size = SIZE_MAX - (size_t) buf;
1273
        }
1274
        f.bufend = buf + size;
1275
 
1276
#if 0                                                   /* shouldn't be necessary */
1277
/*  #ifdef __STDIO_GLIBC_CUSTOM_STREAMS */
1278
        f.f.cookie = &(f.f.filedes);
1279
        f.f.gcs.read = 0;
1280
        f.f.gcs.write = 0;
1281
        f.f.gcs.seek = 0;
1282
        f.f.gcs.close = 0;
1283
#endif
1284
        f.f.filedes = -2;                               /* for debugging */
1285
        f.f.modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
1286
 
1287
#ifdef __STDIO_MBSTATE
1288
        __INIT_MBSTATE(&(f.f.state));
1289
#endif /* __STDIO_MBSTATE */
1290
 
1291
#ifdef __STDIO_THREADSAFE
1292
        f.f.user_locking = 0;
1293
        __stdio_init_mutex(&f.f.lock);
1294
#endif
1295
 
1296
        rv = vfprintf((FILE *) &f, format, arg);
1297
        if (size) {
1298
                if (f.bufpos == f.bufend) {
1299
                        --f.bufpos;
1300
                }
1301
                *f.bufpos = 0;
1302
        }
1303
        return rv;
1304
}
1305
 
1306
#elif defined(__STDIO_GLIBC_CUSTOM_STREAMS)
1307
 
1308
typedef struct {
1309
        size_t pos;
1310
        size_t len;
1311
        unsigned char *buf;
1312
        FILE *fp;
1313
} __snpf_cookie;
1314
 
1315
#define COOKIE ((__snpf_cookie *) cookie)
1316
 
1317
static ssize_t snpf_write(register void *cookie, const char *buf,
1318
                                                  size_t bufsize)
1319
{
1320
        size_t count;
1321
        register char *p;
1322
 
1323
        /* Note: bufsize < SSIZE_MAX because of _stdio_WRITE. */
1324
 
1325
        if (COOKIE->len > COOKIE->pos) {
1326
                count = COOKIE->len - COOKIE->pos - 1; /* Leave space for nul. */
1327
                if (count > bufsize) {
1328
                        count = bufsize;
1329
                }
1330
 
1331
                p = COOKIE->buf + COOKIE->pos;
1332
                while (count) {
1333
                        *p++ = *buf++;
1334
                        --count;
1335
                }
1336
                *p = 0;
1337
        }
1338
 
1339
        COOKIE->pos += bufsize;
1340
 
1341
        return bufsize;
1342
}
1343
 
1344
#undef COOKIE
1345
 
1346
int vsnprintf(char *__restrict buf, size_t size,
1347
                          const char * __restrict format, va_list arg)
1348
{
1349
        FILE f;
1350
        __snpf_cookie cookie;
1351
        int rv;
1352
 
1353
        cookie.buf = buf;
1354
        cookie.len = size;
1355
        cookie.pos = 0;
1356
        cookie.fp = &f;
1357
 
1358
        f.cookie = &cookie;
1359
        f.gcs.write = snpf_write;
1360
        f.gcs.read = NULL;
1361
        f.gcs.seek = NULL;
1362
        f.gcs.close = NULL;
1363
 
1364
        f.filedes = -1;                         /* For debugging. */
1365
        f.modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
1366
 
1367
#ifdef __STDIO_MBSTATE
1368
        __INIT_MBSTATE(&(f.state));
1369
#endif /* __STDIO_MBSTATE */
1370
 
1371
#ifdef __STDIO_THREADSAFE
1372
        f.user_locking = 0;
1373
        __stdio_init_mutex(&f.lock);
1374
#endif
1375
 
1376
        rv = vfprintf(&f, format, arg);
1377
 
1378
        return rv;
1379
}
1380
 
1381
#else
1382
#warning Skipping vsnprintf since no buffering, no custom streams, and not old vfprintf!
1383
#ifdef __STDIO_HAS_VSNPRINTF
1384
#error WHOA! __STDIO_HAS_VSNPRINTF is defined!
1385
#endif
1386
#endif
1387
 
1388
#endif
1389
/**********************************************************************/
1390
#ifdef L_vdprintf
1391
 
1392
int vdprintf(int filedes, const char * __restrict format, va_list arg)
1393
{
1394
        FILE f;
1395
        int rv;
1396
#ifdef __STDIO_BUFFERS
1397
        char buf[64];                           /* TODO: provide _optional_ buffering? */
1398
 
1399
#ifdef __STDIO_GETC_MACRO
1400
        f.bufgetc =
1401
#endif
1402
        f.bufpos = f.bufread = f.bufstart = buf;
1403
#ifdef __STDIO_PUTC_MACRO
1404
        f.bufputc =
1405
#endif
1406
        f.bufend = buf + sizeof(buf);
1407
#endif /* __STDIO_BUFFERS */
1408
#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
1409
        f.cookie = &(f.filedes);
1410
        f.gcs.read = _cs_read;
1411
        f.gcs.write = _cs_write;
1412
        f.gcs.seek = 0;                          /* The internal seek func handles normals. */
1413
        f.gcs.close = _cs_close;
1414
#endif
1415
        f.filedes = filedes;
1416
        f.modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
1417
 
1418
#ifdef __STDIO_MBSTATE
1419
        __INIT_MBSTATE(&(f.state));
1420
#endif /* __STDIO_MBSTATE */
1421
 
1422
#ifdef __STDIO_THREADSAFE
1423
        f.user_locking = 0;
1424
        __stdio_init_mutex(&f.lock);
1425
#endif
1426
 
1427
        rv = vfprintf(&f, format, arg);
1428
 
1429
        return fflush(&f) ? -1 : rv;
1430
}
1431
 
1432
#endif
1433
/**********************************************************************/
1434
#ifdef L_vasprintf
1435
 
1436
#ifndef __STDIO_HAS_VSNPRINTF
1437
#warning Skipping vasprintf since no vsnprintf!
1438
#else
1439
 
1440
int vasprintf(char **__restrict buf, const char * __restrict format,
1441
                         va_list arg)
1442
{
1443
        /* TODO -- change the default implementation? */
1444
#ifndef __STDIO_GLIBC_CUSTOM_STREAMS
1445
        /* This implementation actually calls the printf machinery twice, but only
1446
         * only does one malloc.  This can be a problem though when custom printf
1447
         * specs or the %m specifier are involved because the results of the
1448
         * second call might be different from the first. */
1449
        va_list arg2;
1450
        int rv;
1451
 
1452
        va_copy(arg2, arg);
1453
        rv = vsnprintf(NULL, 0, format, arg2);
1454
        va_end(arg2);
1455
 
1456
        return (((rv >= 0) && ((*buf = malloc(++rv)) != NULL))
1457
                        ? vsnprintf(*buf, rv, format, arg)
1458
                        : -1);
1459
#else
1460
        FILE *f;
1461
        size_t size;
1462
        int rv;
1463
 
1464
        /* TODO - do the memstream stuff inline here to avoid fclose and the openlist? */
1465
        if ((f = open_memstream(buf, &size)) == NULL) {
1466
                return -1;
1467
        }
1468
        rv = vfprintf(f, format, arg);
1469
        fclose(f);
1470
        if (rv < 0) {
1471
                free(*buf);
1472
                *buf = NULL;
1473
                return -1;
1474
        }
1475
        return rv;
1476
#endif
1477
}
1478
#endif
1479
#endif
1480
/**********************************************************************/
1481
#ifdef L_vprintf
1482
int vprintf(const char * __restrict format, va_list arg)
1483
{
1484
        return vfprintf(stdout, format, arg);
1485
}
1486
#endif
1487
/**********************************************************************/
1488
#ifdef L_vsprintf
1489
 
1490
#ifndef __STDIO_HAS_VSNPRINTF
1491
#warning Skipping vsprintf since no vsnprintf!
1492
#else
1493
 
1494
int vsprintf(char *__restrict buf, const char * __restrict format,
1495
                         va_list arg)
1496
{
1497
        return vsnprintf(buf, SIZE_MAX, format, arg);
1498
}
1499
 
1500
#endif
1501
#endif
1502
/**********************************************************************/
1503
#ifdef L_fprintf
1504
 
1505
int fprintf(FILE * __restrict stream, const char * __restrict format, ...)
1506
{
1507
        va_list arg;
1508
        int rv;
1509
 
1510
        va_start(arg, format);
1511
        rv = vfprintf(stream, format, arg);
1512
        va_end(arg);
1513
 
1514
        return rv;
1515
}
1516
 
1517
#endif
1518
/**********************************************************************/
1519
#ifdef L_snprintf
1520
 
1521
#ifndef __STDIO_HAS_VSNPRINTF
1522
#warning Skipping snprintf since no vsnprintf!
1523
#else
1524
 
1525
int snprintf(char *__restrict buf, size_t size,
1526
                         const char * __restrict format, ...)
1527
{
1528
        va_list arg;
1529
        int rv;
1530
 
1531
        va_start(arg, format);
1532
        rv = vsnprintf(buf, size, format, arg);
1533
        va_end(arg);
1534
        return rv;
1535
}
1536
 
1537
#endif
1538
#endif
1539
/**********************************************************************/
1540
#ifdef L_dprintf
1541
 
1542
int dprintf(int filedes, const char * __restrict format, ...)
1543
{
1544
        va_list arg;
1545
        int rv;
1546
 
1547
        va_start(arg, format);
1548
        rv = vdprintf(filedes, format, arg);
1549
        va_end(arg);
1550
 
1551
        return rv;
1552
}
1553
 
1554
#endif
1555
/**********************************************************************/
1556
#ifdef L_asprintf
1557
 
1558
#ifndef __STDIO_HAS_VSNPRINTF
1559
#warning Skipping asprintf and __asprintf since no vsnprintf!
1560
#else
1561
 
1562
weak_alias(__asprintf,asprintf)
1563
 
1564
int __asprintf(char **__restrict buf, const char * __restrict format, ...)
1565
{
1566
        va_list arg;
1567
        int rv;
1568
 
1569
        va_start(arg, format);
1570
        rv = vasprintf(buf, format, arg);
1571
        va_end(arg);
1572
 
1573
        return rv;
1574
}
1575
 
1576
#endif
1577
#endif
1578
/**********************************************************************/
1579
#ifdef L_printf
1580
int printf(const char * __restrict format, ...)
1581
{
1582
        va_list arg;
1583
        int rv;
1584
 
1585
        va_start(arg, format);
1586
        rv = vfprintf(stdout, format, arg);
1587
        va_end(arg);
1588
 
1589
        return rv;
1590
}
1591
#endif
1592
/**********************************************************************/
1593
#ifdef L_sprintf
1594
 
1595
#ifndef __STDIO_HAS_VSNPRINTF
1596
#warning Skipping sprintf since no vsnprintf!
1597
#else
1598
 
1599
int sprintf(char *__restrict buf, const char * __restrict format, ...)
1600
{
1601
        va_list arg;
1602
        int rv;
1603
 
1604
        va_start(arg, format);
1605
        rv = vsnprintf(buf, SIZE_MAX, format, arg);
1606
        va_end(arg);
1607
 
1608
        return rv;
1609
}
1610
 
1611
#endif
1612
#endif
1613
/**********************************************************************/
1614
#ifdef L_vswprintf
1615
 
1616
#ifdef __STDIO_BUFFERS
1617
int vswprintf(wchar_t *__restrict buf, size_t size,
1618
                          const wchar_t * __restrict format, va_list arg)
1619
{
1620
        FILE f;
1621
        int rv;
1622
 
1623
#ifdef __STDIO_GETC_MACRO
1624
        f.bufgetc =
1625
#endif
1626
        f.bufpos = f.bufread = f.bufstart = (char *) buf;
1627
 
1628
/*      if (size > SIZE_MAX - (size_t) buf) { */
1629
/*              size = SIZE_MAX - (size_t) buf; */
1630
/*      } */
1631
#ifdef __STDIO_PUTC_MACRO
1632
        f.bufputc =
1633
#endif
1634
        f.bufend = (char *)(buf + size);
1635
 
1636
#if 0                                                   /* shouldn't be necessary */
1637
/*  #ifdef __STDIO_GLIBC_CUSTOM_STREAMS */
1638
        f.cookie = &(f.filedes);
1639
        f.gcs.read = 0;
1640
        f.gcs.write = 0;
1641
        f.gcs.seek = 0;
1642
        f.gcs.close = 0;
1643
#endif
1644
        f.filedes = -3;                         /* for debugging */
1645
        f.modeflags = (__FLAG_WIDE|__FLAG_WRITEONLY|__FLAG_WRITING);
1646
 
1647
#ifdef __STDIO_MBSTATE
1648
        __INIT_MBSTATE(&(f.state));
1649
#endif /* __STDIO_MBSTATE */
1650
 
1651
#ifdef __STDIO_THREADSAFE
1652
        f.user_locking = 0;
1653
        __stdio_init_mutex(&f.lock);
1654
#endif
1655
 
1656
        rv = vfwprintf(&f, format, arg);
1657
 
1658
        /* NOTE: Return behaviour differs from snprintf... */
1659
        if (f.bufpos == f.bufend) {
1660
                rv = -1;
1661
                if (size) {
1662
                        f.bufpos = (char *)(((wchar_t *) f.bufpos) - 1);
1663
                }
1664
        }
1665
        if (size) {
1666
                *((wchar_t *) f.bufpos) = 0;
1667
        }
1668
        return rv;
1669
}
1670
#else  /* __STDIO_BUFFERS */
1671
#warning Skipping vswprintf since no buffering!
1672
#endif /* __STDIO_BUFFERS */
1673
#endif
1674
/**********************************************************************/
1675
#ifdef L_swprintf
1676
#ifdef __STDIO_BUFFERS
1677
 
1678
int swprintf(wchar_t *__restrict buf, size_t size,
1679
                         const wchar_t * __restrict format, ...)
1680
{
1681
        va_list arg;
1682
        int rv;
1683
 
1684
        va_start(arg, format);
1685
        rv = vswprintf(buf, size, format, arg);
1686
        va_end(arg);
1687
        return rv;
1688
}
1689
 
1690
#else  /* __STDIO_BUFFERS */
1691
#warning Skipping vsWprintf since no buffering!
1692
#endif /* __STDIO_BUFFERS */
1693
#endif
1694
/**********************************************************************/
1695
#ifdef L_fwprintf
1696
 
1697
int fwprintf(FILE * __restrict stream, const wchar_t * __restrict format, ...)
1698
{
1699
        va_list arg;
1700
        int rv;
1701
 
1702
        va_start(arg, format);
1703
        rv = vfwprintf(stream, format, arg);
1704
        va_end(arg);
1705
 
1706
        return rv;
1707
}
1708
 
1709
#endif
1710
/**********************************************************************/
1711
#ifdef L_vwprintf
1712
int vwprintf(const wchar_t * __restrict format, va_list arg)
1713
{
1714
        return vfwprintf(stdout, format, arg);
1715
}
1716
#endif
1717
/**********************************************************************/
1718
#ifdef L_wprintf
1719
int wprintf(const wchar_t * __restrict format, ...)
1720
{
1721
        va_list arg;
1722
        int rv;
1723
 
1724
        va_start(arg, format);
1725
        rv = vfwprintf(stdout, format, arg);
1726
        va_end(arg);
1727
 
1728
        return rv;
1729
}
1730
#endif
1731
/**********************************************************************/
1732
#ifdef L__fpmaxtostr
1733
 
1734
/* Copyright (C) 2000, 2001, 2003      Manuel Novoa III
1735
 *
1736
 * Function:
1737
 *
1738
 *     size_t _fpmaxtostr(FILE * fp, __fpmax_t x, struct printf_info *info,
1739
 *                         __fp_outfunc_t fp_outfunc);
1740
 *
1741
 * This is derived from the old _dtostr, whic I wrote for uClibc to provide
1742
 * floating point support for the printf functions.  It handles +/- infinity,
1743
 * nan, and signed 0 assuming you have ieee arithmetic.  It also now handles
1744
 * digit grouping (for the uClibc supported locales) and hexadecimal float
1745
 * notation.  Finally, via the fp_outfunc parameter, it now supports wide
1746
 * output.
1747
 *
1748
 * Notes:
1749
 *
1750
 * At most DECIMAL_DIG significant digits are kept.  Any trailing digits
1751
 * are treated as 0 as they are really just the results of rounding noise
1752
 * anyway.  If you want to do better, use an arbitary precision arithmetic
1753
 * package.  ;-)
1754
 *
1755
 * It should also be fairly portable, as no assumptions are made about the
1756
 * bit-layout of doubles.  Of course, that does make it less efficient than
1757
 * it could be.
1758
 *
1759
 */
1760
 
1761
/*****************************************************************************/
1762
/* Don't change anything that follows unless you know what you're doing.     */
1763
/*****************************************************************************/
1764
/* Fairly portable nan check.  Bitwise for i386 generated larger code.
1765
 * If you have a better version, comment this out.
1766
 */
1767
#define isnan(x)             ((x) != (x))
1768
 
1769
/* Without seminumerical functions to examine the sign bit, this is
1770
 * about the best we can do to test for '-0'.
1771
 */
1772
#define zeroisnegative(x)    ((1./(x)) < 0)
1773
 
1774
/*****************************************************************************/
1775
/* Don't change anything that follows peroid!!!  ;-)                         */
1776
/*****************************************************************************/
1777
#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
1778
#if FLT_RADIX != 2
1779
#error FLT_RADIX != 2 is not currently supported
1780
#endif
1781
#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
1782
 
1783
#define NUM_HEX_DIGITS      ((FPMAX_MANT_DIG + 3)/ 4)
1784
 
1785
/* WARNING: Adjust _fp_out_wide() below if this changes! */
1786
/* With 32 bit ints, we can get 9 decimal digits per block. */
1787
#define DIGITS_PER_BLOCK     9
1788
#define HEX_DIGITS_PER_BLOCK 8
1789
 
1790
/* Maximum number of subcases to output double is...
1791
 *  0 - sign
1792
 *  1 - padding and initial digit
1793
 *  2 - digits left of the radix
1794
 *  3 - 0s left of the radix        or   radix
1795
 *  4 - radix                       or   digits right of the radix
1796
 *  5 - 0s right of the radix
1797
 *  6 - exponent
1798
 *  7 - trailing space padding
1799
 * although not all cases may occur.
1800
 */
1801
#define MAX_CALLS 8
1802
 
1803
/*****************************************************************************/
1804
 
1805
#define NUM_DIGIT_BLOCKS   ((DECIMAL_DIG+DIGITS_PER_BLOCK-1)/DIGITS_PER_BLOCK)
1806
#define NUM_HEX_DIGIT_BLOCKS \
1807
   ((NUM_HEX_DIGITS+HEX_DIGITS_PER_BLOCK-1)/HEX_DIGITS_PER_BLOCK)
1808
 
1809
/* WARNING: Adjust _fp_out_wide() below if this changes! */
1810
 
1811
/* extra space for '-', '.', 'e+###', and nul */
1812
#define BUF_SIZE  ( 3 + NUM_DIGIT_BLOCKS * DIGITS_PER_BLOCK )
1813
 
1814
/*****************************************************************************/
1815
 
1816
static const char fmt[] = "inf\0INF\0nan\0NAN\0.\0,";
1817
 
1818
#define INF_OFFSET        0             /* must be 1st */
1819
#define NAN_OFFSET        8             /* must be 2nd.. see hex sign handling */
1820
#define DECPT_OFFSET     16
1821
#define THOUSEP_OFFSET   18
1822
 
1823
#define EMPTY_STRING_OFFSET 3
1824
 
1825
/*****************************************************************************/
1826
#if FPMAX_MAX_10_EXP < -FPMAX_MIN_10_EXP
1827
#error scaling code can not handle FPMAX_MAX_10_EXP < -FPMAX_MIN_10_EXP
1828
#endif
1829
 
1830
static const __fpmax_t exp10_table[] =
1831
{
1832
        1e1L, 1e2L, 1e4L, 1e8L, 1e16L, 1e32L,   /* floats */
1833
#if FPMAX_MAX_10_EXP < 32
1834
#error unsupported FPMAX_MAX_10_EXP (< 32).  ANSI/ISO C requires >= 37.
1835
#endif
1836
#if FPMAX_MAX_10_EXP >= 64
1837
        1e64L,
1838
#endif
1839
#if FPMAX_MAX_10_EXP >= 128
1840
        1e128L,
1841
#endif
1842
#if FPMAX_MAX_10_EXP >= 256
1843
        1e256L,
1844
#endif
1845
#if FPMAX_MAX_10_EXP >= 512
1846
        1e512L,
1847
#endif
1848
#if FPMAX_MAX_10_EXP >= 1024
1849
        1e1024L,
1850
#endif
1851
#if FPMAX_MAX_10_EXP >= 2048
1852
        1e2048L,
1853
#endif
1854
#if FPMAX_MAX_10_EXP >= 4096
1855
        1e4096L
1856
#endif
1857
#if FPMAX_MAX_10_EXP >= 8192
1858
#error unsupported FPMAX_MAX_10_EXP.  please increase table
1859
#endif
1860
};
1861
 
1862
#define EXP10_TABLE_SIZE     (sizeof(exp10_table)/sizeof(exp10_table[0]))
1863
#define EXP10_TABLE_MAX      (1U<<(EXP10_TABLE_SIZE-1))
1864
 
1865
/*****************************************************************************/
1866
#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
1867
 
1868
#if FLT_RADIX != 2
1869
#error FLT_RADIX != 2 is not currently supported
1870
#endif
1871
 
1872
#if FPMAX_MAX_EXP < -FPMAX_MIN_EXP
1873
#error scaling code can not handle FPMAX_MAX_EXP < -FPMAX_MIN_EXP
1874
#endif
1875
 
1876
static const __fpmax_t exp16_table[] = {
1877
        0x1.0p4L, 0x1.0p8L, 0x1.0p16L, 0x1.0p32L, 0x1.0p64L,
1878
#if FPMAX_MAX_EXP >= 128
1879
        0x1.0p128L,
1880
#endif
1881
#if FPMAX_MAX_EXP >= 256
1882
        0x1.0p256L,
1883
#endif
1884
#if FPMAX_MAX_EXP >= 512
1885
        0x1.0p512L,
1886
#endif
1887
#if FPMAX_MAX_EXP >= 1024
1888
        0x1.0p1024L,
1889
#endif
1890
#if FPMAX_MAX_EXP >= 2048
1891
        0x1.0p2048L,
1892
#endif
1893
#if FPMAX_MAX_EXP >= 4096
1894
        0x1.0p4096L,
1895
#endif
1896
#if FPMAX_MAX_EXP >= 8192
1897
        0x1.0p8192L,
1898
#endif
1899
#if FPMAX_MAX_EXP >= 16384
1900
        0x1.0p16384L
1901
#endif
1902
#if FPMAX_MAX_EXP >= 32768 
1903
#error unsupported FPMAX_MAX_EXP.  please increase table
1904
#endif
1905
};
1906
 
1907
#define EXP16_TABLE_SIZE     (sizeof(exp16_table)/sizeof(exp16_table[0]))
1908
#define EXP16_TABLE_MAX      (1U<<(EXP16_TABLE_SIZE-1))
1909
 
1910
#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
1911
/*****************************************************************************/
1912
 
1913
#define FPO_ZERO_PAD    (0x80 | '0')
1914
#define FPO_STR_WIDTH   (0x80 | ' ');
1915
#define FPO_STR_PREC    'p'
1916
 
1917
size_t _fpmaxtostr(FILE * fp, __fpmax_t x, struct printf_info *info,
1918
                                   __fp_outfunc_t fp_outfunc)
1919
{
1920
#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
1921
        __fpmax_t lower_bnd;
1922
        __fpmax_t upper_bnd = 1e9;
1923
#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
1924
        uint_fast32_t digit_block;
1925
#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
1926
        uint_fast32_t base = 10;
1927
        const __fpmax_t *power_table;
1928
        int dpb = DIGITS_PER_BLOCK;
1929
        int ndb = NUM_DIGIT_BLOCKS;
1930
        int nd = DECIMAL_DIG;
1931
        int sufficient_precision = 0;
1932
#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
1933
#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
1934
        int num_groups = 0;
1935
        int initial_group;         /* This does not need to be initialized. */
1936
        int tslen;                         /* This does not need to be initialized. */
1937
        int nblk2;                         /* This does not need to be initialized. */
1938
        const char *ts;            /* This does not need to be initialized. */
1939
#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
1940
        int i, j;
1941
        int round, o_exp;
1942
        int exp, exp_neg;
1943
        int width, preci;
1944
        int cnt;
1945
        char *s;
1946
        char *e;
1947
        intptr_t pc_fwi[3*MAX_CALLS];
1948
        intptr_t *ppc;
1949
        intptr_t *ppc_last;
1950
#ifdef __UCLIBC_MJN3_ONLY__
1951
#warning TODO: The size of exp_buf[] should really be determined by the float constants.
1952
#endif /* __UCLIBC_MJN3_ONLY__ */
1953
        char exp_buf[16];
1954
        char buf[BUF_SIZE];
1955
        char sign_str[6];                       /* Last 2 are for 1st digit + nul. */
1956
        char o_mode;
1957
        char mode;
1958
 
1959
 
1960
        width = info->width;
1961
        preci = info->prec;
1962
        mode = info->spec;
1963
 
1964
        *exp_buf = 'e';
1965
        if ((mode|0x20) == 'a') {
1966
#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
1967
                *exp_buf = 'p';
1968
                if (preci < 0) {
1969
                        preci = NUM_HEX_DIGITS;
1970
                        sufficient_precision = 1;
1971
                }
1972
#else
1973
                mode += ('g' - 'a');
1974
#endif
1975
        }
1976
 
1977
        if (preci < 0) {
1978
                preci = 6;
1979
        }
1980
 
1981
        *sign_str = '\0';
1982
        if (PRINT_INFO_FLAG_VAL(info,showsign)) {
1983
                *sign_str = '+';
1984
        } else if (PRINT_INFO_FLAG_VAL(info,space)) {
1985
                *sign_str = ' ';
1986
        }
1987
 
1988
        *(sign_str+1) = 0;
1989
        pc_fwi[5] = INF_OFFSET;
1990
        if (isnan(x)) {                         /* First, check for nan. */
1991
                pc_fwi[5] = NAN_OFFSET;
1992
                goto INF_NAN;
1993
        }
1994
 
1995
        if (x == 0) {                            /* Handle 0 now to avoid false positive. */
1996
#if 1
1997
                if (zeroisnegative(x)) { /* Handle 'signed' zero. */
1998
                        *sign_str = '-';
1999
                }
2000
#endif
2001
                exp = -1;
2002
                goto GENERATE_DIGITS;
2003
        }
2004
 
2005
        if (x < 0) {                             /* Convert negatives to positives. */
2006
                *sign_str = '-';
2007
                x = -x;
2008
        }
2009
 
2010
        if (__FPMAX_ZERO_OR_INF_CHECK(x)) {     /* Inf since zero handled above. */
2011
        INF_NAN:
2012
                info->pad = ' ';
2013
                ppc = pc_fwi + 6;
2014
                pc_fwi[3] = FPO_STR_PREC;
2015
                pc_fwi[4] = 3;
2016
                if (mode < 'a') {
2017
                        pc_fwi[5] += 4;
2018
                }
2019
                pc_fwi[5] = (intptr_t)(fmt + pc_fwi[5]);
2020
                goto EXIT_SPECIAL;
2021
        }
2022
 
2023
#ifdef __UCLIBC_MJN3_ONLY__
2024
#warning TODO: Clean up defines when hexadecimal float notation is unsupported.
2025
#endif /* __UCLIBC_MJN3_ONLY__ */
2026
 
2027
#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
2028
 
2029
        if ((mode|0x20) == 'a') {
2030
                lower_bnd = 0x1.0p31L;
2031
                upper_bnd = 0x1.0p32L;
2032
                power_table = exp16_table;
2033
                exp = HEX_DIGITS_PER_BLOCK - 1;
2034
                i = EXP16_TABLE_SIZE;
2035
                j = EXP16_TABLE_MAX;
2036
                dpb = HEX_DIGITS_PER_BLOCK;
2037
                ndb = NUM_HEX_DIGIT_BLOCKS;
2038
                nd = NUM_HEX_DIGITS;
2039
                base = 16;
2040
        } else {
2041
                lower_bnd = 1e8;
2042
/*              upper_bnd = 1e9; */
2043
                power_table = exp10_table;
2044
                exp = DIGITS_PER_BLOCK - 1;
2045
                i = EXP10_TABLE_SIZE;
2046
                j = EXP10_TABLE_MAX;
2047
/*              dpb = DIGITS_PER_BLOCK; */
2048
/*              ndb = NUM_DIGIT_BLOCKS; */
2049
/*              base = 10; */
2050
        }
2051
 
2052
 
2053
 
2054
#else  /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
2055
 
2056
#define lower_bnd    1e8
2057
#define upper_bnd    1e9
2058
#define power_table  exp10_table
2059
#define dpb          DIGITS_PER_BLOCK
2060
#define base         10
2061
#define ndb          NUM_DIGIT_BLOCKS
2062
#define nd           DECIMAL_DIG
2063
 
2064
        exp = DIGITS_PER_BLOCK - 1;
2065
        i = EXP10_TABLE_SIZE;
2066
        j = EXP10_TABLE_MAX;
2067
 
2068
#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
2069
 
2070
        exp_neg = 0;
2071
        if (x < lower_bnd) {            /* Do we need to scale up or down? */
2072
                exp_neg = 1;
2073
        }
2074
 
2075
        do {
2076
                --i;
2077
                if (exp_neg) {
2078
                        if (x * power_table[i] < upper_bnd) {
2079
                                x *= power_table[i];
2080
                                exp -= j;
2081
                        }
2082
                } else {
2083
                        if (x / power_table[i] >= lower_bnd) {
2084
                                x /= power_table[i];
2085
                                exp += j;
2086
                        }
2087
                }
2088
                j >>= 1;
2089
        } while (i);
2090
        if (x >= upper_bnd) {           /* Handle bad rounding case. */
2091
                x /= power_table[0];
2092
                ++exp;
2093
        }
2094
        assert(x < upper_bnd);
2095
 
2096
 GENERATE_DIGITS:
2097
        s = buf + 2;                            /* Leave space for '\0' and '0'. */
2098
        i = 0;
2099
        do {
2100
                digit_block = (uint_fast32_t) x;
2101
                assert(digit_block < upper_bnd);
2102
#ifdef __UCLIBC_MJN3_ONLY__
2103
#warning CONSIDER: Can rounding be a problem?
2104
#endif /* __UCLIBC_MJN3_ONLY__ */
2105
                x = (x - digit_block) * upper_bnd;
2106
                s += dpb;
2107
                j = 0;
2108
                do {
2109
                        s[- ++j] = '0' + (digit_block % base);
2110
                        digit_block /= base;
2111
                } while (j < dpb);
2112
        } while (++i < ndb);
2113
 
2114
        /*************************************************************************/
2115
 
2116
        if (mode < 'a') {
2117
                *exp_buf -= ('a' - 'A'); /* e->E and p->P */
2118
                mode += ('a' - 'A');
2119
        }
2120
 
2121
        o_mode = mode;
2122
        if ((mode == 'g') && (preci > 0)){
2123
                --preci;
2124
        }
2125
        round = preci;
2126
 
2127
        if (mode == 'f') {
2128
                round += exp;
2129
                if (round < -1) {
2130
                        memset(buf, '0', DECIMAL_DIG); /* OK, since 'f' -> decimal case. */
2131
                    exp = -1;
2132
                    round = -1;
2133
                }
2134
        }
2135
 
2136
        s = buf;
2137
        *s++ = 0;                                        /* Terminator for rounding and 0-triming. */
2138
        *s = '0';                                       /* Space to round. */
2139
 
2140
        i = 0;
2141
        e = s + nd + 1;
2142
        if (round < nd) {
2143
                e = s + round + 2;
2144
                if (*e >= '0' + (base/2)) {     /* NOTE: We always round away from 0! */
2145
                        i = 1;
2146
                }
2147
        }
2148
 
2149
        do {                                            /* Handle rounding and trim trailing 0s. */
2150
                *--e += i;                              /* Add the carry. */
2151
        } while ((*e == '0') || (*e > '0' - 1 + base));
2152
 
2153
#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
2154
        if ((mode|0x20) == 'a') {
2155
                char *q;
2156
 
2157
                for (q = e ; *q ; --q) {
2158
                        if (*q > '9') {
2159
                                *q += (*exp_buf - ('p' - 'a') - '9' - 1);
2160
                        }
2161
                }
2162
 
2163
                if (e > s) {
2164
                        exp *= 4;                       /* Change from base 16 to base 2. */
2165
                }
2166
        }
2167
#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
2168
 
2169
        o_exp = exp;
2170
        if (e <= s) {                           /* We carried into an extra digit. */
2171
                ++o_exp;
2172
                e = s;                                  /* Needed if all 0s. */
2173
        } else {
2174
                ++s;
2175
        }
2176
        *++e = 0;                                        /* Terminating nul char. */
2177
 
2178
        if ((mode == 'g') && ((o_exp >= -4) && (o_exp <= round))) {
2179
                mode = 'f';
2180
                preci = round - o_exp;
2181
        }
2182
 
2183
        exp = o_exp;
2184
        if (mode != 'f') {
2185
                o_exp = 0;
2186
        }
2187
 
2188
        if (o_exp < 0) {                 /* Exponent is < 0, so */
2189
                *--s = '0';                             /* fake the first 0 digit. */
2190
        }
2191
 
2192
        pc_fwi[3] = FPO_ZERO_PAD;
2193
        pc_fwi[4] = 1;
2194
        pc_fwi[5] = (intptr_t)(sign_str + 4);
2195
        sign_str[4] = *s++;
2196
        sign_str[5] = 0;
2197
        ppc = pc_fwi + 6;
2198
 
2199
        i = e - s;                                      /* Total digits is 'i'. */
2200
        if (o_exp >= 0) {
2201
#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
2202
 
2203
                const char *p;
2204
 
2205
                if (PRINT_INFO_FLAG_VAL(info,group)
2206
                        && *(p = __UCLIBC_CURLOCALE_DATA.grouping)
2207
                        ) {
2208
                        int nblk1;
2209
 
2210
                        nblk2 = nblk1 = *p;
2211
                        if (*++p) {
2212
                                nblk2 = *p;
2213
                                assert(!*++p);
2214
                        }
2215
 
2216
                        if (o_exp >= nblk1) {
2217
                                num_groups = (o_exp - nblk1) / nblk2 + 1;
2218
                                initial_group = (o_exp - nblk1) % nblk2;
2219
 
2220
#ifdef __UCLIBC_HAS_WCHAR__
2221
                                if (PRINT_INFO_FLAG_VAL(info,wide)) {
2222
                                        /* _fp_out_wide() will fix this up. */
2223
                                        ts = fmt + THOUSEP_OFFSET;
2224
                                        tslen = 1;
2225
                                } else {
2226
#endif /* __UCLIBC_HAS_WCHAR__ */
2227
                                        ts = __UCLIBC_CURLOCALE_DATA.thousands_sep;
2228
                                        tslen = __UCLIBC_CURLOCALE_DATA.thousands_sep_len;
2229
#ifdef __UCLIBC_HAS_WCHAR__
2230
                                }
2231
#endif /* __UCLIBC_HAS_WCHAR__ */
2232
 
2233
                                width -= num_groups * tslen;
2234
                        }
2235
                }
2236
 
2237
 
2238
#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
2239
                ppc[0] = FPO_STR_PREC;
2240
                ppc[2] = (intptr_t)(s);
2241
                if (o_exp >= i) {               /* all digit(s) left of decimal */
2242
                        ppc[1] = i;
2243
                        ppc += 3;
2244
                        o_exp -= i;
2245
                        i = 0;
2246
                        if (o_exp>0) {           /* have 0s left of decimal */
2247
                                ppc[0] = FPO_ZERO_PAD;
2248
                                ppc[1] = o_exp;
2249
                                ppc[2] = (intptr_t)(fmt + EMPTY_STRING_OFFSET);
2250
                                ppc += 3;
2251
                        }
2252
                } else if (o_exp > 0) {  /* decimal between digits */
2253
                        ppc[1] = o_exp;
2254
                        ppc += 3;
2255
                        s += o_exp;
2256
                        i -= o_exp;
2257
                }
2258
                o_exp = -1;
2259
        }
2260
 
2261
        if (PRINT_INFO_FLAG_VAL(info,alt)
2262
                || (i)
2263
                || ((o_mode != 'g')
2264
#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
2265
                        && (o_mode != 'a')
2266
#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
2267
                        && (preci > 0))
2268
                ) {
2269
                ppc[0] = FPO_STR_PREC;
2270
#ifdef __LOCALE_C_ONLY
2271
                ppc[1] = 1;
2272
                ppc[2] = (intptr_t)(fmt + DECPT_OFFSET);
2273
#else  /* __LOCALE_C_ONLY */
2274
#ifdef __UCLIBC_HAS_WCHAR__
2275
                        if (PRINT_INFO_FLAG_VAL(info,wide)) {
2276
                                /* _fp_out_wide() will fix this up. */
2277
                                ppc[1] = 1;
2278
                                ppc[2] = (intptr_t)(fmt + DECPT_OFFSET);
2279
                        } else {
2280
#endif /* __UCLIBC_HAS_WCHAR__ */
2281
                                ppc[1] = __UCLIBC_CURLOCALE_DATA.decimal_point_len;
2282
                                ppc[2] = (intptr_t)(__UCLIBC_CURLOCALE_DATA.decimal_point);
2283
#ifdef __UCLIBC_HAS_WCHAR__
2284
                        }
2285
#endif /* __UCLIBC_HAS_WCHAR__ */
2286
#endif /* __LOCALE_C_ONLY */
2287
                        ppc += 3;
2288
        }
2289
 
2290
        if (++o_exp < 0) {                       /* Have 0s right of decimal. */
2291
                ppc[0] = FPO_ZERO_PAD;
2292
                ppc[1] = -o_exp;
2293
                ppc[2] = (intptr_t)(fmt + EMPTY_STRING_OFFSET);
2294
                ppc += 3;
2295
        }
2296
        if (i) {                                        /* Have digit(s) right of decimal. */
2297
                ppc[0] = FPO_STR_PREC;
2298
                ppc[1] = i;
2299
                ppc[2] = (intptr_t)(s);
2300
                ppc += 3;
2301
        }
2302
 
2303
        if (((o_mode != 'g') || PRINT_INFO_FLAG_VAL(info,alt))
2304
#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
2305
                && !sufficient_precision
2306
#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
2307
                ) {
2308
                i -= o_exp;
2309
                if (i < preci) {                /* Have 0s right of digits. */
2310
                        i = preci - i;
2311
                        ppc[0] = FPO_ZERO_PAD;
2312
                        ppc[1] = i;
2313
                        ppc[2] = (intptr_t)(fmt + EMPTY_STRING_OFFSET);
2314
                        ppc += 3;
2315
                }
2316
        }
2317
 
2318
        /* Build exponent string. */
2319
        if (mode != 'f') {
2320
                char *p = exp_buf + sizeof(exp_buf);
2321
                char exp_char = *exp_buf;
2322
                char exp_sign = '+';
2323
#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
2324
                int min_exp_dig_plus_2 = ((o_mode != 'a') ? (2+2) : (2+1));
2325
#else  /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
2326
#define min_exp_dig_plus_2  (2+2)
2327
#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
2328
 
2329
                if (exp < 0) {
2330
                        exp_sign = '-';
2331
                        exp = -exp;
2332
                }
2333
 
2334
                *--p = 0;                        /* nul-terminate */
2335
                j = 2;                          /* Count exp_char and exp_sign. */
2336
                do {
2337
                        *--p = '0' + (exp % 10);
2338
                        exp /= 10;
2339
                } while ((++j < min_exp_dig_plus_2) || exp); /* char+sign+mindigits */
2340
                *--p = exp_sign;
2341
                *--p = exp_char;
2342
 
2343
                ppc[0] = FPO_STR_PREC;
2344
                ppc[1] = j;
2345
                ppc[2] = (intptr_t)(p);
2346
                ppc += 3;
2347
        }
2348
 
2349
 EXIT_SPECIAL:
2350
        ppc_last = ppc;
2351
        ppc = pc_fwi + 4;        /* Need width fields starting with second. */
2352
        do {
2353
                width -= *ppc;
2354
                ppc += 3;
2355
        } while (ppc < ppc_last);
2356
 
2357
        ppc = pc_fwi;
2358
        ppc[0] = FPO_STR_WIDTH;
2359
        ppc[1] = i = ((*sign_str) != 0);
2360
        ppc[2] = (intptr_t) sign_str;
2361
 
2362
#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
2363
        if (((mode|0x20) == 'a') && (pc_fwi[3] >= 16)) { /* Hex sign handling. */
2364
                /* Hex and not inf or nan, so prefix with 0x. */
2365
                char *h = sign_str + i;
2366
                *h = '0';
2367
                *++h = 'x' - 'p' + *exp_buf;
2368
                *++h = 0;
2369
                ppc[1] = (i += 2);
2370
        }
2371
#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
2372
 
2373
        if ((width -= i) > 0) {
2374
                if (PRINT_INFO_FLAG_VAL(info,left)) { /* Left-justified. */
2375
                        ppc_last[0] = FPO_STR_WIDTH;
2376
                        ppc_last[1] = width;
2377
                        ppc_last[2] = (intptr_t)(fmt + EMPTY_STRING_OFFSET);
2378
                        ppc_last += 3;
2379
                } else if (info->pad == '0') { /* 0 padding */
2380
                        ppc[4] += width;        /* Pad second field. */
2381
                } else {
2382
                        ppc[1] += width;        /* Pad first (sign) field. */
2383
                }
2384
        }
2385
 
2386
        cnt = 0;
2387
 
2388
        do {
2389
#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
2390
 
2391
                if ((ppc == pc_fwi + 6) && num_groups) {
2392
                        const char *gp = (const char *) ppc[2];
2393
                        int len = ppc[1];
2394
                        int blk = initial_group;
2395
 
2396
                        cnt += num_groups * tslen; /* Adjust count now for sep chars. */
2397
 
2398
/*                      printf("\n"); */
2399
                        do {
2400
                                if (!blk) {             /* Initial group could be 0 digits long! */
2401
                                        blk = nblk2;
2402
                                } else if (len >= blk) { /* Enough digits for a group. */
2403
/*                                      printf("norm:  len=%d blk=%d  \"%.*s\"\n", len, blk, blk, gp); */
2404
                                        fp_outfunc(fp, *ppc, blk, (intptr_t) gp);
2405
                                        assert(gp);
2406
                                        if (*gp) {
2407
                                                gp += blk;
2408
                                        }
2409
                                        len -= blk;
2410
                                } else {                /* Transition to 0s. */
2411
/*                                      printf("trans: len=%d blk=%d  \"%.*s\"\n", len, blk, len, gp); */
2412
                                        if (len) {
2413
/*                                              printf("len\n"); */
2414
                                                fp_outfunc(fp, *ppc, len, (intptr_t) gp);
2415
                                                gp += len;
2416
                                        }
2417
 
2418
                                        if (ppc[3] == FPO_ZERO_PAD) { /* Need to group 0s */
2419
/*                                              printf("zeropad\n"); */
2420
                                                cnt += ppc[1];
2421
                                                ppc += 3;
2422
                                                gp = (const char *) ppc[2];
2423
                                                blk -= len;     /* blk > len, so blk still > 0. */
2424
                                                len = ppc[1];
2425
                                                continue; /* Don't decrement num_groups here. */
2426
                                        } else {
2427
                                                assert(num_groups == 0);
2428
                                                break;
2429
                                        }
2430
                                }
2431
 
2432
                                if (num_groups <= 0) {
2433
                                        break;
2434
                                }
2435
                                --num_groups;
2436
 
2437
                                fp_outfunc(fp, FPO_STR_PREC, tslen, (intptr_t) ts);
2438
                                blk = nblk2;
2439
 
2440
/*                              printf("num_groups=%d   blk=%d\n", num_groups, blk); */
2441
 
2442
                        } while (1);
2443
                } else
2444
 
2445
#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
2446
 
2447
                fp_outfunc(fp, *ppc, ppc[1], ppc[2]); /* NOTE: Remember 'else' above! */
2448
 
2449
                cnt += ppc[1];
2450
                ppc += 3;
2451
        } while (ppc < ppc_last);
2452
 
2453
        return cnt;
2454
}
2455
 
2456
#endif
2457
/**********************************************************************/
2458
#ifdef L__store_inttype
2459
 
2460
/* Right now, we assume intmax_t is either long or long long */
2461
 
2462
#ifdef INTMAX_MAX
2463
 
2464
#ifdef LLONG_MAX
2465
 
2466
#if INTMAX_MAX > LLONG_MAX
2467
#error INTMAX_MAX > LLONG_MAX!  The printf code needs to be updated!
2468
#endif
2469
 
2470
#elif INTMAX_MAX > LONG_MAX
2471
 
2472
#error No LLONG_MAX and INTMAX_MAX > LONG_MAX!  The printf code needs to be updated!
2473
 
2474
#endif /* LLONG_MAX */
2475
 
2476
#endif /* INTMAX_MAX */
2477
 
2478
/* We assume int may be short or long, but short and long are different. */
2479
 
2480
void _store_inttype(register void *dest, int desttype, uintmax_t val)
2481
{
2482
        if (desttype == __PA_FLAG_CHAR) { /* assume char not int */
2483
                *((unsigned char *) dest) = val;
2484
                return;
2485
        }
2486
#if defined(LLONG_MAX) && (LONG_MAX != LLONG_MAX)
2487
        if (desttype == PA_FLAG_LONG_LONG) {
2488
                *((unsigned long long int *) dest) = val;
2489
                return;
2490
        }
2491
#endif /* LLONG_MAX */
2492
#if SHRT_MAX != INT_MAX
2493
        if (desttype == PA_FLAG_SHORT) {
2494
                *((unsigned short int *) dest) = val;
2495
                return;
2496
        }
2497
#endif /* SHRT_MAX */
2498
#if LONG_MAX != INT_MAX
2499
        if (desttype == PA_FLAG_LONG) {
2500
                *((unsigned long int *) dest) = val;
2501
                return;
2502
        }
2503
#endif /* LONG_MAX */
2504
 
2505
        *((unsigned int *) dest) = val;
2506
}
2507
 
2508
#endif
2509
/**********************************************************************/
2510
#ifdef L__load_inttype
2511
 
2512
extern uintmax_t _load_inttype(int desttype, register const void *src,
2513
                                                           int uflag)
2514
{
2515
        if (uflag >= 0) {                        /* unsigned */
2516
#if LONG_MAX != INT_MAX
2517
                if (desttype & (PA_FLAG_LONG|PA_FLAG_LONG_LONG)) {
2518
#ifdef LLONG_MAX
2519
                        if (desttype == PA_FLAG_LONG_LONG) {
2520
                                return *((unsigned long long int *) src);
2521
                        }
2522
#endif
2523
                        return *((unsigned long int *) src);
2524
                }
2525
#else  /* LONG_MAX != INT_MAX */
2526
#ifdef LLONG_MAX
2527
                if (desttype & PA_FLAG_LONG_LONG) {
2528
                        return *((unsigned long long int *) src);
2529
                }
2530
#endif
2531
#endif /* LONG_MAX != INT_MAX */
2532
                {
2533
                        unsigned int x;
2534
                        x = *((unsigned int *) src);
2535
                        if (desttype == __PA_FLAG_CHAR) x = (unsigned char) x;
2536
#if SHRT_MAX != INT_MAX
2537
                        if (desttype == PA_FLAG_SHORT) x = (unsigned short int) x;
2538
#endif
2539
                        return x;
2540
                }
2541
        } else {                                        /* signed */
2542
#if LONG_MAX != INT_MAX
2543
                if (desttype & (PA_FLAG_LONG|PA_FLAG_LONG_LONG)) {
2544
#ifdef LLONG_MAX
2545
                        if (desttype == PA_FLAG_LONG_LONG) {
2546
                                return *((long long int *) src);
2547
                        }
2548
#endif
2549
                        return *((long int *) src);
2550
                }
2551
#else  /* LONG_MAX != INT_MAX */
2552
#ifdef LLONG_MAX
2553
                if (desttype & PA_FLAG_LONG_LONG) {
2554
                        return *((long long int *) src);
2555
                }
2556
#endif
2557
#endif /* LONG_MAX != INT_MAX */
2558
                {
2559
                        int x;
2560
                        x = *((int *) src);
2561
                        if (desttype == __PA_FLAG_CHAR) x = (char) x;
2562
#if SHRT_MAX != INT_MAX
2563
                        if (desttype == PA_FLAG_SHORT) x = (short int) x;
2564
#endif
2565
                        return x;
2566
                }
2567
        }
2568
}
2569
 
2570
#endif
2571
/**********************************************************************/
2572
#if defined(L_vfprintf) || defined(L_vfwprintf)
2573
 
2574
/* We only support ascii digits (or their USC equivalent codes) in
2575
 * precision and width settings in *printf (wide) format strings.
2576
 * In other words, we don't currently support glibc's 'I' flag.
2577
 * We do accept it, but it is currently ignored. */
2578
 
2579
static void _charpad(FILE * __restrict stream, int padchar, size_t numpad);
2580
 
2581
#ifdef L_vfprintf
2582
 
2583
#define VFPRINTF vfprintf
2584
#define FMT_TYPE char
2585
#define OUTNSTR _outnstr
2586
#define STRLEN  strlen
2587
#define _PPFS_init _ppfs_init
2588
#define OUTPUT(F,S)                     fputs(S,F)
2589
#define _outnstr(stream, string, len)   _stdio_fwrite(string, len, stream)
2590
#define FP_OUT _fp_out_narrow
2591
 
2592
#ifdef __STDIO_PRINTF_FLOAT
2593
 
2594
static void _fp_out_narrow(FILE *fp, intptr_t type, intptr_t len, intptr_t buf)
2595
{
2596
        if (type & 0x80) {                      /* Some type of padding needed. */
2597
                int buflen = strlen((const char *) buf);
2598
                if ((len -= buflen) > 0) {
2599
                        _charpad(fp, (type & 0x7f), len);
2600
                }
2601
                len = buflen;
2602
        }
2603
        OUTNSTR(fp, (const char *) buf, len);
2604
}
2605
 
2606
#endif /* __STDIO_PRINTF_FLOAT */
2607
 
2608
#else  /* L_vfprintf */
2609
 
2610
#define VFPRINTF vfwprintf
2611
#define FMT_TYPE wchar_t
2612
#define OUTNSTR _outnwcs
2613
#define STRLEN  wcslen
2614
#define _PPFS_init _ppwfs_init
2615
#define OUTPUT(F,S)                     fputws(S,F)
2616
#define _outnwcs(stream, wstring, len)  _wstdio_fwrite(wstring, len, stream)
2617
#define FP_OUT _fp_out_wide
2618
 
2619
static void _outnstr(FILE *stream, const char *s, size_t wclen)
2620
{
2621
        /* NOTE!!! len here is the number of wchars we want to generate!!! */
2622
        wchar_t wbuf[64];
2623
        mbstate_t mbstate;
2624
        size_t todo, r;
2625
 
2626
        mbstate.mask = 0;
2627
        todo = wclen;
2628
 
2629
        while (todo) {
2630
                r = mbsrtowcs(wbuf, &s,
2631
                                          ((todo <= sizeof(wbuf)/sizeof(wbuf[0]))
2632
                                           ? todo
2633
                                           : sizeof(wbuf)/sizeof(wbuf[0])),
2634
                                          &mbstate);
2635
                assert(((ssize_t)r) > 0);
2636
                _outnwcs(stream, wbuf, r);
2637
                todo -= r;
2638
        }
2639
}
2640
 
2641
#ifdef __STDIO_PRINTF_FLOAT
2642
 
2643
#ifdef __UCLIBC_MJN3_ONLY__
2644
#warning TODO: Move defines from _fpmaxtostr.  Put them in a common header.
2645
#endif
2646
 
2647
/* The following defines are from _fpmaxtostr.*/
2648
#define DIGITS_PER_BLOCK     9
2649
#define NUM_DIGIT_BLOCKS   ((DECIMAL_DIG+DIGITS_PER_BLOCK-1)/DIGITS_PER_BLOCK)
2650
#define BUF_SIZE  ( 3 + NUM_DIGIT_BLOCKS * DIGITS_PER_BLOCK )
2651
 
2652
static void _fp_out_wide(FILE *fp, intptr_t type, intptr_t len, intptr_t buf)
2653
{
2654
        wchar_t wbuf[BUF_SIZE];
2655
        const char *s = (const char *) buf;
2656
        int i;
2657
 
2658
        if (type & 0x80) {                      /* Some type of padding needed */
2659
                int buflen = strlen(s);
2660
                if ((len -= buflen) > 0) {
2661
                        _charpad(fp, (type & 0x7f), len);
2662
                }
2663
                len = buflen;
2664
        }
2665
 
2666
        if (len > 0) {
2667
                i = 0;
2668
                do {
2669
#ifdef __LOCALE_C_ONLY
2670
                        wbuf[i] = s[i];
2671
#else  /* __LOCALE_C_ONLY */
2672
 
2673
#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
2674
                        if (s[i] == ',') {
2675
                                wbuf[i] = __UCLIBC_CURLOCALE_DATA.thousands_sep_wc;
2676
                        } else
2677
#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
2678
                        if (s[i] == '.') {
2679
                                wbuf[i] = __UCLIBC_CURLOCALE_DATA.decimal_point_wc;
2680
                        } else {
2681
                                wbuf[i] = s[i];
2682
                        }
2683
#endif /* __LOCALE_C_ONLY */
2684
 
2685
                } while (++i < len);
2686
 
2687
                OUTNSTR(fp, wbuf, len);
2688
        }
2689
}
2690
 
2691
#endif /* __STDIO_PRINTF_FLOAT */
2692
 
2693
static int _ppwfs_init(register ppfs_t *ppfs, const wchar_t *fmt0)
2694
{
2695
        static const wchar_t invalid_wcs[] = L"Invalid wide format string.";
2696
        int r;
2697
 
2698
        /* First, zero out everything... argnumber[], argtype[], argptr[] */
2699
        memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */
2700
#ifdef NL_ARGMAX
2701
        --ppfs->maxposarg;                      /* set to -1 */
2702
#endif /* NL_ARGMAX */
2703
        ppfs->fmtpos = (const char *) fmt0;
2704
        ppfs->info._flags = FLAG_WIDESTREAM;
2705
 
2706
        {
2707
                mbstate_t mbstate;
2708
                const wchar_t *p;
2709
                mbstate.mask = 0;        /* Initialize the mbstate. */
2710
                p = fmt0;
2711
                if (wcsrtombs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) {
2712
                        ppfs->fmtpos = (const char *) invalid_wcs;
2713
                        return -1;
2714
                }
2715
        }
2716
 
2717
        /* now set all argtypes to no-arg */
2718
        {
2719
#if 1
2720
                /* TODO - use memset here since already "paid for"? */
2721
                register int *p = ppfs->argtype;
2722
 
2723
                r = MAX_ARGS;
2724
                do {
2725
                        *p++ = __PA_NOARG;
2726
                } while (--r);
2727
#else
2728
                /* TODO -- get rid of this?? */
2729
                register char *p = (char *) ((MAX_ARGS-1) * sizeof(int));
2730
 
2731
                do {
2732
                        *((int *)(((char *)ppfs) + ((int)p) + offsetof(ppfs_t,argtype))) = __PA_NOARG;
2733
                        p -= sizeof(int);
2734
                } while (p);
2735
#endif
2736
        }
2737
 
2738
        /*
2739
         * Run through the entire format string to validate it and initialize
2740
         * the positional arg numbers (if any).
2741
         */
2742
        {
2743
                register const wchar_t *fmt = fmt0;
2744
 
2745
                while (*fmt) {
2746
                        if ((*fmt == '%') && (*++fmt != '%')) {
2747
                                ppfs->fmtpos = (const char *) fmt; /* back up to the '%' */
2748
                                if ((r = _ppfs_parsespec(ppfs)) < 0) {
2749
                                        return -1;
2750
                                }
2751
                                fmt = (const wchar_t *) ppfs->fmtpos; /* update to one past end of spec */
2752
                        } else {
2753
                                ++fmt;
2754
                        }
2755
                }
2756
                ppfs->fmtpos = (const char *) fmt0; /* rewind */
2757
        }
2758
 
2759
#ifdef NL_ARGMAX
2760
        /* If we have positional args, make sure we know all the types. */
2761
        {
2762
                register int *p = ppfs->argtype;
2763
                r = ppfs->maxposarg;
2764
                while (--r >= 0) {
2765
                        if ( *p == __PA_NOARG ) { /* missing arg type!!! */
2766
                                return -1;
2767
                        }
2768
                        ++p;
2769
                }
2770
        }
2771
#endif /* NL_ARGMAX */
2772
 
2773
        return 0;
2774
}
2775
 
2776
#endif /* L_vfprintf */
2777
 
2778
static void _charpad(FILE * __restrict stream, int padchar, size_t numpad)
2779
{
2780
        /* TODO -- Use a buffer to cut down on function calls... */
2781
        FMT_TYPE pad[1];
2782
 
2783
        *pad = padchar;
2784
        while (numpad) {
2785
                OUTNSTR(stream, pad, 1);
2786
                --numpad;
2787
        }
2788
}
2789
 
2790
/* TODO -- Dynamically allocate work space to accomodate stack-poor archs? */
2791
static int _do_one_spec(FILE * __restrict stream,
2792
                                                 register ppfs_t *ppfs, int *count)
2793
{
2794
        static const char spec_base[] = SPEC_BASE;
2795
#ifdef L_vfprintf
2796
        static const char prefix[] = "+\0-\0 \0000x\0000X";
2797
        /*                            0  2  4  6   9 11*/
2798
#else  /* L_vfprintf */
2799
        static const wchar_t prefix[] = L"+\0-\0 \0000x\0000X";
2800
#endif /* L_vfprintf */
2801
        enum {
2802
                PREFIX_PLUS = 0,
2803
                PREFIX_MINUS = 2,
2804
                PREFIX_SPACE = 4,
2805
                PREFIX_LWR_X = 6,
2806
                PREFIX_UPR_X = 9,
2807
                PREFIX_NONE = 11
2808
        };
2809
 
2810
#ifdef __va_arg_ptr
2811
        const void * const *argptr;
2812
#else
2813
        const void * argptr[MAX_ARGS_PER_SPEC];
2814
#endif
2815
        int *argtype;
2816
#ifdef __UCLIBC_HAS_WCHAR__
2817
        const wchar_t *ws = NULL;
2818
        mbstate_t mbstate;
2819
#endif /* __UCLIBC_HAS_WCHAR__ */
2820
        size_t slen;
2821
#ifdef L_vfprintf
2822
#define SLEN slen
2823
#else
2824
        size_t SLEN;
2825
        wchar_t wbuf[2];
2826
#endif
2827
        int base;
2828
        int numpad;
2829
        int alphacase;
2830
        int numfill = 0;                 /* TODO: fix */
2831
        int prefix_num = PREFIX_NONE;
2832
        char padchar = ' ';
2833
#ifdef __UCLIBC_MJN3_ONLY__
2834
#warning TODO: Determine appropriate buf size.
2835
#endif /* __UCLIBC_MJN3_ONLY__ */
2836
        /* TODO: buf needs to be big enough for any possible error return strings
2837
         * and also for any locale-grouped long long integer strings generated.
2838
         * This should be large enough for any of the current archs/locales, but
2839
         * eventually this should be handled robustly. */
2840
        char buf[128];
2841
 
2842
#ifdef NDEBUG
2843
        _ppfs_parsespec(ppfs);
2844
#else
2845
        if (_ppfs_parsespec(ppfs) < 0) { /* TODO: just for debugging */
2846
                abort();
2847
        }
2848
#endif
2849
        _ppfs_setargs(ppfs);
2850
 
2851
        argtype = ppfs->argtype + ppfs->argnumber[2] - 1;
2852
        /* Deal with the argptr vs argvalue issue. */
2853
#ifdef __va_arg_ptr
2854
        argptr = (const void * const *) ppfs->argptr;
2855
#ifdef NL_ARGMAX
2856
        if (ppfs->maxposarg > 0) {       /* Using positional args... */
2857
                argptr += ppfs->argnumber[2] - 1;
2858
        }
2859
#endif /* NL_ARGMAX */
2860
#else
2861
        /* Need to build a local copy... */
2862
        {
2863
                register argvalue_t *p = ppfs->argvalue;
2864
                int i;
2865
#ifdef NL_ARGMAX
2866
                if (ppfs->maxposarg > 0) {       /* Using positional args... */
2867
                        p += ppfs->argnumber[2] - 1;
2868
                }
2869
#endif /* NL_ARGMAX */
2870
                for (i = 0 ; i < ppfs->num_data_args ; i++ ) {
2871
                        argptr[i] = (void *) p++;
2872
                }
2873
        }
2874
#endif
2875
        {
2876
                register char *s = NULL; /* TODO: Should s be unsigned char * ? */
2877
 
2878
                if (ppfs->conv_num == CONV_n) {
2879
                        _store_inttype(*(void **)*argptr,
2880
                                                   ppfs->info._flags & __PA_INTMASK,
2881
                                                   (intmax_t) (*count));
2882
                        return 0;
2883
                }
2884
                if (ppfs->conv_num <= CONV_i) { /* pointer or (un)signed int */
2885
                        alphacase = __UIM_LOWER;
2886
 
2887
#ifdef __UCLIBC_MJN3_ONLY__
2888
#ifdef L_vfprintf
2889
#warning CONSIDER: Should we ignore these flags if stub locale?  What about custom specs?
2890
#endif
2891
#endif /* __UCLIBC_MJN3_ONLY__ */
2892
                        if ((base = spec_base[(int)(ppfs->conv_num - CONV_p)]) == 10) {
2893
                                if (PRINT_INFO_FLAG_VAL(&(ppfs->info),group)) {
2894
                                        alphacase = __UIM_GROUP;
2895
                                }
2896
                                if (PRINT_INFO_FLAG_VAL(&(ppfs->info),i18n)) {
2897
                                        alphacase |= 0x80;
2898
                                }
2899
                        }
2900
 
2901
                        if (ppfs->conv_num <= CONV_u) { /* pointer or unsigned int */
2902
                                if (ppfs->conv_num == CONV_X) {
2903
                                        alphacase = __UIM_UPPER;
2904
                                }
2905
                                if (ppfs->conv_num == CONV_p) { /* pointer */
2906
                                        prefix_num = PREFIX_LWR_X;
2907
                                } else {                /* unsigned int */
2908
                                }
2909
                        } else {                        /* signed int */
2910
                                base = -base;
2911
                        }
2912
                        if (ppfs->info.prec < 0) { /* Ignore '0' flag if prec specified. */
2913
                                padchar = ppfs->info.pad;
2914
                        }
2915
#ifdef __UCLIBC_MJN3_ONLY__
2916
#ifdef L_vfprintf
2917
#warning CONSIDER: If using outdigits and/or grouping, how should we interpret precision?
2918
#endif
2919
#endif /* __UCLIBC_MJN3_ONLY__ */
2920
                        s = _uintmaxtostr(buf + sizeof(buf) - 1,
2921
                                                          (uintmax_t)
2922
                                                          _load_inttype(*argtype & __PA_INTMASK,
2923
                                                                                        *argptr, base), base, alphacase);
2924
                        if (ppfs->conv_num > CONV_u) { /* signed int */
2925
                                if (*s == '-') {
2926
                                        PRINT_INFO_SET_FLAG(&(ppfs->info),showsign);
2927
                                        ++s;            /* handle '-' in the prefix string */
2928
                                        prefix_num = PREFIX_MINUS;
2929
                                } else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),showsign)) {
2930
                                        prefix_num = PREFIX_PLUS;
2931
                                } else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),space)) {
2932
                                        prefix_num = PREFIX_SPACE;
2933
                                }
2934
                        }
2935
                        slen = (char *)(buf + sizeof(buf) - 1) - s;
2936
#ifdef L_vfwprintf
2937
                        {
2938
                                const char *q = s;
2939
                                mbstate.mask = 0; /* Initialize the mbstate. */
2940
                                SLEN = mbsrtowcs(NULL, &q, 0, &mbstate);
2941
                        }
2942
#endif
2943
                        numfill = ((ppfs->info.prec < 0) ? 1 : ppfs->info.prec);
2944
                        if (PRINT_INFO_FLAG_VAL(&(ppfs->info),alt)) {
2945
                                if (ppfs->conv_num <= CONV_x) { /* x or p */
2946
                                        prefix_num = PREFIX_LWR_X;
2947
                                }
2948
                                if (ppfs->conv_num == CONV_X) {
2949
                                        prefix_num = PREFIX_UPR_X;
2950
                                }
2951
                                if ((ppfs->conv_num == CONV_o) && (numfill <= SLEN)) {
2952
                                        numfill = ((*s == '0') ? 1 : SLEN + 1);
2953
                                }
2954
                        }
2955
                        if (*s == '0') {
2956
                                if (prefix_num >= PREFIX_LWR_X) {
2957
                                        prefix_num = PREFIX_NONE;
2958
                                }
2959
                                if (ppfs->conv_num == CONV_p) {/* null pointer */
2960
                                        s = "(nil)";
2961
#ifdef L_vfwprintf
2962
                                        SLEN =
2963
#endif
2964
                                        slen = 5;
2965
                                        numfill = 0;
2966
                                } else if (numfill == 0) {       /* if precision 0, no output */
2967
#ifdef L_vfwprintf
2968
                                        SLEN =
2969
#endif
2970
                                        slen = 0;
2971
                                }
2972
                        }
2973
                        numfill = ((numfill > SLEN) ? numfill - SLEN : 0);
2974
                } else if (ppfs->conv_num <= CONV_A) {  /* floating point */
2975
#ifdef __STDIO_PRINTF_FLOAT
2976
                        *count +=
2977
                                _fpmaxtostr(stream,
2978
                                                        (__fpmax_t)
2979
                                                        (PRINT_INFO_FLAG_VAL(&(ppfs->info),is_long_double)
2980
                                                         ? *(long double *) *argptr
2981
                                                         : (long double) (* (double *) *argptr)),
2982
                                                        &ppfs->info, FP_OUT );
2983
                        return 0;
2984
#else  /* __STDIO_PRINTF_FLOAT */
2985
                        return -1;                      /* TODO -- try to continue? */
2986
#endif /* __STDIO_PRINTF_FLOAT */
2987
                } else if (ppfs->conv_num <= CONV_S) {  /* wide char or string */
2988
#ifdef L_vfprintf
2989
 
2990
#ifdef __UCLIBC_HAS_WCHAR__
2991
                        mbstate.mask = 0;        /* Initialize the mbstate. */
2992
                        if (ppfs->conv_num == CONV_S) { /* wide string */
2993
                                if (!(ws = *((const wchar_t **) *argptr))) {
2994
                                        goto NULL_STRING;
2995
                                }
2996
                                /* We use an awful uClibc-specific hack here, passing
2997
                                 * (char*) &ws as the conversion destination.  This signals
2998
                                 * uClibc's wcsrtombs that we want a "restricted" length
2999
                                 * such that the mbs fits in a buffer of the specified
3000
                                 * size with no partial conversions. */
3001
                                if ((slen = wcsrtombs((char *) &ws, &ws, /* Use awful hack! */
3002
                                                                          ((ppfs->info.prec >= 0)
3003
                                                                           ? ppfs->info.prec
3004
                                                                           : SIZE_MAX), &mbstate))
3005
                                        == ((size_t)-1)
3006
                                        ) {
3007
                                        return -1;      /* EILSEQ */
3008
                                }
3009
                        } else {                        /* wide char */
3010
                                s = buf;
3011
                                slen = wcrtomb(s, (*((const wchar_t *) *argptr)), &mbstate);
3012
                                if (slen == ((size_t)-1)) {
3013
                                        return -1;      /* EILSEQ */
3014
                                }
3015
                                s[slen] = 0;     /* TODO - Is this necessary? */
3016
                        }
3017
#else  /* __UCLIBC_HAS_WCHAR__ */
3018
                        return -1;
3019
#endif /* __UCLIBC_HAS_WCHAR__ */
3020
                } else if (ppfs->conv_num <= CONV_s) {  /* char or string */
3021
                        if (ppfs->conv_num == CONV_s) { /* string */
3022
                                s = *((char **) (*argptr));
3023
                                if (s) {
3024
#ifdef __STDIO_PRINTF_M_SUPPORT
3025
                                SET_STRING_LEN:
3026
#endif
3027
                                        slen = strnlen(s, ((ppfs->info.prec >= 0)
3028
                                                                           ? ppfs->info.prec : SIZE_MAX));
3029
                                } else {
3030
#ifdef __UCLIBC_HAS_WCHAR__
3031
                                NULL_STRING:
3032
#endif
3033
                                        s = "(null)";
3034
                                        slen = 6;
3035
                                }
3036
                        } else {                        /* char */
3037
                                s = buf;
3038
                                *s = (unsigned char)(*((const int *) *argptr));
3039
                                s[1] = 0;
3040
                                slen = 1;
3041
                        }
3042
 
3043
#else  /* L_vfprintf */
3044
 
3045
                        if (ppfs->conv_num == CONV_S) { /* wide string */
3046
                                ws = *((wchar_t **) (*argptr));
3047
                                if (!ws) {
3048
                                        goto NULL_STRING;
3049
                                }
3050
                                SLEN = wcsnlen(ws, ((ppfs->info.prec >= 0)
3051
                                                                        ? ppfs->info.prec : SIZE_MAX));
3052
                        } else {                        /* wide char */
3053
                                *wbuf = (wchar_t)(*((const wint_t *) *argptr));
3054
                        CHAR_CASE:
3055
                                ws = wbuf;
3056
                                wbuf[1] = 0;
3057
                                SLEN = 1;
3058
                        }
3059
 
3060
                } else if (ppfs->conv_num <= CONV_s) {  /* char or string */
3061
 
3062
                        if (ppfs->conv_num == CONV_s) { /* string */
3063
#ifdef __UCLIBC_MJN3_ONLY__
3064
#warning TODO: Fix %s for vfwprintf... output upto illegal sequence?
3065
#endif /* __UCLIBC_MJN3_ONLY__ */
3066
                                s = *((char **) (*argptr));
3067
                                if (s) {
3068
#ifdef __STDIO_PRINTF_M_SUPPORT
3069
                                SET_STRING_LEN:
3070
#endif
3071
                                        /* We use an awful uClibc-specific hack here, passing
3072
                                         * (wchar_t*) &mbstate as the conversion destination.
3073
                                         *  This signals uClibc's mbsrtowcs that we want a
3074
                                         * "restricted" length such that the mbs fits in a buffer
3075
                                         * of the specified size with no partial conversions. */
3076
                                        {
3077
                                                const char *q = s;
3078
                                                mbstate.mask = 0;        /* Initialize the mbstate. */
3079
                                                SLEN = mbsrtowcs((wchar_t *) &mbstate, &q,
3080
                                                                                 ((ppfs->info.prec >= 0)
3081
                                                                                  ? ppfs->info.prec : SIZE_MAX),
3082
                                                                                 &mbstate);
3083
                                        }
3084
                                        if (SLEN == ((size_t)(-1))) {
3085
                                                return -1;      /* EILSEQ */
3086
                                        }
3087
                                } else {
3088
                                NULL_STRING:
3089
                                        s = "(null)";
3090
                                        SLEN = slen = 6;
3091
                                }
3092
                        } else {                        /* char */
3093
                                *wbuf = btowc( (unsigned char)(*((const int *) *argptr)) );
3094
                                goto CHAR_CASE;
3095
                        }
3096
 
3097
#endif /* L_vfprintf */
3098
 
3099
#ifdef __STDIO_PRINTF_M_SUPPORT
3100
                } else if (ppfs->conv_num == CONV_m) {
3101
                        s = _glibc_strerror_r(errno, buf, sizeof(buf));
3102
                        goto SET_STRING_LEN;
3103
#endif
3104
                } else {
3105
#ifdef __STDIO_GLIBC_CUSTOM_PRINTF
3106
                        assert(ppfs->conv_num == CONV_custom0);
3107
 
3108
                        s = _custom_printf_spec;
3109
                        do {
3110
                                if (*s == ppfs->info.spec) {
3111
                                        int rv;
3112
                                        /* TODO -- check return value for sanity? */
3113
                                        rv = (*_custom_printf_handler
3114
                                                  [(int)(s-_custom_printf_spec)])
3115
                                                (stream, &ppfs->info, argptr);
3116
                                        if (rv < 0) {
3117
                                                return -1;
3118
                                        }
3119
                                        *count += rv;
3120
                                        return 0;
3121
                                }
3122
                        } while (++s < (_custom_printf_spec + MAX_USER_SPEC));
3123
#endif /* __STDIO_GLIBC_CUSTOM_PRINTF */
3124
                        assert(0);
3125
                        return -1;
3126
                }
3127
 
3128
#ifdef __UCLIBC_MJN3_ONLY__
3129
#ifdef L_vfprintf
3130
#warning CONSIDER: If using outdigits and/or grouping, how should we pad?
3131
#endif
3132
#endif /* __UCLIBC_MJN3_ONLY__ */
3133
                {
3134
                        size_t t;
3135
 
3136
                        t = SLEN + numfill;
3137
                        if (prefix_num != PREFIX_NONE) {
3138
                                t += ((prefix_num < PREFIX_LWR_X) ? 1 : 2);
3139
                        }
3140
                        numpad = ((ppfs->info.width > t) ? (ppfs->info.width - t) : 0);
3141
                        *count += t + numpad;
3142
                }
3143
                if (padchar == '0') { /* TODO: check this */
3144
                        numfill += numpad;
3145
                        numpad = 0;
3146
                }
3147
 
3148
                /* Now handle the output itself. */
3149
                if (!PRINT_INFO_FLAG_VAL(&(ppfs->info),left)) {
3150
                        _charpad(stream, ' ', numpad);
3151
                        numpad = 0;
3152
                }
3153
                OUTPUT(stream, prefix + prefix_num);
3154
                _charpad(stream, '0', numfill);
3155
 
3156
#ifdef L_vfprintf
3157
 
3158
#ifdef __UCLIBC_HAS_WCHAR__
3159
                if (!ws) {
3160
                        assert(s);
3161
                        _outnstr(stream, s, slen);
3162
                } else {                                /* wide string */
3163
                        size_t t;
3164
                        mbstate.mask = 0;        /* Initialize the mbstate. */
3165
                        while (slen) {
3166
                                t = (slen <= sizeof(buf)) ? slen : sizeof(buf);
3167
                                t = wcsrtombs(buf, &ws, t, &mbstate);
3168
                                assert (t != ((size_t)(-1)));
3169
                                _outnstr(stream, buf, t);
3170
                                slen -= t;
3171
                        }
3172
                }
3173
#else  /* __UCLIBC_HAS_WCHAR__ */
3174
                _outnstr(stream, s, slen);
3175
#endif /* __UCLIBC_HAS_WCHAR__ */
3176
 
3177
#else  /* L_vfprintf */
3178
 
3179
                if (!ws) {
3180
                        assert(s);
3181
                        _outnstr(stream, s, SLEN);
3182
                } else {
3183
                        _outnwcs(stream, ws, SLEN);
3184
                }
3185
 
3186
#endif /* L_vfprintf */
3187
                _charpad(stream, ' ', numpad);
3188
        }
3189
 
3190
        return 0;
3191
}
3192
 
3193
int VFPRINTF (FILE * __restrict stream,
3194
                          register const FMT_TYPE * __restrict format,
3195
                          va_list arg)
3196
{
3197
        ppfs_t ppfs;
3198
        int count, r;
3199
        register const FMT_TYPE *s;
3200
 
3201
        __STDIO_THREADLOCK(stream);
3202
 
3203
        count = 0;
3204
        s = format;
3205
 
3206
#if defined(L_vfprintf) && defined(__UCLIBC_HAS_WCHAR__)
3207
        /* Sigh... I forgot that by calling _stdio_fwrite, vfprintf doesn't
3208
         * always check the stream's orientation.  This is just a temporary
3209
         * fix until I rewrite the stdio core work routines. */
3210
        if (stream->modeflags & __FLAG_WIDE) {
3211
                stream->modeflags |= __FLAG_ERROR;
3212
                count = -1;
3213
                goto DONE;
3214
        }
3215
        stream->modeflags |= __FLAG_NARROW;
3216
#endif
3217
 
3218
        if (_PPFS_init(&ppfs, format) < 0) { /* Bad format string. */
3219
                OUTNSTR(stream, (const FMT_TYPE *) ppfs.fmtpos,
3220
                                STRLEN((const FMT_TYPE *)(ppfs.fmtpos)));
3221
#if defined(L_vfprintf) && !defined(NDEBUG)
3222
                fprintf(stderr,"\nIMbS: \"%s\"\n\n", format);
3223
#endif
3224
                count = -1;
3225
        } else {
3226
                _ppfs_prepargs(&ppfs, arg);     /* This did a va_copy!!! */
3227
 
3228
                do {
3229
                        while (*format && (*format != '%')) {
3230
                                ++format;
3231
                        }
3232
 
3233
                        if (format-s) {         /* output any literal text in format string */
3234
                                if ( (r = OUTNSTR(stream, s, format-s)) < 0) {
3235
                                        count = -1;
3236
                                        break;
3237
                                }
3238
                                count += r;
3239
                        }
3240
 
3241
                        if (!*format) {                 /* we're done */
3242
                                break;
3243
                        }
3244
 
3245
                        if (format[1] != '%') { /* if we get here, *format == '%' */
3246
                                /* TODO: _do_one_spec needs to know what the output funcs are!!! */
3247
                                ppfs.fmtpos = (const char *)(++format);
3248
                                /* TODO: check -- should only fail on stream error */
3249
                                if ( (r = _do_one_spec(stream, &ppfs, &count)) < 0) {
3250
                                        count = -1;
3251
                                        break;
3252
                                }
3253
                                s = format = (const FMT_TYPE *) ppfs.fmtpos;
3254
                        } else {                        /* %% means literal %, so start new string */
3255
                                s = ++format;
3256
                                ++format;
3257
                        }
3258
                } while (1);
3259
 
3260
                va_end(ppfs.arg);               /* Need to clean up after va_copy! */
3261
        }
3262
 
3263
#if defined(L_vfprintf) && defined(__UCLIBC_HAS_WCHAR__)
3264
 DONE:
3265
#endif
3266
 
3267
        __STDIO_THREADUNLOCK(stream);
3268
 
3269
        return count;
3270
}
3271
#endif
3272
/**********************************************************************/

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.