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

Subversion Repositories openrisc

[/] [openrisc/] [tags/] [gnu-src/] [newlib-1.18.0/] [newlib-1.18.0-or32-1.0rc2/] [newlib/] [libc/] [stdio/] [vfwprintf.c] - Blame information for rev 520

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 207 jeremybenn
/*
2
 * Copyright (c) 1990 The Regents of the University of California.
3
 * All rights reserved.
4
 *
5
 * This code is derived from software contributed to Berkeley by
6
 * Chris Torek.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 4. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
 
33
/*
34
FUNCTION
35
<<vfwprintf>>, <<vwprintf>>, <<vswprintf>>---wide character format argument list
36
 
37
INDEX
38
        vfwprintf
39
INDEX
40
        _vfwprintf_r
41
INDEX
42
        vwprintf
43
INDEX
44
        _vwprintf_r
45
INDEX
46
        vswprintf
47
INDEX
48
        _vswprintf_r
49
 
50
ANSI_SYNOPSIS
51
        #include <stdio.h>
52
        #include <stdarg.h>
53
        #include <wchar.h>
54
        int vwprintf(const wchar_t *<[fmt]>, va_list <[list]>);
55
        int vfwprintf(FILE *<[fp]>, const wchar_t *<[fmt]>, va_list <[list]>);
56
        int vswprintf(wchar_t *<[str]>, size_t <[size]>, const wchar_t *<[fmt]>,
57
                        va_list <[list]>);
58
 
59
        int _vwprintf_r(struct _reent *<[reent]>, const wchar_t *<[fmt]>,
60
                va_list <[list]>);
61
        int _vfwprintf_r(struct _reent *<[reent]>, FILE *<[fp]>,
62
                const wchar_t *<[fmt]>, va_list <[list]>);
63
        int _vswprintf_r(struct _reent *<[reent]>, wchar_t *<[str]>,
64
                size_t <[size]>, const wchar_t *<[fmt]>, va_list <[list]>);
65
 
66
DESCRIPTION
67
<<vwprintf>>, <<vfwprintf>> and <<vswprintf>> are (respectively) variants
68
of <<wprintf>>, <<fwprintf>> and <<swprintf>>.  They differ only in allowing
69
their caller to pass the variable argument list as a <<va_list>> object
70
(initialized by <<va_start>>) rather than directly accepting a variable
71
number of arguments.  The caller is responsible for calling <<va_end>>.
72
 
73
<<_vwprintf_r>>, <<_vfwprintf_r>> and <<_vswprintf_r>> are reentrant
74
versions of the above.
75
 
76
RETURNS
77
The return values are consistent with the corresponding functions.
78
 
79
PORTABILITY
80
POSIX-1.2008 with extensions; C99 (compliant except for POSIX extensions).
81
 
82
Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
83
<<lseek>>, <<read>>, <<sbrk>>, <<write>>.
84
 
85
SEEALSO
86
<<wprintf>>, <<fwprintf>> and <<swprintf>>.
87
*/
88
 
89
/*
90
 * Actual wprintf innards.
91
 *
92
 * This code is large and complicated...
93
 */
94
#include <newlib.h>
95
 
96
#ifdef INTEGER_ONLY
97
# define VFWPRINTF vfiwprintf
98
# ifdef STRING_ONLY
99
#   define _VFWPRINTF_R _svfiwprintf_r
100
# else
101
#   define _VFWPRINTF_R _vfiwprintf_r
102
# endif
103
#else
104
# define VFWPRINTF vfwprintf
105
# ifdef STRING_ONLY
106
#   define _VFWPRINTF_R _svfwprintf_r
107
# else
108
#   define _VFWPRINTF_R _vfwprintf_r
109
# endif
110
# ifndef NO_FLOATING_POINT
111
#  define FLOATING_POINT
112
# endif
113
#endif
114
 
115
#define _NO_POS_ARGS
116
#ifdef _WANT_IO_POS_ARGS
117
# undef _NO_POS_ARGS
118
#endif
119
 
120
#include <_ansi.h>
121
#include <reent.h>
122
#include <stdio.h>
123
#include <stdlib.h>
124
#include <string.h>
125
#include <limits.h>
126
#include <stdint.h>
127
#include <wchar.h>
128
#include <sys/lock.h>
129
#include <stdarg.h>
130
#include "local.h"
131
#include "fvwrite.h"
132
#include "vfieeefp.h"
133
 
134
/* Currently a test is made to see if long double processing is warranted.
135
   This could be changed in the future should the _ldtoa_r code be
136
   preferred over _dtoa_r.  */
137
#define _NO_LONGDBL
138
#if defined _WANT_IO_LONG_DOUBLE && (LDBL_MANT_DIG > DBL_MANT_DIG)
139
#undef _NO_LONGDBL
140
#endif
141
 
142
#define _NO_LONGLONG
143
#if defined _WANT_IO_LONG_LONG \
144
        && (defined __GNUC__ || __STDC_VERSION__ >= 199901L)
145
# undef _NO_LONGLONG
146
#endif
147
 
148
int _EXFUN(_VFWPRINTF_R, (struct _reent *, FILE *, _CONST wchar_t *, va_list));
149
/* Defined in vfprintf.c. */
150
#ifdef STRING_ONLY
151
#define __SPRINT __ssprint_r
152
#else
153
#define __SPRINT __sprint_r
154
#endif
155
int _EXFUN(__SPRINT, (struct _reent *, FILE *, register struct __suio *));
156
 
157
#ifndef STRING_ONLY
158
/*
159
 * Helper function for `fprintf to unbuffered unix file': creates a
160
 * temporary buffer.  We only work on write-only files; this avoids
161
 * worries about ungetc buffers and so forth.
162
 */
163
static int
164
_DEFUN(__sbwprintf, (rptr, fp, fmt, ap),
165
       struct _reent *rptr _AND
166
       register FILE *fp   _AND
167
       _CONST wchar_t *fmt  _AND
168
       va_list ap)
169
{
170
        int ret;
171
        FILE fake;
172
        unsigned char buf[BUFSIZ];
173
 
174
        /* copy the important variables */
175
        fake._flags = fp->_flags & ~__SNBF;
176
        fake._flags2 = fp->_flags2;
177
        fake._file = fp->_file;
178
        fake._cookie = fp->_cookie;
179
        fake._write = fp->_write;
180
 
181
        /* set up the buffer */
182
        fake._bf._base = fake._p = buf;
183
        fake._bf._size = fake._w = sizeof (buf);
184
        fake._lbfsize = 0;       /* not actually used, but Just In Case */
185
#ifndef __SINGLE_THREAD__
186
        __lock_init_recursive (fake._lock);
187
#endif
188
 
189
        /* do the work, then copy any error status */
190
        ret = _VFWPRINTF_R (rptr, &fake, fmt, ap);
191
        if (ret >= 0 && _fflush_r (rptr, &fake))
192
                ret = EOF;
193
        if (fake._flags & __SERR)
194
                fp->_flags |= __SERR;
195
 
196
#ifndef __SINGLE_THREAD__
197
        __lock_close_recursive (fake._lock);
198
#endif
199
        return (ret);
200
}
201
#endif /* !STRING_ONLY */
202
 
203
 
204
#ifdef FLOATING_POINT
205
# include <locale.h>
206
# include <math.h>
207
 
208
/* For %La, an exponent of 15 bits occupies the exponent character, a
209
   sign, and up to 5 digits.  */
210
# define MAXEXPLEN              7
211
# define DEFPREC                6
212
 
213
# ifdef _NO_LONGDBL
214
 
215
extern char *_dtoa_r _PARAMS((struct _reent *, double, int,
216
                              int, int *, int *, char **));
217
 
218
#  define _PRINTF_FLOAT_TYPE double
219
#  define _DTOA_R _dtoa_r
220
#  define FREXP frexp
221
 
222
# else /* !_NO_LONGDBL */
223
 
224
extern char *_ldtoa_r _PARAMS((struct _reent *, _LONG_DOUBLE, int,
225
                              int, int *, int *, char **));
226
 
227
extern int _EXFUN(_ldcheck,(_LONG_DOUBLE *));
228
 
229
#  define _PRINTF_FLOAT_TYPE _LONG_DOUBLE
230
#  define _DTOA_R _ldtoa_r
231
/* FIXME - frexpl is not yet supported; and cvt infloops if (double)f
232
   converts a finite value into infinity.  */
233
/* #  define FREXP frexpl */
234
#  define FREXP(f,e) ((_LONG_DOUBLE) frexp ((double)f, e))
235
# endif /* !_NO_LONGDBL */
236
 
237
static wchar_t *wcvt(struct _reent *, _PRINTF_FLOAT_TYPE, int, int, wchar_t *,
238
                    int *, int, int *, wchar_t *);
239
 
240
static int wexponent(wchar_t *, int, int);
241
 
242
#endif /* FLOATING_POINT */
243
 
244
/* BUF must be big enough for the maximum %#llo (assuming long long is
245
   at most 64 bits, this would be 23 characters), the maximum
246
   multibyte character %C, and the maximum default precision of %La
247
   (assuming long double is at most 128 bits with 113 bits of
248
   mantissa, this would be 29 characters).  %e, %f, and %g use
249
   reentrant storage shared with mprec.  All other formats that use
250
   buf get by with fewer characters.  Making BUF slightly bigger
251
   reduces the need for malloc in %.*a and %ls/%S, when large precision or
252
   long strings are processed.  */
253
#define BUF             40
254
#if defined _MB_CAPABLE && MB_LEN_MAX > BUF
255
# undef BUF
256
# define BUF MB_LEN_MAX
257
#endif
258
 
259
#ifndef _NO_LONGLONG
260
# define quad_t long long
261
# define u_quad_t unsigned long long
262
#else
263
# define quad_t long
264
# define u_quad_t unsigned long
265
#endif
266
 
267
typedef quad_t * quad_ptr_t;
268
typedef _PTR     void_ptr_t;
269
typedef char *   char_ptr_t;
270
typedef wchar_t* wchar_ptr_t;
271
typedef long *   long_ptr_t;
272
typedef int  *   int_ptr_t;
273
typedef short *  short_ptr_t;
274
 
275
#ifndef _NO_POS_ARGS
276
# ifdef NL_ARGMAX
277
#  define MAX_POS_ARGS NL_ARGMAX
278
# else
279
#  define MAX_POS_ARGS 32
280
# endif
281
 
282
union arg_val
283
{
284
  int val_int;
285
  u_int val_u_int;
286
  long val_long;
287
  u_long val_u_long;
288
  float val_float;
289
  double val_double;
290
  _LONG_DOUBLE val__LONG_DOUBLE;
291
  int_ptr_t val_int_ptr_t;
292
  short_ptr_t val_short_ptr_t;
293
  long_ptr_t val_long_ptr_t;
294
  char_ptr_t val_char_ptr_t;
295
  wchar_ptr_t val_wchar_ptr_t;
296
  quad_ptr_t val_quad_ptr_t;
297
  void_ptr_t val_void_ptr_t;
298
  quad_t val_quad_t;
299
  u_quad_t val_u_quad_t;
300
  wint_t val_wint_t;
301
};
302
 
303
static union arg_val *
304
_EXFUN(get_arg, (struct _reent *data, int n, wchar_t *fmt,
305
                 va_list *ap, int *numargs, union arg_val *args,
306
                 int *arg_type, wchar_t **last_fmt));
307
#endif /* !_NO_POS_ARGS */
308
 
309
/*
310
 * Macros for converting digits to letters and vice versa
311
 */
312
#define to_digit(c)     ((c) - L'0')
313
#define is_digit(c)     ((unsigned)to_digit (c) <= 9)
314
#define to_char(n)      ((n) + L'0')
315
 
316
/*
317
 * Flags used during conversion.
318
 */
319
#define ALT             0x001           /* alternate form */
320
#define HEXPREFIX       0x002           /* add 0x or 0X prefix */
321
#define LADJUST         0x004           /* left adjustment */
322
#define LONGDBL         0x008           /* long double */
323
#define LONGINT         0x010           /* long integer */
324
#ifndef _NO_LONGLONG
325
# define QUADINT        0x020           /* quad integer */
326
#else /* ifdef _NO_LONGLONG, make QUADINT equivalent to LONGINT, so
327
         that %lld behaves the same as %ld, not as %d, as expected if:
328
         sizeof (long long) = sizeof long > sizeof int  */
329
# define QUADINT        LONGINT
330
#endif
331
#define SHORTINT        0x040           /* short integer */
332
#define ZEROPAD         0x080           /* zero (as opposed to blank) pad */
333
#define FPT             0x100           /* Floating point number */
334
#ifdef _WANT_IO_C99_FORMATS
335
# define CHARINT        0x200           /* char as integer */
336
#else /* define as 0, to make SARG and UARG occupy fewer instructions  */
337
# define CHARINT        0
338
#endif
339
 
340
#ifndef STRING_ONLY
341
int
342
_DEFUN(VFWPRINTF, (fp, fmt0, ap),
343
       FILE * fp         _AND
344
       _CONST wchar_t *fmt0 _AND
345
       va_list ap)
346
{
347
  int result;
348
  result = _VFWPRINTF_R (_REENT, fp, fmt0, ap);
349
  return result;
350
}
351
#endif /* STRING_ONLY */
352
 
353
int
354
_DEFUN(_VFWPRINTF_R, (data, fp, fmt0, ap),
355
       struct _reent *data _AND
356
       FILE * fp           _AND
357
       _CONST wchar_t *fmt0   _AND
358
       va_list ap)
359
{
360
        register wchar_t *fmt;  /* format string */
361
        register wint_t ch;     /* character from fmt */
362
        register int n, m;      /* handy integers (short term usage) */
363
        register wchar_t *cp;   /* handy char pointer (short term usage) */
364
        register struct __siov *iovp;/* for PRINT macro */
365
        register int flags;     /* flags as above */
366
        wchar_t *fmt_anchor;    /* current format spec being processed */
367
#ifndef _NO_POS_ARGS
368
        int N;                  /* arg number */
369
        int arg_index;          /* index into args processed directly */
370
        int numargs;            /* number of varargs read */
371
        wchar_t *saved_fmt;     /* saved fmt pointer */
372
        union arg_val args[MAX_POS_ARGS];
373
        int arg_type[MAX_POS_ARGS];
374
        int is_pos_arg;         /* is current format positional? */
375
        int old_is_pos_arg;     /* is current format positional? */
376
#endif
377
        int ret;                /* return value accumulator */
378
        int width;              /* width from format (%8d), or 0 */
379
        int prec;               /* precision from format (%.3d), or -1 */
380
        wchar_t sign;           /* sign prefix (' ', '+', '-', or \0) */
381
#ifdef FLOATING_POINT
382
        wchar_t decimal_point;
383
#ifdef _MB_CAPABLE
384
        mbstate_t state;        /* mbtowc calls from library must not change state */
385
#endif
386
        wchar_t softsign;               /* temporary negative sign for floats */
387
        union { int i; _PRINTF_FLOAT_TYPE fp; } _double_ = {0};
388
# define _fpvalue (_double_.fp)
389
        int expt;               /* integer value of exponent */
390
        int expsize = 0; /* character count for expstr */
391
        int ndig = 0;            /* actual number of digits returned by wcvt */
392
        wchar_t expstr[MAXEXPLEN];      /* buffer for exponent string */
393
#endif /* FLOATING_POINT */
394
        u_quad_t _uquad;        /* integer arguments %[diouxX] */
395
        enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
396
        int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
397
        int realsz;             /* field size expanded by dprec */
398
        int size = 0;            /* size of converted field or string */
399
        wchar_t *xdigs = NULL;  /* digits for [xX] conversion */
400
#define NIOV 8
401
        struct __suio uio;      /* output information: summary */
402
        struct __siov iov[NIOV];/* ... and individual io vectors */
403
        wchar_t buf[BUF];       /* space for %c, %ls/%S, %[diouxX], %[aA] */
404
        wchar_t ox[2];          /* space for 0x hex-prefix */
405
        wchar_t *malloc_buf = NULL;/* handy pointer for malloced buffers */
406
 
407
        /*
408
         * Choose PADSIZE to trade efficiency vs. size.  If larger printf
409
         * fields occur frequently, increase PADSIZE and make the initialisers
410
         * below longer.
411
         */
412
#define PADSIZE 16              /* pad chunk size */
413
        static _CONST wchar_t blanks[PADSIZE] =
414
         {L' ',L' ',L' ',L' ',L' ',L' ',L' ',L' ',
415
          L' ',L' ',L' ',L' ',L' ',L' ',L' ',L' '};
416
        static _CONST wchar_t zeroes[PADSIZE] =
417
         {L'0',L'0',L'0',L'0',L'0',L'0',L'0',L'0',
418
          L'0',L'0',L'0',L'0',L'0',L'0',L'0',L'0'};
419
 
420
#ifdef FLOATING_POINT
421
#ifdef _MB_CAPABLE
422
        memset (&state, '\0', sizeof (state));
423
        _mbrtowc_r (data, &decimal_point, _localeconv_r (data)->decimal_point,
424
                    MB_CUR_MAX, &state);
425
#else
426
        decimal_point = (wchar_t) *_localeconv_r (data)->decimal_point;
427
#endif
428
#endif
429
        /*
430
         * BEWARE, these `goto error' on error, and PAD uses `n'.
431
         */
432
#define PRINT(ptr, len) { \
433
        iovp->iov_base = (char *) (ptr); \
434
        iovp->iov_len = (len) * sizeof (wchar_t); \
435
        uio.uio_resid += (len) * sizeof (wchar_t); \
436
        iovp++; \
437
        if (++uio.uio_iovcnt >= NIOV) { \
438
                if (__SPRINT(data, fp, &uio)) \
439
                        goto error; \
440
                iovp = iov; \
441
        } \
442
}
443
#define PAD(howmany, with) { \
444
        if ((n = (howmany)) > 0) { \
445
                while (n > PADSIZE) { \
446
                        PRINT (with, PADSIZE); \
447
                        n -= PADSIZE; \
448
                } \
449
                PRINT (with, n); \
450
        } \
451
}
452
#define FLUSH() { \
453
        if (uio.uio_resid && __SPRINT(data, fp, &uio)) \
454
                goto error; \
455
        uio.uio_iovcnt = 0; \
456
        iovp = iov; \
457
}
458
 
459
        /* Macros to support positional arguments */
460
#ifndef _NO_POS_ARGS
461
# define GET_ARG(n, ap, type)                                           \
462
        (is_pos_arg                                                     \
463
         ? (n < numargs                                                 \
464
            ? args[n].val_##type                                        \
465
            : get_arg (data, n, fmt_anchor, &ap, &numargs, args,        \
466
                       arg_type, &saved_fmt)->val_##type)               \
467
         : (arg_index++ < numargs                                       \
468
            ? args[n].val_##type                                        \
469
            : (numargs < MAX_POS_ARGS                                   \
470
               ? args[numargs++].val_##type = va_arg (ap, type)         \
471
               : va_arg (ap, type))))
472
#else
473
# define GET_ARG(n, ap, type) (va_arg (ap, type))
474
#endif
475
 
476
        /*
477
         * To extend shorts properly, we need both signed and unsigned
478
         * argument extraction methods.
479
         */
480
#ifndef _NO_LONGLONG
481
#define SARG() \
482
        (flags&QUADINT ? GET_ARG (N, ap, quad_t) : \
483
            flags&LONGINT ? GET_ARG (N, ap, long) : \
484
            flags&SHORTINT ? (long)(short)GET_ARG (N, ap, int) : \
485
            flags&CHARINT ? (long)(signed char)GET_ARG (N, ap, int) : \
486
            (long)GET_ARG (N, ap, int))
487
#define UARG() \
488
        (flags&QUADINT ? GET_ARG (N, ap, u_quad_t) : \
489
            flags&LONGINT ? GET_ARG (N, ap, u_long) : \
490
            flags&SHORTINT ? (u_long)(u_short)GET_ARG (N, ap, int) : \
491
            flags&CHARINT ? (u_long)(unsigned char)GET_ARG (N, ap, int) : \
492
            (u_long)GET_ARG (N, ap, u_int))
493
#else
494
#define SARG() \
495
        (flags&LONGINT ? GET_ARG (N, ap, long) : \
496
            flags&SHORTINT ? (long)(short)GET_ARG (N, ap, int) : \
497
            flags&CHARINT ? (long)(signed char)GET_ARG (N, ap, int) : \
498
            (long)GET_ARG (N, ap, int))
499
#define UARG() \
500
        (flags&LONGINT ? GET_ARG (N, ap, u_long) : \
501
            flags&SHORTINT ? (u_long)(u_short)GET_ARG (N, ap, int) : \
502
            flags&CHARINT ? (u_long)(unsigned char)GET_ARG (N, ap, int) : \
503
            (u_long)GET_ARG (N, ap, u_int))
504
#endif
505
 
506
#ifndef STRING_ONLY
507
        /* Initialize std streams if not dealing with sprintf family.  */
508
        CHECK_INIT (data, fp);
509
        _flockfile (fp);
510
 
511
        ORIENT(fp, 1);
512
 
513
        /* sorry, fwprintf(read_only_file, "") returns EOF, not 0 */
514
        if (cantwrite (data, fp)) {
515
                _funlockfile (fp);
516
                return (EOF);
517
        }
518
 
519
        /* optimise fwprintf(stderr) (and other unbuffered Unix files) */
520
        if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
521
            fp->_file >= 0) {
522
                _funlockfile (fp);
523
                return (__sbwprintf (data, fp, fmt0, ap));
524
        }
525
#else /* STRING_ONLY */
526
        /* Create initial buffer if we are called by asprintf family.  */
527
        if (fp->_flags & __SMBF && !fp->_bf._base)
528
        {
529
                fp->_bf._base = fp->_p = _malloc_r (data, 64);
530
                if (!fp->_p)
531
                {
532
                        data->_errno = ENOMEM;
533
                        return EOF;
534
                }
535
                fp->_bf._size = 64;
536
        }
537
#endif /* STRING_ONLY */
538
 
539
        fmt = (wchar_t *)fmt0;
540
        uio.uio_iov = iovp = iov;
541
        uio.uio_resid = 0;
542
        uio.uio_iovcnt = 0;
543
        ret = 0;
544
#ifndef _NO_POS_ARGS
545
        arg_index = 0;
546
        saved_fmt = NULL;
547
        arg_type[0] = -1;
548
        numargs = 0;
549
        is_pos_arg = 0;
550
#endif
551
 
552
        /*
553
         * Scan the format for conversions (`%' character).
554
         */
555
        for (;;) {
556
                cp = fmt;
557
                while (*fmt != L'\0' && *fmt != L'%')
558
                    ++fmt;
559
                if ((m = fmt - cp) != 0) {
560
                        PRINT (cp, m);
561
                        ret += m;
562
                }
563
                if (*fmt == L'\0')
564
                    goto done;
565
                fmt_anchor = fmt;
566
                fmt++;          /* skip over '%' */
567
 
568
                flags = 0;
569
                dprec = 0;
570
                width = 0;
571
                prec = -1;
572
                sign = L'\0';
573
#ifndef _NO_POS_ARGS
574
                N = arg_index;
575
                is_pos_arg = 0;
576
#endif
577
 
578
rflag:          ch = *fmt++;
579
reswitch:       switch (ch) {
580
#ifdef _WANT_IO_C99_FORMATS
581
                case L'\'':
582
                  /* The ' flag is required by POSIX, but not C99.
583
                     FIXME:  this flag is currently a no-op.  */
584
                  goto rflag;
585
#endif
586
                case L' ':
587
                        /*
588
                         * ``If the space and + flags both appear, the space
589
                         * flag will be ignored.''
590
                         *      -- ANSI X3J11
591
                         */
592
                        if (!sign)
593
                                sign = L' ';
594
                        goto rflag;
595
                case L'#':
596
                        flags |= ALT;
597
                        goto rflag;
598
                case L'*':
599
#ifndef _NO_POS_ARGS
600
                        /* we must check for positional arg used for dynamic width */
601
                        n = N;
602
                        old_is_pos_arg = is_pos_arg;
603
                        is_pos_arg = 0;
604
                        if (is_digit (*fmt)) {
605
                                wchar_t *old_fmt = fmt;
606
 
607
                                n = 0;
608
                                ch = *fmt++;
609
                                do {
610
                                        n = 10 * n + to_digit (ch);
611
                                        ch = *fmt++;
612
                                } while (is_digit (ch));
613
 
614
                                if (ch == L'$') {
615
                                        if (n <= MAX_POS_ARGS) {
616
                                                n -= 1;
617
                                                is_pos_arg = 1;
618
                                        }
619
                                        else
620
                                                goto error;
621
                                }
622
                                else {
623
                                        fmt = old_fmt;
624
                                        goto rflag;
625
                                }
626
                        }
627
#endif /* !_NO_POS_ARGS */
628
 
629
                        /*
630
                         * ``A negative field width argument is taken as a
631
                         * - flag followed by a positive field width.''
632
                         *      -- ANSI X3J11
633
                         * They don't exclude field widths read from args.
634
                         */
635
                        width = GET_ARG (n, ap, int);
636
#ifndef _NO_POS_ARGS
637
                        is_pos_arg = old_is_pos_arg;
638
#endif
639
                        if (width >= 0)
640
                                goto rflag;
641
                        width = -width;
642
                        /* FALLTHROUGH */
643
                case L'-':
644
                        flags |= LADJUST;
645
                        goto rflag;
646
                case L'+':
647
                        sign = L'+';
648
                        goto rflag;
649
                case L'.':
650
                        if ((ch = *fmt++) == L'*') {
651
#ifndef _NO_POS_ARGS
652
                                /* we must check for positional arg used for dynamic width */
653
                                n = N;
654
                                old_is_pos_arg = is_pos_arg;
655
                                is_pos_arg = 0;
656
                                if (is_digit (*fmt)) {
657
                                        wchar_t *old_fmt = fmt;
658
 
659
                                        n = 0;
660
                                        ch = *fmt++;
661
                                        do {
662
                                                n = 10 * n + to_digit (ch);
663
                                                ch = *fmt++;
664
                                        } while (is_digit (ch));
665
 
666
                                        if (ch == L'$') {
667
                                                if (n <= MAX_POS_ARGS) {
668
                                                        n -= 1;
669
                                                        is_pos_arg = 1;
670
                                                }
671
                                                else
672
                                                        goto error;
673
                                        }
674
                                        else {
675
                                                fmt = old_fmt;
676
                                                goto rflag;
677
                                        }
678
                                }
679
#endif /* !_NO_POS_ARGS */
680
                                prec = GET_ARG (n, ap, int);
681
#ifndef _NO_POS_ARGS
682
                                is_pos_arg = old_is_pos_arg;
683
#endif
684
                                if (prec < 0)
685
                                        prec = -1;
686
                                goto rflag;
687
                        }
688
                        n = 0;
689
                        while (is_digit (ch)) {
690
                                n = 10 * n + to_digit (ch);
691
                                ch = *fmt++;
692
                        }
693
                        prec = n < 0 ? -1 : n;
694
                        goto reswitch;
695
                case L'0':
696
                        /*
697
                         * ``Note that 0 is taken as a flag, not as the
698
                         * beginning of a field width.''
699
                         *      -- ANSI X3J11
700
                         */
701
                        flags |= ZEROPAD;
702
                        goto rflag;
703
                case L'1': case L'2': case L'3': case L'4':
704
                case L'5': case L'6': case L'7': case L'8': case L'9':
705
                        n = 0;
706
                        do {
707
                                n = 10 * n + to_digit (ch);
708
                                ch = *fmt++;
709
                        } while (is_digit (ch));
710
#ifndef _NO_POS_ARGS
711
                        if (ch == L'$') {
712
                                if (n <= MAX_POS_ARGS) {
713
                                        N = n - 1;
714
                                        is_pos_arg = 1;
715
                                        goto rflag;
716
                                }
717
                                else
718
                                        goto error;
719
                        }
720
#endif /* !_NO_POS_ARGS */
721
                        width = n;
722
                        goto reswitch;
723
#ifdef FLOATING_POINT
724
                case L'L':
725
                        flags |= LONGDBL;
726
                        goto rflag;
727
#endif
728
                case L'h':
729
#ifdef _WANT_IO_C99_FORMATS
730
                        if (*fmt == L'h') {
731
                                fmt++;
732
                                flags |= CHARINT;
733
                        } else
734
#endif
735
                                flags |= SHORTINT;
736
                        goto rflag;
737
                case L'l':
738
#if defined _WANT_IO_C99_FORMATS || !defined _NO_LONGLONG
739
                        if (*fmt == L'l') {
740
                                fmt++;
741
                                flags |= QUADINT;
742
                        } else
743
#endif
744
                                flags |= LONGINT;
745
                        goto rflag;
746
                case L'q': /* GNU extension */
747
                        flags |= QUADINT;
748
                        goto rflag;
749
#ifdef _WANT_IO_C99_FORMATS
750
                case L'j':
751
                  if (sizeof (intmax_t) == sizeof (long))
752
                    flags |= LONGINT;
753
                  else
754
                    flags |= QUADINT;
755
                  goto rflag;
756
                case L'z':
757
                  if (sizeof (size_t) < sizeof (int))
758
                    /* POSIX states size_t is 16 or more bits, as is short.  */
759
                    flags |= SHORTINT;
760
                  else if (sizeof (size_t) == sizeof (int))
761
                    /* no flag needed */;
762
                  else if (sizeof (size_t) <= sizeof (long))
763
                    flags |= LONGINT;
764
                  else
765
                    /* POSIX states that at least one programming
766
                       environment must support size_t no wider than
767
                       long, but that means other environments can
768
                       have size_t as wide as long long.  */
769
                    flags |= QUADINT;
770
                  goto rflag;
771
                case L't':
772
                  if (sizeof (ptrdiff_t) < sizeof (int))
773
                    /* POSIX states ptrdiff_t is 16 or more bits, as
774
                       is short.  */
775
                    flags |= SHORTINT;
776
                  else if (sizeof (ptrdiff_t) == sizeof (int))
777
                    /* no flag needed */;
778
                  else if (sizeof (ptrdiff_t) <= sizeof (long))
779
                    flags |= LONGINT;
780
                  else
781
                    /* POSIX states that at least one programming
782
                       environment must support ptrdiff_t no wider than
783
                       long, but that means other environments can
784
                       have ptrdiff_t as wide as long long.  */
785
                    flags |= QUADINT;
786
                  goto rflag;
787
                case L'C':      /* POSIX extension */
788
#endif /* _WANT_IO_C99_FORMATS */
789
                case L'c':
790
                        cp = buf;
791
                        if (ch == L'c' && !(flags & LONGINT)) {
792
                                wint_t wc = btowc ((int) GET_ARG (N, ap, int));
793
                                if (wc == WEOF) {
794
                                    fp->_flags |= __SERR;
795
                                    goto error;
796
                                }
797
                                cp[0] = (wchar_t) wc;
798
                        }
799
                        else
800
                        {
801
                                cp[0] = GET_ARG (N, ap, int);
802
                        }
803
                        cp[1] = L'\0';
804
                        size = 1;
805
                        sign = L'\0';
806
                        break;
807
                case L'd':
808
                case L'i':
809
                        _uquad = SARG ();
810
#ifndef _NO_LONGLONG
811
                        if ((quad_t)_uquad < 0)
812
#else
813
                        if ((long) _uquad < 0)
814
#endif
815
                        {
816
 
817
                                _uquad = -_uquad;
818
                                sign = L'-';
819
                        }
820
                        base = DEC;
821
                        goto number;
822
#ifdef FLOATING_POINT
823
# ifdef _WANT_IO_C99_FORMATS
824
                case L'a':
825
                case L'A':
826
                case L'F':
827
# endif
828
                case L'e':
829
                case L'E':
830
                case L'f':
831
                case L'g':
832
                case L'G':
833
# ifdef _NO_LONGDBL
834
                        if (flags & LONGDBL) {
835
                                _fpvalue = (double) GET_ARG (N, ap, _LONG_DOUBLE);
836
                        } else {
837
                                _fpvalue = GET_ARG (N, ap, double);
838
                        }
839
 
840
                        /* do this before tricky precision changes
841
 
842
                           If the output is infinite or NaN, leading
843
                           zeros are not permitted.  Otherwise, scanf
844
                           could not read what printf wrote.
845
                         */
846
                        if (isinf (_fpvalue)) {
847
                                if (_fpvalue < 0)
848
                                        sign = '-';
849
                                if (ch <= L'G') /* 'A', 'E', 'F', or 'G' */
850
                                        cp = L"INF";
851
                                else
852
                                        cp = L"inf";
853
                                size = 3;
854
                                flags &= ~ZEROPAD;
855
                                break;
856
                        }
857
                        if (isnan (_fpvalue)) {
858
                                if (ch <= L'G') /* 'A', 'E', 'F', or 'G' */
859
                                        cp = L"NAN";
860
                                else
861
                                        cp = L"nan";
862
                                size = 3;
863
                                flags &= ~ZEROPAD;
864
                                break;
865
                        }
866
 
867
# else /* !_NO_LONGDBL */
868
 
869
                        if (flags & LONGDBL) {
870
                                _fpvalue = GET_ARG (N, ap, _LONG_DOUBLE);
871
                        } else {
872
                                _fpvalue = (_LONG_DOUBLE)GET_ARG (N, ap, double);
873
                        }
874
 
875
                        /* do this before tricky precision changes */
876
                        expt = _ldcheck (&_fpvalue);
877
                        if (expt == 2) {
878
                                if (_fpvalue < 0)
879
                                        sign = L'-';
880
                                if (ch <= L'G') /* 'A', 'E', 'F', or 'G' */
881
                                        cp = L"INF";
882
                                else
883
                                        cp = L"inf";
884
                                size = 3;
885
                                flags &= ~ZEROPAD;
886
                                break;
887
                        }
888
                        if (expt == 1) {
889
                                if (ch <= L'G') /* 'A', 'E', 'F', or 'G' */
890
                                        cp = L"NAN";
891
                                else
892
                                        cp = L"nan";
893
                                size = 3;
894
                                flags &= ~ZEROPAD;
895
                                break;
896
                        }
897
# endif /* !_NO_LONGDBL */
898
 
899
                        cp = buf;
900
# ifdef _WANT_IO_C99_FORMATS
901
                        if (ch == L'a' || ch == L'A') {
902
                                ox[0] = L'0';
903
                                ox[1] = ch == L'a' ? L'x' : L'X';
904
                                flags |= HEXPREFIX;
905
                                if (prec >= BUF)
906
                                  {
907
                                    if ((malloc_buf =
908
                                         (wchar_t *)_malloc_r (data, (prec + 1) * sizeof (wchar_t)))
909
                                        == NULL)
910
                                      {
911
                                        fp->_flags |= __SERR;
912
                                        goto error;
913
                                      }
914
                                    cp = malloc_buf;
915
                                  }
916
                        } else
917
# endif /* _WANT_IO_C99_FORMATS */
918
                        if (prec == -1) {
919
                                prec = DEFPREC;
920
                        } else if ((ch == L'g' || ch == L'G') && prec == 0) {
921
                                prec = 1;
922
                        }
923
 
924
                        flags |= FPT;
925
 
926
                        cp = wcvt (data, _fpvalue, prec, flags, &softsign,
927
                                   &expt, ch, &ndig, cp);
928
 
929
                        if (ch == L'g' || ch == L'G') {
930
                                if (expt <= -4 || expt > prec)
931
                                        ch -= 2; /* 'e' or 'E' */
932
                                else
933
                                        ch = L'g';
934
                        }
935
# ifdef _WANT_IO_C99_FORMATS
936
                        else if (ch == L'F')
937
                                ch = L'f';
938
# endif
939
                        if (ch <= L'e') {       /* 'a', 'A', 'e', or 'E' fmt */
940
                                --expt;
941
                                expsize = wexponent (expstr, expt, ch);
942
                                size = expsize + ndig;
943
                                if (ndig > 1 || flags & ALT)
944
                                        ++size;
945
                        } else if (ch == L'f') {                /* f fmt */
946
                                if (expt > 0) {
947
                                        size = expt;
948
                                        if (prec || flags & ALT)
949
                                                size += prec + 1;
950
                                } else  /* "0.X" */
951
                                        size = (prec || flags & ALT)
952
                                                  ? prec + 2
953
                                                  : 1;
954
                        } else if (expt >= ndig) {      /* fixed g fmt */
955
                                size = expt;
956
                                if (flags & ALT)
957
                                        ++size;
958
                        } else
959
                                size = ndig + (expt > 0 ?
960
                                        1 : 2 - expt);
961
 
962
                        if (softsign)
963
                                sign = L'-';
964
                        break;
965
#endif /* FLOATING_POINT */
966
                case L'n':
967
#ifndef _NO_LONGLONG
968
                        if (flags & QUADINT)
969
                                *GET_ARG (N, ap, quad_ptr_t) = ret;
970
                        else
971
#endif
972
                        if (flags & LONGINT)
973
                                *GET_ARG (N, ap, long_ptr_t) = ret;
974
                        else if (flags & SHORTINT)
975
                                *GET_ARG (N, ap, short_ptr_t) = ret;
976
#ifdef _WANT_IO_C99_FORMATS
977
                        else if (flags & CHARINT)
978
                                *GET_ARG (N, ap, char_ptr_t) = ret;
979
#endif
980
                        else
981
                                *GET_ARG (N, ap, int_ptr_t) = ret;
982
                        continue;       /* no output */
983
                case L'o':
984
                        _uquad = UARG ();
985
                        base = OCT;
986
                        goto nosign;
987
                case L'p':
988
                        /*
989
                         * ``The argument shall be a pointer to void.  The
990
                         * value of the pointer is converted to a sequence
991
                         * of printable characters, in an implementation-
992
                         * defined manner.''
993
                         *      -- ANSI X3J11
994
                         */
995
                        /* NOSTRICT */
996
                        _uquad = (uintptr_t) GET_ARG (N, ap, void_ptr_t);
997
                        base = HEX;
998
                        xdigs = L"0123456789abcdef";
999
                        flags |= HEXPREFIX;
1000
                        ox[0] = L'0';
1001
                        ox[1] = ch = L'x';
1002
                        goto nosign;
1003
                case L's':
1004
#ifdef _WANT_IO_C99_FORMATS
1005
                case L'S':      /* POSIX extension */
1006
#endif
1007
                        sign = '\0';
1008
                        cp = GET_ARG (N, ap, wchar_ptr_t);
1009
#ifndef __OPTIMIZE_SIZE__
1010
                        /* Behavior is undefined if the user passed a
1011
                           NULL string when precision is not 0.
1012
                           However, if we are not optimizing for size,
1013
                           we might as well mirror glibc behavior.  */
1014
                        if (cp == NULL) {
1015
                                cp = L"(null)";
1016
                                size = ((unsigned) prec > 6U) ? 6 : prec;
1017
                        }
1018
                        else
1019
#endif /* __OPTIMIZE_SIZE__ */
1020
#ifdef _MB_CAPABLE
1021
                        if (ch == L's' && !(flags & LONGINT)) {
1022
                                char *arg = (char *) cp;
1023
                                size_t insize = 0, nchars = 0, nconv = 0;
1024
                                mbstate_t ps;
1025
                                wchar_t *p;
1026
 
1027
                                if (prec >= 0) {
1028
                                        char *p = arg;
1029
                                        memset ((_PTR)&ps, '\0', sizeof (mbstate_t));
1030
                                        while (nchars < (size_t)prec) {
1031
                                                nconv = mbrlen (p, MB_CUR_MAX, &ps);
1032
                                                if (nconv == 0 || nconv == (size_t)-1 ||
1033
                                                    nconv == (size_t)-2)
1034
                                                        break;
1035
                                                p += nconv;
1036
                                                ++nchars;
1037
                                                insize += nconv;
1038
                                        }
1039
                                        if (nconv == (size_t) -1 || nconv == (size_t) -2) {
1040
                                                fp->_flags |= __SERR;
1041
                                                goto error;
1042
                                        }
1043
                                } else
1044
                                        insize = strlen(arg);
1045
                                if (insize >= BUF) {
1046
                                    if ((malloc_buf = (wchar_t *) _malloc_r (data, (insize + 1) * sizeof (wchar_t)))
1047
                                                                == NULL) {
1048
                                                        fp->_flags |= __SERR;
1049
                                                        goto error;
1050
                                                }
1051
                                                cp = malloc_buf;
1052
                                } else
1053
                                        cp = buf;
1054
                                memset ((_PTR)&ps, '\0', sizeof (mbstate_t));
1055
                                p = cp;
1056
                                while (insize != 0) {
1057
                                        nconv = _mbrtowc_r (data, p, arg, insize, &ps);
1058
                                        if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2)
1059
                                                break;
1060
                                        ++p;
1061
                                        arg += nconv;
1062
                                        insize -= nconv;
1063
                                }
1064
                                if (nconv == (size_t) -1 || nconv == (size_t) -2) {
1065
                                        fp->_flags |= __SERR;
1066
                                        goto error;
1067
                                }
1068
                                *p = L'\0';
1069
                                size = p - cp;
1070
                        }
1071
                        else
1072
#endif /* _MB_CAPABLE */
1073
                        if (prec >= 0) {
1074
                                /*
1075
                                 * can't use wcslen; can only look for the
1076
                                 * NUL in the first `prec' characters, and
1077
                                 * strlen () will go further.
1078
                                 */
1079
                                wchar_t *p = wmemchr (cp, L'\0', prec);
1080
 
1081
                                if (p != NULL) {
1082
                                        size = p - cp;
1083
                                        if (size > prec)
1084
                                                size = prec;
1085
                                } else
1086
                                        size = prec;
1087
                        } else
1088
                                size = wcslen (cp);
1089
 
1090
                        break;
1091
                case L'u':
1092
                        _uquad = UARG ();
1093
                        base = DEC;
1094
                        goto nosign;
1095
                case L'X':
1096
                        xdigs = L"0123456789ABCDEF";
1097
                        goto hex;
1098
                case 'x':
1099
                        xdigs = L"0123456789abcdef";
1100
hex:                    _uquad = UARG ();
1101
                        base = HEX;
1102
                        /* leading 0x/X only if non-zero */
1103
                        if (flags & ALT && _uquad != 0) {
1104
                                ox[0] = L'0';
1105
                                ox[1] = ch;
1106
                                flags |= HEXPREFIX;
1107
                        }
1108
 
1109
                        /* unsigned conversions */
1110
nosign:                 sign = L'\0';
1111
                        /*
1112
                         * ``... diouXx conversions ... if a precision is
1113
                         * specified, the 0 flag will be ignored.''
1114
                         *      -- ANSI X3J11
1115
                         */
1116
number:                 if ((dprec = prec) >= 0)
1117
                                flags &= ~ZEROPAD;
1118
 
1119
                        /*
1120
                         * ``The result of converting a zero value with an
1121
                         * explicit precision of zero is no characters.''
1122
                         *      -- ANSI X3J11
1123
                         */
1124
                        cp = buf + BUF;
1125
                        if (_uquad != 0 || prec != 0) {
1126
                                /*
1127
                                 * Unsigned mod is hard, and unsigned mod
1128
                                 * by a constant is easier than that by
1129
                                 * a variable; hence this switch.
1130
                                 */
1131
                                switch (base) {
1132
                                case OCT:
1133
                                        do {
1134
                                                *--cp = to_char (_uquad & 7);
1135
                                                _uquad >>= 3;
1136
                                        } while (_uquad);
1137
                                        /* handle octal leading 0 */
1138
                                        if (flags & ALT && *cp != L'0')
1139
                                                *--cp = L'0';
1140
                                        break;
1141
 
1142
                                case DEC:
1143
                                        /* many numbers are 1 digit */
1144
                                        while (_uquad >= 10) {
1145
                                                *--cp = to_char (_uquad % 10);
1146
                                                _uquad /= 10;
1147
                                        }
1148
                                        *--cp = to_char (_uquad);
1149
                                        break;
1150
 
1151
                                case HEX:
1152
                                        do {
1153
                                                *--cp = xdigs[_uquad & 15];
1154
                                                _uquad >>= 4;
1155
                                        } while (_uquad);
1156
                                        break;
1157
 
1158
                                default:
1159
                                        cp = L"bug in vfprintf: bad base";
1160
                                        size = wcslen (cp);
1161
                                        goto skipsize;
1162
                                }
1163
                        }
1164
                       /*
1165
                        * ...result is to be converted to an 'alternate form'.
1166
                        * For o conversion, it increases the precision to force
1167
                        * the first digit of the result to be a zero."
1168
                        *     -- ANSI X3J11
1169
                        *
1170
                        * To demonstrate this case, compile and run:
1171
                        *    printf ("%#.0o",0);
1172
                        */
1173
                       else if (base == OCT && (flags & ALT))
1174
                         *--cp = L'0';
1175
 
1176
                        size = buf + BUF - cp;
1177
                skipsize:
1178
                        break;
1179
                default:        /* "%?" prints ?, unless ? is NUL */
1180
                        if (ch == L'\0')
1181
                                goto done;
1182
                        /* pretend it was %c with argument ch */
1183
                        cp = buf;
1184
                        *cp = ch;
1185
                        size = 1;
1186
                        sign = L'\0';
1187
                        break;
1188
                }
1189
 
1190
                /*
1191
                 * All reasonable formats wind up here.  At this point, `cp'
1192
                 * points to a string which (if not flags&LADJUST) should be
1193
                 * padded out to `width' places.  If flags&ZEROPAD, it should
1194
                 * first be prefixed by any sign or other prefix; otherwise,
1195
                 * it should be blank padded before the prefix is emitted.
1196
                 * After any left-hand padding and prefixing, emit zeroes
1197
                 * required by a decimal [diouxX] precision, then print the
1198
                 * string proper, then emit zeroes required by any leftover
1199
                 * floating precision; finally, if LADJUST, pad with blanks.
1200
                 * If flags&FPT, ch must be in [aAeEfg].
1201
                 *
1202
                 * Compute actual size, so we know how much to pad.
1203
                 * size excludes decimal prec; realsz includes it.
1204
                 */
1205
                realsz = dprec > size ? dprec : size;
1206
                if (sign)
1207
                        realsz++;
1208
                if (flags & HEXPREFIX)
1209
                        realsz+= 2;
1210
 
1211
                /* right-adjusting blank padding */
1212
                if ((flags & (LADJUST|ZEROPAD)) == 0)
1213
                        PAD (width - realsz, blanks);
1214
 
1215
                /* prefix */
1216
                if (sign)
1217
                        PRINT (&sign, 1);
1218
                if (flags & HEXPREFIX)
1219
                        PRINT (ox, 2);
1220
 
1221
                /* right-adjusting zero padding */
1222
                if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
1223
                        PAD (width - realsz, zeroes);
1224
 
1225
                /* leading zeroes from decimal precision */
1226
                PAD (dprec - size, zeroes);
1227
 
1228
                /* the string or number proper */
1229
#ifdef FLOATING_POINT
1230
                if ((flags & FPT) == 0) {
1231
                        PRINT (cp, size);
1232
                } else {        /* glue together f_p fragments */
1233
                        if (ch >= L'f') {       /* 'f' or 'g' */
1234
                                if (_fpvalue == 0) {
1235
                                        /* kludge for __dtoa irregularity */
1236
                                        PRINT (L"0", 1);
1237
                                        if (expt < ndig || flags & ALT) {
1238
                                                PRINT (&decimal_point, 1);
1239
                                                PAD (ndig - 1, zeroes);
1240
                                        }
1241
                                } else if (expt <= 0) {
1242
                                        PRINT (L"0", 1);
1243
                                        if (expt || ndig || flags & ALT) {
1244
                                                PRINT (&decimal_point, 1);
1245
                                                PAD (-expt, zeroes);
1246
                                                PRINT (cp, ndig);
1247
                                        }
1248
                                } else if (expt >= ndig) {
1249
                                        PRINT (cp, ndig);
1250
                                        PAD (expt - ndig, zeroes);
1251
                                        if (flags & ALT)
1252
                                                PRINT (&decimal_point, 1);
1253
                                } else {
1254
                                        PRINT (cp, expt);
1255
                                        cp += expt;
1256
                                        PRINT (&decimal_point, 1);
1257
                                        PRINT (cp, ndig - expt);
1258
                                }
1259
                        } else {        /* 'a', 'A', 'e', or 'E' */
1260
                                if (ndig > 1 || flags & ALT) {
1261
                                        PRINT (cp, 1);
1262
                                        cp++;
1263
                                        PRINT (&decimal_point, 1);
1264
                                        if (_fpvalue) {
1265
                                                PRINT (cp, ndig - 1);
1266
                                        } else  /* 0.[0..] */
1267
                                                /* __dtoa irregularity */
1268
                                                PAD (ndig - 1, zeroes);
1269
                                } else  /* XeYYY */
1270
                                        PRINT (cp, 1);
1271
                                PRINT (expstr, expsize);
1272
                        }
1273
                }
1274
#else /* !FLOATING_POINT */
1275
                PRINT (cp, size);
1276
#endif
1277
                /* left-adjusting padding (always blank) */
1278
                if (flags & LADJUST)
1279
                        PAD (width - realsz, blanks);
1280
 
1281
                /* finally, adjust ret */
1282
                ret += width > realsz ? width : realsz;
1283
 
1284
                FLUSH ();       /* copy out the I/O vectors */
1285
 
1286
                if (malloc_buf != NULL) {
1287
                        _free_r (data, malloc_buf);
1288
                        malloc_buf = NULL;
1289
                }
1290
        }
1291
done:
1292
        FLUSH ();
1293
error:
1294
        if (malloc_buf != NULL)
1295
                _free_r (data, malloc_buf);
1296
#ifndef STRING_ONLY
1297
        _funlockfile (fp);
1298
#endif
1299
        return (__sferror (fp) ? EOF : ret);
1300
        /* NOTREACHED */
1301
}
1302
 
1303
#ifdef FLOATING_POINT
1304
 
1305
/* Using reentrant DATA, convert finite VALUE into a string of digits
1306
   with no decimal point, using NDIGITS precision and FLAGS as guides
1307
   to whether trailing zeros must be included.  Set *SIGN to nonzero
1308
   if VALUE was negative.  Set *DECPT to the exponent plus one.  Set
1309
   *LENGTH to the length of the returned string.  CH must be one of
1310
   [aAeEfFgG]; if it is [aA], then the return string lives in BUF,
1311
   otherwise the return value shares the mprec reentrant storage.  */
1312
static wchar_t *
1313
wcvt(struct _reent *data, _PRINTF_FLOAT_TYPE value, int ndigits, int flags,
1314
     wchar_t *sign, int *decpt, int ch, int *length, wchar_t *buf)
1315
{
1316
        int mode, dsgn;
1317
# ifdef _NO_LONGDBL
1318
        union double_union tmp;
1319
 
1320
        tmp.d = value;
1321
        if (word0 (tmp) & Sign_bit) { /* this will check for < 0 and -0.0 */
1322
                value = -value;
1323
                *sign = L'-';
1324
        } else
1325
                *sign = L'\0';
1326
# else /* !_NO_LONGDBL */
1327
        union
1328
        {
1329
          struct ldieee ieee;
1330
          _LONG_DOUBLE val;
1331
        } ld;
1332
 
1333
        ld.val = value;
1334
        if (ld.ieee.sign) { /* this will check for < 0 and -0.0 */
1335
                value = -value;
1336
                *sign = L'-';
1337
        } else
1338
                *sign = L'\0';
1339
# endif /* !_NO_LONGDBL */
1340
 
1341
# ifdef _WANT_IO_C99_FORMATS
1342
        if (ch == L'a' || ch == L'A') {
1343
                wchar_t *digits, *bp, *rve;
1344
                /* This code assumes FLT_RADIX is a power of 2.  The initial
1345
                   division ensures the digit before the decimal will be less
1346
                   than FLT_RADIX (unless it is rounded later).  There is no
1347
                   loss of precision in these calculations.  */
1348
                value = FREXP (value, decpt) / 8;
1349
                if (!value)
1350
                        *decpt = 1;
1351
                digits = ch == L'a' ? L"0123456789abcdef" : L"0123456789ABCDEF";
1352
                bp = buf;
1353
                do {
1354
                        value *= 16;
1355
                        mode = (int) value;
1356
                        value -= mode;
1357
                        *bp++ = digits[mode];
1358
                } while (ndigits-- && value);
1359
                if (value > 0.5 || (value == 0.5 && mode & 1)) {
1360
                        /* round to even */
1361
                        rve = bp;
1362
                        while (*--rve == digits[0xf]) {
1363
                                *rve = L'0';
1364
                        }
1365
                        *rve = *rve == L'9' ? digits[0xa] : *rve + 1;
1366
                } else {
1367
                        while (ndigits-- >= 0) {
1368
                                *bp++ = L'0';
1369
                        }
1370
                }
1371
                *length = bp - buf;
1372
                return buf;
1373
        }
1374
# endif /* _WANT_IO_C99_FORMATS */
1375
        if (ch == L'f' || ch == L'F') {
1376
                mode = 3;               /* ndigits after the decimal point */
1377
        } else {
1378
                /* To obtain ndigits after the decimal point for the 'e'
1379
                 * and 'E' formats, round to ndigits + 1 significant
1380
                 * figures.
1381
                 */
1382
                if (ch == L'e' || ch == L'E') {
1383
                        ndigits++;
1384
                }
1385
                mode = 2;               /* ndigits significant digits */
1386
        }
1387
 
1388
        {
1389
          char *digits, *bp, *rve;
1390
#ifndef _MB_CAPABLE
1391
          int i;
1392
#endif
1393
 
1394
          digits = _DTOA_R (data, value, mode, ndigits, decpt, &dsgn, &rve);
1395
 
1396
          if ((ch != L'g' && ch != L'G') || flags & ALT) {      /* Print trailing zeros */
1397
                bp = digits + ndigits;
1398
                if (ch == L'f' || ch == L'F') {
1399
                        if (*digits == L'0' && value)
1400
                                *decpt = -ndigits + 1;
1401
                        bp += *decpt;
1402
                }
1403
                if (value == 0)  /* kludge for __dtoa irregularity */
1404
                        rve = bp;
1405
                while (rve < bp)
1406
                        *rve++ = '0';
1407
          }
1408
#ifdef _MB_CAPABLE
1409
          *length = _mbsnrtowcs_r (data, buf, (const char **) &digits,
1410
                                   rve - digits, BUF, NULL);
1411
#else
1412
          *length = rve - digits;
1413
          for (i = 0; i < *length && i < BUF; ++i)
1414
            buf[i] = (wchar_t) digits[i];
1415
#endif
1416
          return buf;
1417
        }
1418
}
1419
 
1420
static int
1421
wexponent(wchar_t *p0, int exp, int fmtch)
1422
{
1423
        register wchar_t *p, *t;
1424
        wchar_t expbuf[MAXEXPLEN];
1425
# ifdef _WANT_IO_C99_FORMATS
1426
        int isa = fmtch == L'a' || fmtch == L'A';
1427
# else
1428
#  define isa 0
1429
# endif
1430
 
1431
        p = p0;
1432
        *p++ = isa ? L'p' - L'a' + fmtch : fmtch;
1433
        if (exp < 0) {
1434
                exp = -exp;
1435
                *p++ = L'-';
1436
        }
1437
        else
1438
                *p++ = L'+';
1439
        t = expbuf + MAXEXPLEN;
1440
        if (exp > 9) {
1441
                do {
1442
                        *--t = to_char (exp % 10);
1443
                } while ((exp /= 10) > 9);
1444
                *--t = to_char (exp);
1445
                for (; t < expbuf + MAXEXPLEN; *p++ = *t++);
1446
        }
1447
        else {
1448
                if (!isa)
1449
                        *p++ = L'0';
1450
                *p++ = to_char (exp);
1451
        }
1452
        return (p - p0);
1453
}
1454
#endif /* FLOATING_POINT */
1455
 
1456
 
1457
#ifndef _NO_POS_ARGS
1458
 
1459
/* Positional argument support.
1460
   Written by Jeff Johnston
1461
 
1462
   Copyright (c) 2002 Red Hat Incorporated.
1463
   All rights reserved.
1464
 
1465
   Redistribution and use in source and binary forms, with or without
1466
   modification, are permitted provided that the following conditions are met:
1467
 
1468
      Redistributions of source code must retain the above copyright
1469
      notice, this list of conditions and the following disclaimer.
1470
 
1471
      Redistributions in binary form must reproduce the above copyright
1472
      notice, this list of conditions and the following disclaimer in the
1473
      documentation and/or other materials provided with the distribution.
1474
 
1475
      The name of Red Hat Incorporated may not be used to endorse
1476
      or promote products derived from this software without specific
1477
      prior written permission.
1478
 
1479
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1480
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1481
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1482
   DISCLAIMED.  IN NO EVENT SHALL RED HAT INCORPORATED BE LIABLE FOR ANY
1483
   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1484
   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1485
   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1486
   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1487
   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1488
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
1489
 
1490
/* function to get positional parameter N where n = N - 1 */
1491
static union arg_val *
1492
_DEFUN(get_arg, (data, n, fmt, ap, numargs_p, args, arg_type, last_fmt),
1493
       struct _reent *data _AND
1494
       int n               _AND
1495
       wchar_t *fmt        _AND
1496
       va_list *ap         _AND
1497
       int *numargs_p      _AND
1498
       union arg_val *args _AND
1499
       int *arg_type       _AND
1500
       wchar_t **last_fmt)
1501
{
1502
  wchar_t ch;
1503
  int number, flags;
1504
  int spec_type;
1505
  int numargs = *numargs_p;
1506
  __CH_CLASS chtype;
1507
  __STATE state, next_state;
1508
  __ACTION action;
1509
  int pos, last_arg;
1510
  int max_pos_arg = n;
1511
  /* Only need types that can be reached via vararg promotions.  */
1512
  enum types { INT, LONG_INT, QUAD_INT, CHAR_PTR, DOUBLE, LONG_DOUBLE, WIDE_CHAR };
1513
 
1514
  /* if this isn't the first call, pick up where we left off last time */
1515
  if (*last_fmt != NULL)
1516
    fmt = *last_fmt;
1517
 
1518
  /* we need to process either to end of fmt string or until we have actually
1519
     read the desired parameter from the vararg list. */
1520
  while (*fmt && n >= numargs)
1521
    {
1522
      while (*fmt != L'\0' && *fmt != L'%')
1523
                                fmt += 1;
1524
 
1525
      if (*fmt == L'\0')
1526
                                break;
1527
      state = START;
1528
      flags = 0;
1529
      pos = -1;
1530
      number = 0;
1531
      spec_type = INT;
1532
 
1533
      /* Use state/action table to process format specifiers.  We ignore invalid
1534
         formats and we are only interested in information that tells us how to
1535
         read the vararg list. */
1536
      while (state != DONE)
1537
        {
1538
          ch = *fmt++;
1539
          chtype = ch < (wchar_t) 256 ? __chclass[ch] : OTHER;
1540
          next_state = __state_table[state][chtype];
1541
          action = __action_table[state][chtype];
1542
          state = next_state;
1543
 
1544
          switch (action)
1545
            {
1546
            case GETMOD:  /* we have format modifier */
1547
              switch (ch)
1548
                {
1549
                case L'h':
1550
                  /* No flag needed, since short and char promote to int.  */
1551
                  break;
1552
                case L'L':
1553
                  flags |= LONGDBL;
1554
                  break;
1555
                case L'q':
1556
                  flags |= QUADINT;
1557
                  break;
1558
# ifdef _WANT_IO_C99_FORMATS
1559
                case L'j':
1560
                  if (sizeof (intmax_t) == sizeof (long))
1561
                    flags |= LONGINT;
1562
                  else
1563
                    flags |= QUADINT;
1564
                  break;
1565
                case L'z':
1566
                  if (sizeof (size_t) <= sizeof (int))
1567
                    /* no flag needed */;
1568
                  else if (sizeof (size_t) <= sizeof (long))
1569
                    flags |= LONGINT;
1570
                  else
1571
                    /* POSIX states that at least one programming
1572
                       environment must support size_t no wider than
1573
                       long, but that means other environments can
1574
                       have size_t as wide as long long.  */
1575
                    flags |= QUADINT;
1576
                  break;
1577
                case L't':
1578
                  if (sizeof (ptrdiff_t) <= sizeof (int))
1579
                    /* no flag needed */;
1580
                  else if (sizeof (ptrdiff_t) <= sizeof (long))
1581
                    flags |= LONGINT;
1582
                  else
1583
                    /* POSIX states that at least one programming
1584
                       environment must support ptrdiff_t no wider than
1585
                       long, but that means other environments can
1586
                       have ptrdiff_t as wide as long long.  */
1587
                    flags |= QUADINT;
1588
                  break;
1589
# endif /* _WANT_IO_C99_FORMATS */
1590
                case L'l':
1591
                default:
1592
# if defined _WANT_IO_C99_FORMATS || !defined _NO_LONGLONG
1593
                  if (*fmt == L'l')
1594
                    {
1595
                      flags |= QUADINT;
1596
                      ++fmt;
1597
                    }
1598
                  else
1599
# endif
1600
                    flags |= LONGINT;
1601
                  break;
1602
                }
1603
              break;
1604
            case GETARG: /* we have format specifier */
1605
              {
1606
                numargs &= (MAX_POS_ARGS - 1);
1607
                /* process the specifier and translate it to a type to fetch from varargs */
1608
                switch (ch)
1609
                  {
1610
                  case L'd':
1611
                  case L'i':
1612
                  case L'o':
1613
                  case L'x':
1614
                  case L'X':
1615
                  case L'u':
1616
                    if (flags & LONGINT)
1617
                      spec_type = LONG_INT;
1618
# ifndef _NO_LONGLONG
1619
                    else if (flags & QUADINT)
1620
                      spec_type = QUAD_INT;
1621
# endif
1622
                    else
1623
                      spec_type = INT;
1624
                    break;
1625
# ifdef _WANT_IO_C99_FORMATS
1626
                  case L'a':
1627
                  case L'A':
1628
                  case L'F':
1629
# endif
1630
                  case L'f':
1631
                  case L'g':
1632
                  case L'G':
1633
                  case L'E':
1634
                  case L'e':
1635
# ifndef _NO_LONGDBL
1636
                    if (flags & LONGDBL)
1637
                      spec_type = LONG_DOUBLE;
1638
                    else
1639
# endif
1640
                      spec_type = DOUBLE;
1641
                    break;
1642
                  case L's':
1643
# ifdef _WANT_IO_C99_FORMATS
1644
                  case L'S':    /* POSIX extension */
1645
# endif
1646
                  case L'p':
1647
                  case L'n':
1648
                    spec_type = CHAR_PTR;
1649
                    break;
1650
                  case L'c':
1651
# ifdef _WANT_IO_C99_FORMATS
1652
                    if (flags & LONGINT)
1653
                      spec_type = WIDE_CHAR;
1654
                    else
1655
# endif
1656
                      spec_type = INT;
1657
                    break;
1658
# ifdef _WANT_IO_C99_FORMATS
1659
                  case L'C':    /* POSIX extension */
1660
                    spec_type = WIDE_CHAR;
1661
                    break;
1662
# endif
1663
                  }
1664
 
1665
                /* if we have a positional parameter, just store the type, otherwise
1666
                   fetch the parameter from the vararg list */
1667
                if (pos != -1)
1668
                  arg_type[pos] = spec_type;
1669
                else
1670
                  {
1671
                    switch (spec_type)
1672
                      {
1673
                      case LONG_INT:
1674
                        args[numargs++].val_long = va_arg (*ap, long);
1675
                        break;
1676
                      case QUAD_INT:
1677
                        args[numargs++].val_quad_t = va_arg (*ap, quad_t);
1678
                        break;
1679
                      case WIDE_CHAR:
1680
                        args[numargs++].val_wint_t = va_arg (*ap, wint_t);
1681
                        break;
1682
                      case INT:
1683
                        args[numargs++].val_int = va_arg (*ap, int);
1684
                        break;
1685
                      case CHAR_PTR:
1686
                        args[numargs++].val_wchar_ptr_t = va_arg (*ap, wchar_t *);
1687
                        break;
1688
                      case DOUBLE:
1689
                        args[numargs++].val_double = va_arg (*ap, double);
1690
                        break;
1691
                      case LONG_DOUBLE:
1692
                        args[numargs++].val__LONG_DOUBLE = va_arg (*ap, _LONG_DOUBLE);
1693
                        break;
1694
                      }
1695
                  }
1696
              }
1697
              break;
1698
            case GETPOS: /* we have positional specifier */
1699
              if (arg_type[0] == -1)
1700
                memset (arg_type, 0, sizeof (int) * MAX_POS_ARGS);
1701
              pos = number - 1;
1702
              max_pos_arg = (max_pos_arg > pos ? max_pos_arg : pos);
1703
              break;
1704
            case PWPOS:  /* we have positional specifier for width or precision */
1705
              if (arg_type[0] == -1)
1706
                memset (arg_type, 0, sizeof (int) * MAX_POS_ARGS);
1707
              number -= 1;
1708
              arg_type[number] = INT;
1709
              max_pos_arg = (max_pos_arg > number ? max_pos_arg : number);
1710
              break;
1711
            case GETPWB: /* we require format pushback */
1712
              --fmt;
1713
              /* fallthrough */
1714
            case GETPW:  /* we have a variable precision or width to acquire */
1715
              args[numargs++].val_int = va_arg (*ap, int);
1716
              break;
1717
            case NUMBER: /* we have a number to process */
1718
              number = (ch - '0');
1719
              while ((ch = *fmt) != '\0' && is_digit (ch))
1720
                {
1721
                  number = number * 10 + (ch - '0');
1722
                  ++fmt;
1723
                }
1724
              break;
1725
            case SKIPNUM: /* we have a number to skip */
1726
              while ((ch = *fmt) != '\0' && is_digit (ch))
1727
                ++fmt;
1728
              break;
1729
            case NOOP:
1730
            default:
1731
              break; /* do nothing */
1732
            }
1733
        }
1734
    }
1735
 
1736
  /* process all arguments up to at least the one we are looking for and if we
1737
     have seen the end of the string, then process up to the max argument needed */
1738
  if (*fmt == '\0')
1739
    last_arg = max_pos_arg;
1740
  else
1741
    last_arg = n;
1742
 
1743
  while (numargs <= last_arg)
1744
    {
1745
      switch (arg_type[numargs])
1746
        {
1747
        case LONG_INT:
1748
          args[numargs++].val_long = va_arg (*ap, long);
1749
          break;
1750
        case QUAD_INT:
1751
          args[numargs++].val_quad_t = va_arg (*ap, quad_t);
1752
          break;
1753
        case CHAR_PTR:
1754
          args[numargs++].val_wchar_ptr_t = va_arg (*ap, wchar_t *);
1755
          break;
1756
        case DOUBLE:
1757
          args[numargs++].val_double = va_arg (*ap, double);
1758
          break;
1759
        case LONG_DOUBLE:
1760
          args[numargs++].val__LONG_DOUBLE = va_arg (*ap, _LONG_DOUBLE);
1761
          break;
1762
        case WIDE_CHAR:
1763
          args[numargs++].val_wint_t = va_arg (*ap, wint_t);
1764
          break;
1765
        case INT:
1766
        default:
1767
          args[numargs++].val_int = va_arg (*ap, int);
1768
          break;
1769
        }
1770
    }
1771
 
1772
  /* alter the global numargs value and keep a reference to the last bit of the fmt
1773
     string we processed here because the caller will continue processing where we started */
1774
  *numargs_p = numargs;
1775
  *last_fmt = fmt;
1776
  return &args[n];
1777
}
1778
#endif /* !_NO_POS_ARGS */

powered by: WebSVN 2.1.0

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