Contiki 2.6

_SP_vfprintf.c

00001 /*
00002 FUNCTION
00003 <<vprintf>>, <<vfprintf>>, <<vsprintf>>---format argument list
00004 
00005 INDEX
00006         vprintf
00007 INDEX
00008         vfprintf
00009 INDEX
00010         vsprintf
00011 INDEX
00012         vsnprintf
00013 
00014 ANSI_SYNOPSIS
00015         #include <stdio.h>
00016         #include <stdarg.h>
00017         int vprintf(const char *<[fmt]>, va_list <[list]>);
00018         int vfprintf(FILE *<[fp]>, const char *<[fmt]>, va_list <[list]>);
00019         int vsprintf(char *<[str]>, const char *<[fmt]>, va_list <[list]>);
00020         int vasprintf(char **<[strp]>, const char *<[fmt]>, va_list <[list]>);
00021         int vsnprintf(char *<[str]>, size_t <[size]>, const char *<[fmt]>, va_list <[list]>);
00022 
00023         int _vprintf_r(void *<[reent]>, const char *<[fmt]>,
00024                         va_list <[list]>);
00025         int _vfprintf_r(void *<[reent]>, FILE *<[fp]>, const char *<[fmt]>,
00026                         va_list <[list]>);
00027         int _vasprintf_r(void *<[reent]>, char **<[str]>, const char *<[fmt]>,
00028                         va_list <[list]>);
00029         int _vsprintf_r(void *<[reent]>, char *<[str]>, const char *<[fmt]>,
00030                         va_list <[list]>);
00031         int _vsnprintf_r(void *<[reent]>, char *<[str]>, size_t <[size]>, const char *<[fmt]>,
00032                         va_list <[list]>);
00033 
00034 TRAD_SYNOPSIS
00035         #include <stdio.h>
00036         #include <varargs.h>
00037         int vprintf( <[fmt]>, <[list]>)
00038         char *<[fmt]>;
00039         va_list <[list]>;
00040 
00041         int vfprintf(<[fp]>, <[fmt]>, <[list]>)
00042         FILE *<[fp]>;
00043         char *<[fmt]>;
00044         va_list <[list]>;
00045 
00046         int vasprintf(<[strp]>, <[fmt]>, <[list]>)
00047         char **<[strp]>;
00048         char *<[fmt]>;
00049         va_list <[list]>;
00050 
00051         int vsprintf(<[str]>, <[fmt]>, <[list]>)
00052         char *<[str]>;
00053         char *<[fmt]>;
00054         va_list <[list]>;
00055 
00056         int vsnprintf(<[str]>, <[size]>, <[fmt]>, <[list]>)
00057         char *<[str]>;
00058         size_t <[size]>;
00059         char *<[fmt]>;
00060         va_list <[list]>;
00061 
00062         int _vprintf_r(<[reent]>, <[fmt]>, <[list]>)
00063         char *<[reent]>;
00064         char *<[fmt]>;
00065         va_list <[list]>;
00066 
00067         int _vfprintf_r(<[reent]>, <[fp]>, <[fmt]>, <[list]>)
00068         char *<[reent]>;
00069         FILE *<[fp]>;
00070         char *<[fmt]>;
00071         va_list <[list]>;
00072 
00073         int _vasprintf_r(<[reent]>, <[strp]>, <[fmt]>, <[list]>)
00074         char *<[reent]>;
00075         char **<[strp]>;
00076         char *<[fmt]>;
00077         va_list <[list]>;
00078 
00079         int _vsprintf_r(<[reent]>, <[str]>, <[fmt]>, <[list]>)
00080         char *<[reent]>;
00081         char *<[str]>;
00082         char *<[fmt]>;
00083         va_list <[list]>;
00084 
00085         int _vsnprintf_r(<[reent]>, <[str]>, <[size]>, <[fmt]>, <[list]>)
00086         char *<[reent]>;
00087         char *<[str]>;
00088         size_t <[size]>;
00089         char *<[fmt]>;
00090         va_list <[list]>;
00091 
00092 DESCRIPTION
00093 <<vprintf>>, <<vfprintf>>, <<vasprintf>>, <<vsprintf>> and <<vsnprintf>> are 
00094 (respectively) variants of <<printf>>, <<fprintf>>, <<asprintf>>, <<sprintf>>,
00095 and <<snprintf>>.  They differ only in allowing their caller to pass the 
00096 variable argument list as a <<va_list>> object (initialized by <<va_start>>) 
00097 rather than directly accepting a variable number of arguments.
00098 
00099 RETURNS
00100 The return values are consistent with the corresponding functions:
00101 <<vasprintf>>/<<vsprintf>> returns the number of bytes in the output string,
00102 save that the concluding <<NULL>> is not counted.
00103 <<vprintf>> and <<vfprintf>> return the number of characters transmitted.
00104 If an error occurs, <<vprintf>> and <<vfprintf>> return <<EOF>> and
00105 <<vasprintf>> returns -1.  No error returns occur for <<vsprintf>>.
00106 
00107 PORTABILITY
00108 ANSI C requires all three functions.
00109 
00110 Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
00111 <<lseek>>, <<read>>, <<sbrk>>, <<write>>.
00112 */
00113 
00114 /*
00115  * Copyright (c) 1990 The Regents of the University of California.
00116  * All rights reserved.
00117  *
00118  * This code is derived from software contributed to Berkeley by
00119  * Chris Torek.
00120  *
00121  * Redistribution and use in source and binary forms, with or without
00122  * modification, are permitted provided that the following conditions
00123  * are met:
00124  * 1. Redistributions of source code must retain the above copyright
00125  *    notice, this list of conditions and the following disclaimer.
00126  * 2. Redistributions in binary form must reproduce the above copyright
00127  *    notice, this list of conditions and the following disclaimer in the
00128  *    documentation and/or other materials provided with the distribution.
00129  * 3. All advertising materials mentioning features or use of this software
00130  *    must display the following acknowledgement:
00131  *      This product includes software developed by the University of
00132  *      California, Berkeley and its contributors.
00133  * 4. Neither the name of the University nor the names of its contributors
00134  *    may be used to endorse or promote products derived from this software
00135  *    without specific prior written permission.
00136  *
00137  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00138  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00139  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00140  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00141  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00142  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00143  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00144  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00145  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00146  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00147  * SUCH DAMAGE.
00148  */
00149 
00150 #if defined(LIBC_SCCS) && !defined(lint)
00151 static char *sccsid = "from: @(#)vfprintf.c     5.50 (Berkeley) 12/16/92";
00152 #endif /* LIBC_SCCS and not lint */
00153 
00154 /*
00155  * Actual printf innards.
00156  *
00157  * This code is large and complicated...
00158  */
00159 
00160 #ifdef INTEGER_ONLY
00161         #define VFPRINTF vfiprintf
00162         #define _VFPRINTF_R _vfiprintf_r
00163 #else
00164         #define VFPRINTF vfprintf
00165         #define _VFPRINTF_R _vfprintf_r
00166         #ifndef NO_FLOATING_POINT
00167         #define FLOATING_POINT
00168         #endif
00169 #endif
00170 
00171 #define _NO_LONGLONG
00172 #if defined WANT_PRINTF_LONG_LONG && defined __GNUC__
00173 # undef _NO_LONGLONG
00174 #endif
00175 
00176 #define _NO_POS_ARGS 
00177 #if defined WANT_IO_POS_ARGS
00178 # undef _NO_POS_ARGS
00179 #endif
00180 
00181 #include <_ansi.h>
00182 #include <stdio.h>
00183 #include <stdlib.h>
00184 #include <string.h>
00185 #include <limits.h>
00186 #include <reent.h>
00187 #include <wchar.h>
00188 #include <string.h>
00189 #include <sys/lock.h>
00190 
00191 #ifdef _HAVE_STDC
00192 #include <stdarg.h>
00193 #else
00194 #include <varargs.h>
00195 #endif
00196 
00197 #ifndef _SMALL_PRINTF
00198         #include "local.h"
00199         #include "fvwrite.h"
00200 #else
00201         #define MAXBUFLOC 80
00202 #endif
00203 
00204         #include "vfieeefp.h"
00205 
00206 /* Currently a test is made to see if long double processing is warranted.
00207    This could be changed in the future should the _ldtoa_r code be
00208    preferred over _dtoa_r.  */
00209 #define _NO_LONGDBL
00210 #if defined WANT_IO_LONG_DBL && (LDBL_MANT_DIG > DBL_MANT_DIG)
00211 #       undef _NO_LONGDBL
00212 #endif
00213 
00214 
00215 #ifndef _SMALL_PRINTF
00216 /*
00217  * Flush out all the vectors defined by the given uio,
00218  * then reset it so that it can be reused.
00219  */
00220 static int
00221 __sprint(fp, uio)
00222         FILE *fp;
00223         register struct __suio *uio;
00224 {
00225         register int err;
00226 
00227         if (uio->uio_resid == 0) {
00228                 uio->uio_iovcnt = 0;
00229                 return (0);
00230         }
00231         err = __sfvwrite(fp, uio);
00232         uio->uio_resid = 0;
00233         uio->uio_iovcnt = 0;
00234         return (err);
00235 }
00236 
00237 /*
00238  * Helper function for `fprintf to unbuffered unix file': creates a
00239  * temporary buffer.  We only work on write-only files; this avoids
00240  * worries about ungetc buffers and so forth.
00241  */
00242 static int
00243 __sbprintf(fp, fmt, ap)
00244         register FILE *fp;
00245         const char *fmt;
00246         va_list ap;
00247 {
00248         int ret;
00249         FILE fake;
00250         unsigned char buf[BUFSIZ];
00251 
00252         /* copy the important variables */
00253         fake._flags = fp->_flags & ~__SNBF;
00254         fake._file = fp->_file;
00255         fake._cookie = fp->_cookie;
00256         fake._write = fp->_write;
00257 
00258         /* set up the buffer */
00259         fake._bf._base = fake._p = buf;
00260         fake._bf._size = fake._w = sizeof(buf);
00261         fake._lbfsize = 0;      /* not actually used, but Just In Case */
00262 #ifndef __SINGLE_THREAD__
00263         __lock_init_recursive (*(_LOCK_RECURSIVE_T *)&fake._lock);
00264 #endif
00265 
00266         /* do the work, then copy any error status */
00267         ret = VFPRINTF(&fake, fmt, ap);
00268         if (ret >= 0 && fflush(&fake))
00269                 ret = EOF;
00270         if (fake._flags & __SERR)
00271                 fp->_flags |= __SERR;
00272 
00273 #ifndef __SINGLE_THREAD__
00274         __lock_close_recursive (*(_LOCK_RECURSIVE_T *)&fake._lock);
00275 #endif
00276         return (ret);
00277 }
00278 #endif
00279 
00280 
00281 
00282 #ifdef FLOATING_POINT
00283 #include <locale.h>
00284 #include <math.h>
00285 #include "floatio.h"
00286 
00287 #if ((MAXEXP+MAXFRACT+1) > MB_LEN_MAX)
00288 #  define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
00289 #else 
00290 #  define BUF MB_LEN_MAX
00291 #endif
00292 
00293 #define DEFPREC         6
00294 
00295 #ifdef _NO_LONGDBL
00296 static char *cvt _PARAMS((struct _reent *, double, int, int, char *, int *, int, int *));
00297 #else
00298 static char *cvt _PARAMS((struct _reent *, _LONG_DOUBLE, int, int, char *, int *, int, int *));
00299 extern int  _ldcheck _PARAMS((_LONG_DOUBLE *));
00300 #endif
00301 
00302 static int exponent _PARAMS((char *, int, int));
00303 
00304 #else /* no FLOATING_POINT */
00305 
00306 #define BUF             40
00307 
00308 #endif /* FLOATING_POINT */
00309 
00310 #ifndef _NO_LONGLONG
00311 #define quad_t long long
00312 #define u_quad_t unsigned long long
00313 #else
00314 #define quad_t long
00315 #define u_quad_t unsigned long
00316 #endif
00317 
00318 typedef quad_t * quad_ptr_t;
00319 typedef void *   void_ptr_t;
00320 typedef char *   char_ptr_t;
00321 typedef long *   long_ptr_t;
00322 typedef int  *   int_ptr_t;
00323 typedef short *  short_ptr_t;
00324 
00325 #ifndef _NO_POS_ARGS
00326 #define MAX_POS_ARGS 32
00327 
00328 union arg_val
00329 {
00330   int val_int;
00331   u_int val_u_int;
00332   long val_long;
00333   u_long val_u_long;
00334   float val_float;
00335   double val_double;
00336   _LONG_DOUBLE val__LONG_DOUBLE;
00337   int_ptr_t val_int_ptr_t;
00338   short_ptr_t val_short_ptr_t;
00339   long_ptr_t val_long_ptr_t;
00340   char_ptr_t val_char_ptr_t;
00341   quad_ptr_t val_quad_ptr_t;
00342   void_ptr_t val_void_ptr_t;
00343   quad_t val_quad_t;
00344   u_quad_t val_u_quad_t;
00345   wint_t val_wint_t;
00346 };
00347 
00348 static union arg_val *get_arg (struct _reent *data, int n, char *fmt, 
00349                                va_list *ap, int *numargs, union arg_val *args, 
00350                                int *arg_type, char **last_fmt);
00351 #endif /* !_NO_POS_ARGS */
00352 
00353 /*
00354  * Macros for converting digits to letters and vice versa
00355  */
00356 #define to_digit(c)     ((c) - '0')
00357 #define is_digit(c)     ((unsigned)to_digit(c) <= 9)
00358 #define to_char(n)      ((n) + '0')
00359 
00360 /*
00361  * Flags used during conversion.
00362  */
00363 #define ALT             0x001           /* alternate form */
00364 #define HEXPREFIX       0x002           /* add 0x or 0X prefix */
00365 #define LADJUST         0x004           /* left adjustment */
00366 #define LONGDBL         0x008           /* long double */
00367 #define LONGINT         0x010           /* long integer */
00368 #ifndef _NO_LONGLONG
00369 #define QUADINT         0x020           /* quad integer */
00370 #else /* ifdef _NO_LONGLONG, make QUADINT equivalent to LONGINT, so
00371          that %lld behaves the same as %ld, not as %d, as expected if:
00372          sizeof (long long) = sizeof long > sizeof int  */
00373 #define QUADINT         LONGINT
00374 #endif
00375 #define SHORTINT        0x040           /* short integer */
00376 #define ZEROPAD         0x080           /* zero (as opposed to blank) pad */
00377 #define FPT             0x100           /* Floating point number */
00378 
00379 
00380                 int _EXFUN (_VFPRINTF_R, (struct _reent *, FILE *, _CONST char *, va_list));
00381                 
00382                 int 
00383                 _DEFUN (VFPRINTF, (fp, fmt0, ap),
00384                         FILE * fp _AND
00385                         _CONST char *fmt0 _AND
00386                         va_list ap)
00387                 {
00388                   int result;
00389                   _flockfile(fp);
00390 #ifndef _SMALL_PRINTF             
00391                   CHECK_INIT (fp);
00392 #endif
00393                   result = _VFPRINTF_R (_REENT, fp, fmt0, ap);
00394                   _funlockfile(fp);
00395                   return result;
00396                 }
00397 
00398 
00399 
00400 int 
00401 _DEFUN (_VFPRINTF_R, (data, fp, fmt0, ap),
00402         struct _reent *data _AND
00403         FILE * fp _AND
00404         _CONST char *fmt0 _AND
00405         va_list ap)
00406 {
00407         register char *fmt;     /* format string */
00408         register int ch;        /* character from fmt */
00409         register int n, m;      /* handy integers (short term usage) */
00410         register char *cp;      /* handy char pointer (short term usage) */
00411         register struct __siov *iovp;/* for PRINT macro */
00412         register int flags;     /* flags as above */
00413         char *fmt_anchor;       /* current format spec being processed */
00414         int N;                  /* arg number */
00415         int arg_index;          /* index into args processed directly */
00416 #ifndef _NO_POS_ARGS
00417         int numargs;            /* number of varargs read */
00418         char *saved_fmt;        /* saved fmt pointer */
00419         union arg_val args[MAX_POS_ARGS];
00420         int arg_type[MAX_POS_ARGS];
00421         int is_pos_arg;         /* is current format positional? */
00422         int old_is_pos_arg;     /* is current format positional? */
00423 #endif
00424         int ret;                /* return value accumulator */
00425         int width;              /* width from format (%8d), or 0 */
00426         int prec;               /* precision from format (%.3d), or -1 */
00427         char sign;              /* sign prefix (' ', '+', '-', or \0) */
00428 #ifdef FLOATING_POINT
00429 #ifdef _SMALL_PRINTF
00430                 char *decimal_point = ".";
00431 #else
00432                 char *decimal_point = localeconv()->decimal_point;
00433 #endif
00434         char softsign;          /* temporary negative sign for floats */
00435 #ifdef _NO_LONGDBL
00436         union { int i; double d; } _double_ = {0};
00437         #define _fpvalue (_double_.d)
00438 #else
00439         union { int i; _LONG_DOUBLE ld; } _long_double_ = {0};
00440         #define _fpvalue (_long_double_.ld)
00441         int tmp;  
00442 #endif
00443         int expt;               /* integer value of exponent */
00444         int expsize = 0;        /* character count for expstr */
00445         int ndig;               /* actual number of digits returned by cvt */
00446         char expstr[7];         /* buffer for exponent string */
00447 #endif
00448         u_quad_t _uquad;        /* integer arguments %[diouxX] */
00449         enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
00450         int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
00451         int realsz;             /* field size expanded by dprec */
00452         int size;               /* size of converted field or string */
00453         char *xdigs = NULL;     /* digits for [xX] conversion */
00454 #ifndef _SMALL_PRINTF
00455                 #define NIOV 8
00456                         struct __suio uio;      /* output information: summary */
00457                         struct __siov iov[NIOV];/* ... and individual io vectors */
00458                         char *malloc_buf = NULL;/* handy pointer for malloced buffers */
00459 #else
00460         char malloc_buf [MAXBUFLOC]; /* local buffers */
00461 #endif
00462 
00463         char buf[BUF];          /* space for %c, %[diouxX], %[eEfgG] */
00464         char ox[2];             /* space for 0x hex-prefix */
00465 #ifdef MB_CAPABLE
00466         wchar_t wc;
00467         mbstate_t state;        /* mbtowc calls from library must not change state */
00468 #endif
00469 
00470 
00471         /*
00472          * Choose PADSIZE to trade efficiency vs. size.  If larger printf
00473          * fields occur frequently, increase PADSIZE and make the initialisers
00474          * below longer.
00475          */
00476 #define PADSIZE 16              /* pad chunk size */
00477         static _CONST char blanks[PADSIZE] =
00478          {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
00479         static _CONST char zeroes[PADSIZE] =
00480          {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
00481 
00482 #ifdef MB_CAPABLE
00483         memset (&state, '\0', sizeof (state));
00484 #endif
00485 
00486 #ifndef  _SMALL_PRINTF
00487                         /*
00488                          * BEWARE, these `goto error' on error, and PAD uses `n'.
00489                          */
00490                 #define PRINT(ptr, len,f) { \
00491                         iovp->iov_base = (ptr); \
00492                         iovp->iov_len = (len); \
00493                         uio.uio_resid += (len); \
00494                         iovp++; \
00495                         if (++uio.uio_iovcnt >= NIOV) { \
00496                                 if (__sprint(fp, &uio)) \
00497                                         goto error; \
00498                                 iovp = iov; \
00499                         } \
00500                 }
00501                 #define PAD(howmany, with,f) { \
00502                         if ((n = (howmany)) > 0) { \
00503                                 while (n > PADSIZE) { \
00504                                         PRINT(with, PADSIZE,f); \
00505                                         n -= PADSIZE; \
00506                                 } \
00507                                 PRINT(with, n,f); \
00508                         } \
00509                 }
00510                 #define FLUSH() { \
00511                         if (uio.uio_resid && __sprint(fp, &uio)) \
00512                                 goto error; \
00513                         uio.uio_iovcnt = 0; \
00514                         iovp = iov; \
00515                 }
00516 #else
00517         //Macros for _SMALL_PRINTF
00518         void _SMALL_PRINTF_puts(const char *ptr, int len, FILE *f);
00519                 #define PRINT(ptr, len, f) {_SMALL_PRINTF_puts(ptr,len,f);}
00520                 #define PAD(howmany, with, f) { \
00521                         if ((n = (howmany)) > 0) { \
00522                                 while (n > PADSIZE) { \
00523                                         PRINT(with, PADSIZE,f); \
00524                                         n -= PADSIZE; \
00525                                 } \
00526                                 PRINT(with, n, f); \
00527                         } \
00528                 }
00529                 #define FLUSH() { ; }
00530 #endif
00531 
00532 
00533         /* Macros to support positional arguments */
00534 #ifndef _NO_POS_ARGS
00535 #define GET_ARG(n, ap, type) \
00536   ( is_pos_arg \
00537       ? n < numargs \
00538          ? args[n].val_##type \
00539          : get_arg (data, n, fmt_anchor, &ap, &numargs, args, arg_type, &saved_fmt)->val_##type \
00540       : arg_index++ < numargs \
00541          ? args[n].val_##type \
00542          : numargs < MAX_POS_ARGS \
00543            ? args[numargs++].val_##type = va_arg(ap, type) \
00544            : va_arg(ap, type) \
00545   )
00546 #else
00547 #define GET_ARG(n, ap, type) (va_arg(ap, type))
00548 #endif
00549     
00550         /*
00551          * To extend shorts properly, we need both signed and unsigned
00552          * argument extraction methods.
00553          */
00554 #ifndef _NO_LONGLONG
00555 #define SARG() \
00556         (flags&QUADINT ? GET_ARG(N, ap, quad_t) : \
00557             flags&LONGINT ? GET_ARG(N, ap, long) : \
00558             flags&SHORTINT ? (long)(short)GET_ARG(N, ap, int) : \
00559             (long)GET_ARG(N, ap, int))
00560 #define UARG() \
00561         (flags&QUADINT ? GET_ARG(N, ap, u_quad_t) : \
00562             flags&LONGINT ? GET_ARG(N, ap, u_long) : \
00563             flags&SHORTINT ? (u_long)(u_short)GET_ARG(N, ap, int) : \
00564             (u_long)GET_ARG(N, ap, u_int))
00565 #else
00566 #define SARG() \
00567         (flags&LONGINT ? GET_ARG(N, ap, long) : \
00568             flags&SHORTINT ? (long)(short)GET_ARG(N, ap, int) : \
00569             (long)GET_ARG(N, ap, int))
00570 #define UARG() \
00571         (flags&LONGINT ? GET_ARG(N, ap, u_long) : \
00572             flags&SHORTINT ? (u_long)(u_short)GET_ARG(N, ap, int) : \
00573             (u_long)GET_ARG(N, ap, u_int))
00574 #endif
00575 
00576 #ifndef _SMALL_PRINTF
00577                         /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
00578                         if (cantwrite(fp))
00579                                 return (EOF);
00580         
00581                         /* optimise fprintf(stderr) (and other unbuffered Unix files) */
00582                         if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
00583                             fp->_file >= 0)
00584                                 return (__sbprintf(fp, fmt0, ap));
00585                 
00586                         uio.uio_iov = iovp = iov;
00587                         uio.uio_resid = 0;
00588                         uio.uio_iovcnt = 0;
00589 #endif
00590         fmt = (char *)fmt0;
00591 
00592         ret = 0;
00593         arg_index = 0;
00594 
00595 #ifndef _NO_POS_ARGS
00596         saved_fmt = NULL;
00597         arg_type[0] = -1;
00598         numargs = 0;
00599         is_pos_arg = 0;
00600 #endif
00601 
00602         /*
00603          * Scan the format for conversions (`%' character).
00604          */
00605         for (;;) {
00606                 cp = fmt;
00607 #ifdef MB_CAPABLE
00608                 while ((n = _mbtowc_r(data, &wc, fmt, MB_CUR_MAX, &state)) > 0) {
00609                     if (wc == '%')
00610                         break;
00611                     fmt += n;
00612                 }
00613 #else
00614                 while (*fmt != '\0' && *fmt != '%')
00615                     fmt += 1;
00616 #endif
00617                 if ((m = fmt - cp) != 0) {
00618                         PRINT(cp, m, fp);
00619                         ret += m;
00620                 }
00621 #ifdef MB_CAPABLE
00622                 if (n <= 0)
00623                     goto done;
00624 #else
00625                 if (*fmt == '\0')
00626                     goto done;
00627 #endif
00628                 fmt_anchor = fmt;
00629                 fmt++;          /* skip over '%' */
00630 
00631                 flags = 0;
00632                 dprec = 0;
00633                 width = 0;
00634                 prec = -1;
00635                 sign = '\0';
00636                 N = arg_index;
00637 #ifndef _NO_POS_ARGS
00638                 is_pos_arg = 0;
00639 #endif
00640 
00641 rflag:          ch = *fmt++;
00642 reswitch:       switch (ch) {
00643                 case ' ':
00644                         /*
00645                          * ``If the space and + flags both appear, the space
00646                          * flag will be ignored.''
00647                          *      -- ANSI X3J11
00648                          */
00649                         if (!sign)
00650                                 sign = ' ';
00651                         goto rflag;
00652                 case '#':
00653                         flags |= ALT;
00654                         goto rflag;
00655                 case '*':
00656                         n = N;
00657 #ifndef _NO_POS_ARGS
00658                         /* we must check for positional arg used for dynamic width */
00659                         old_is_pos_arg = is_pos_arg;
00660                         is_pos_arg = 0;
00661                         if (is_digit(*fmt)) {
00662                                 char *old_fmt = fmt;
00663 
00664                                 n = 0;
00665                                 ch = *fmt++;
00666                                 do {
00667                                         n = 10 * n + to_digit(ch);
00668                                         ch = *fmt++;
00669                                 } while (is_digit(ch));
00670 
00671                                 if (ch == '$') {
00672                                         if (n <= MAX_POS_ARGS) {
00673                                                 n -= 1;
00674                                                 is_pos_arg = 1;
00675                                         }
00676                                         else
00677                                                 goto error;
00678                                 }
00679                                 else {
00680                                         fmt = old_fmt;
00681                                         goto rflag;
00682                                 }
00683                         }
00684 #endif /* !_NO_POS_ARGS */
00685 
00686                         /*
00687                          * ``A negative field width argument is taken as a
00688                          * - flag followed by a positive field width.''
00689                          *      -- ANSI X3J11
00690                          * They don't exclude field widths read from args.
00691                          */
00692                         width = GET_ARG(n, ap, int);
00693 #ifndef _NO_POS_ARGS
00694                         is_pos_arg = old_is_pos_arg;
00695 #endif
00696                         if (width >= 0)
00697                                 goto rflag;
00698                         width = -width;
00699                         /* FALLTHROUGH */
00700                 case '-':
00701                         flags |= LADJUST;
00702                         goto rflag;
00703                 case '+':
00704                         sign = '+';
00705                         goto rflag;
00706                 case '.':
00707                         if ((ch = *fmt++) == '*') {
00708                                 n = N;
00709 #ifndef _NO_POS_ARGS
00710                                 /* we must check for positional arg used for dynamic width */
00711                                 old_is_pos_arg = is_pos_arg;
00712                                 is_pos_arg = 0;
00713                                 if (is_digit(*fmt)) {
00714                                         char *old_fmt = fmt;
00715 
00716                                         n = 0;
00717                                         ch = *fmt++;
00718                                         do {
00719                                                 n = 10 * n + to_digit(ch);
00720                                                 ch = *fmt++;
00721                                         } while (is_digit(ch));
00722 
00723                                         if (ch == '$') {
00724                                                 if (n <= MAX_POS_ARGS) {
00725                                                         n -= 1;
00726                                                         is_pos_arg = 1;
00727                                                 }
00728                                                 else
00729                                                         goto error;
00730                                         }
00731                                         else {
00732                                                 fmt = old_fmt;
00733                                                 goto rflag;
00734                                         }
00735                                 }
00736 #endif /* !_NO_POS_ARGS */
00737                                 prec = GET_ARG(n, ap, int);
00738 #ifndef _NO_POS_ARGS
00739                                 is_pos_arg = old_is_pos_arg;
00740 #endif
00741                                 if (prec < 0)
00742                                         prec = -1;
00743                                 goto rflag;
00744                         }
00745                         n = 0;
00746                         while (is_digit(ch)) {
00747                                 n = 10 * n + to_digit(ch);
00748                                 ch = *fmt++;
00749                         }
00750                         prec = n < 0 ? -1 : n;
00751                         goto reswitch;
00752                 case '0':
00753                         /*
00754                          * ``Note that 0 is taken as a flag, not as the
00755                          * beginning of a field width.''
00756                          *      -- ANSI X3J11
00757                          */
00758                         flags |= ZEROPAD;
00759                         goto rflag;
00760                 case '1': case '2': case '3': case '4':
00761                 case '5': case '6': case '7': case '8': case '9':
00762                         n = 0;
00763                         do {
00764                                 n = 10 * n + to_digit(ch);
00765                                 ch = *fmt++;
00766                         } while (is_digit(ch));
00767 #ifndef _NO_POS_ARGS
00768                         if (ch == '$') {
00769                                 if (n <= MAX_POS_ARGS) {
00770                                         N = n - 1;
00771                                         is_pos_arg = 1;
00772                                         goto rflag;
00773                                 }
00774                                 else
00775                                         goto error;
00776                         }
00777 #endif /* !_NO_POS_ARGS */
00778                         width = n;
00779                         goto reswitch;
00780 #ifdef FLOATING_POINT
00781                 case 'L':
00782                         flags |= LONGDBL;
00783                         goto rflag;
00784 #endif
00785                 case 'h':
00786                         flags |= SHORTINT;
00787                         goto rflag;
00788                 case 'l':
00789                         if (*fmt == 'l') {
00790                                 fmt++;
00791                                 flags |= QUADINT;
00792                         } else {
00793                                 flags |= LONGINT;
00794                         }
00795                         goto rflag;
00796                 case 'q':
00797                         flags |= QUADINT;
00798                         goto rflag;
00799                 case 'c':
00800                 case 'C':
00801                         cp = buf;
00802                         if (ch == 'C' || (flags & LONGINT)) {
00803                                 mbstate_t ps;
00804 
00805                                 memset((void *)&ps, '\0', sizeof(mbstate_t));
00806                                 if ((size = (int)_wcrtomb_r(data, cp, 
00807                                                (wchar_t)GET_ARG(N, ap, wint_t), 
00808                                                 &ps)) == -1)
00809                                         goto error; 
00810                         }
00811                         else {
00812                                 *cp = GET_ARG(N, ap, int);
00813                                 size = 1;
00814                         }
00815                         sign = '\0';
00816                         break;
00817                 case 'D':
00818                         flags |= LONGINT;
00819                         /*FALLTHROUGH*/
00820                 case 'd':
00821                 case 'i':
00822                         _uquad = SARG();
00823 #ifndef _NO_LONGLONG
00824                         if ((quad_t)_uquad < 0)
00825 #else
00826                         if ((long) _uquad < 0)
00827 #endif
00828                         {
00829 
00830                                 _uquad = -_uquad;
00831                                 sign = '-';
00832                         }
00833                         base = DEC;
00834                         goto number;
00835 #ifdef FLOATING_POINT
00836                 case 'e':
00837                 case 'E':
00838                 case 'f':
00839                 case 'g':
00840                 case 'G':
00841                         if (prec == -1) {
00842                                 prec = DEFPREC;
00843                         } else if ((ch == 'g' || ch == 'G') && prec == 0) {
00844                                 prec = 1;
00845                         }
00846 
00847 #ifdef _NO_LONGDBL
00848                         if (flags & LONGDBL) {
00849                                 _fpvalue = (double) GET_ARG(N, ap, _LONG_DOUBLE);
00850                         } else {
00851                                 _fpvalue = GET_ARG(N, ap, double);
00852                         }
00853 
00854                         /* do this before tricky precision changes */
00855                         if (isinf(_fpvalue)) {
00856                                 if (_fpvalue < 0)
00857                                         sign = '-';
00858                                 cp = "Inf";
00859                                 size = 3;
00860                                 break;
00861                         }
00862                         if (isnan(_fpvalue)) {
00863                                 cp = "NaN";
00864                                 size = 3;
00865                                 break;
00866                         }
00867 
00868 #else /* !_NO_LONGDBL */
00869                         
00870                         if (flags & LONGDBL) {
00871                                 _fpvalue = GET_ARG(N, ap, _LONG_DOUBLE);
00872                         } else {
00873                                 _fpvalue = (_LONG_DOUBLE)GET_ARG(N, ap, double);
00874                         }
00875 
00876                         /* do this before tricky precision changes */
00877                         tmp = _ldcheck (&_fpvalue);
00878                         if (tmp == 2) {
00879                                 if (_fpvalue < 0)
00880                                         sign = '-';
00881                                 cp = "Inf";
00882                                 size = 3;
00883                                 break;
00884                         }
00885                         if (tmp == 1) {
00886                                 cp = "NaN";
00887                                 size = 3;
00888                                 break;
00889                         }
00890 #endif /* !_NO_LONGDBL */
00891 
00892                         flags |= FPT;
00893 
00894                         cp = cvt(data, _fpvalue, prec, flags, &softsign,
00895                                 &expt, ch, &ndig);
00896 
00897                         if (ch == 'g' || ch == 'G') {
00898                                 if (expt <= -4 || expt > prec)
00899                                         ch = (ch == 'g') ? 'e' : 'E';
00900                                 else
00901                                         ch = 'g';
00902                         } 
00903                         if (ch <= 'e') {        /* 'e' or 'E' fmt */
00904                                 --expt;
00905                                 expsize = exponent(expstr, expt, ch);
00906                                 size = expsize + ndig;
00907                                 if (ndig > 1 || flags & ALT)
00908                                         ++size;
00909                         } else if (ch == 'f') {         /* f fmt */
00910                                 if (expt > 0) {
00911                                         size = expt;
00912                                         if (prec || flags & ALT)
00913                                                 size += prec + 1;
00914                                 } else  /* "0.X" */
00915                                         size = (prec || flags & ALT)
00916                                                   ? prec + 2
00917                                                   : 1;
00918                         } else if (expt >= ndig) {      /* fixed g fmt */
00919                                 size = expt;
00920                                 if (flags & ALT)
00921                                         ++size;
00922                         } else
00923                                 size = ndig + (expt > 0 ?
00924                                         1 : 2 - expt);
00925 
00926                         if (softsign)
00927                                 sign = '-';
00928                         break;
00929 #endif /* FLOATING_POINT */
00930                 case 'n':
00931 #ifndef _NO_LONGLONG
00932                         if (flags & QUADINT)
00933                                 *GET_ARG(N, ap, quad_ptr_t) = ret;
00934                         else 
00935 #endif
00936                         if (flags & LONGINT)
00937                                 *GET_ARG(N, ap, long_ptr_t) = ret;
00938                         else if (flags & SHORTINT)
00939                                 *GET_ARG(N, ap, short_ptr_t) = ret;
00940                         else
00941                                 *GET_ARG(N, ap, int_ptr_t) = ret;
00942                         continue;       /* no output */
00943                 case 'O':
00944                         flags |= LONGINT;
00945                         /*FALLTHROUGH*/
00946                 case 'o':
00947                         _uquad = UARG();
00948                         base = OCT;
00949                         goto nosign;
00950                 case 'p':
00951                         /*
00952                          * ``The argument shall be a pointer to void.  The
00953                          * value of the pointer is converted to a sequence
00954                          * of printable characters, in an implementation-
00955                          * defined manner.''
00956                          *      -- ANSI X3J11
00957                          */
00958                         /* NOSTRICT */
00959                         _uquad = (u_long)(unsigned _POINTER_INT)GET_ARG(N, ap, void_ptr_t);
00960                         base = HEX;
00961                         xdigs = "0123456789abcdef";
00962                         flags |= HEXPREFIX;
00963                         ch = 'x';
00964                         goto nosign;
00965                 case 's':
00966                 case 'S':
00967                         sign = '\0';
00968                         if ((cp = GET_ARG(N, ap, char_ptr_t)) == NULL) {
00969                                 cp = "(null)";
00970                                 size = 6;
00971                         }
00972                         else if (ch == 'S' || (flags & LONGINT)) {
00973                                 mbstate_t ps;
00974                                 _CONST wchar_t *wcp;
00975  
00976                                 wcp = (_CONST wchar_t *)cp;
00977                                 size = m = 0;
00978                                 memset((void *)&ps, '\0', sizeof(mbstate_t));
00979  
00980                                 /* Count number of bytes needed for multibyte
00981                                    string that will be produced from widechar
00982                                    string.  */
00983                                 if (prec >= 0) {
00984                                         while (1) {
00985                                                 if (wcp[m] == L'\0')
00986                                                         break;
00987                                                 if ((n = (int)_wcrtomb_r(data, 
00988                                                      buf, wcp[m], &ps)) == -1)
00989                                                         goto error;
00990                                                 if (n + size > prec)
00991                                                         break;
00992                                                 m += 1;
00993                                                 size += n;
00994                                                 if (size == prec)
00995                                                         break;
00996                                         }
00997                                 }
00998                                 else {
00999                                         if ((size = (int)_wcsrtombs_r(data, 
01000                                                    NULL, &wcp, 0, &ps)) == -1)
01001                                                 goto error; 
01002                                         wcp = (_CONST wchar_t *)cp;
01003                                 }
01004  
01005                                 if (size == 0)
01006                                         break;
01007  
01008                                 #ifndef _SMALL_PRINTF
01009                                 if ((malloc_buf = 
01010                                     (char *)_malloc_r(data, size + 1)) == NULL)
01011                                         goto error;
01012                                 #endif
01013                              
01014                                 /* Convert widechar string to multibyte string. */
01015                                 memset((void *)&ps, '\0', sizeof(mbstate_t));
01016                                 if (_wcsrtombs_r(data, malloc_buf, &wcp, size, &ps) != size)
01017                                         goto error;
01018                                 cp = malloc_buf;
01019                                 cp[size] = '\0';
01020                         }
01021                         else if (prec >= 0) {
01022                                 /*
01023                                  * can't use strlen; can only look for the
01024                                  * NUL in the first `prec' characters, and
01025                                  * strlen() will go further.
01026                                  */
01027                                 char *p = memchr(cp, 0, prec);
01028 
01029                                 if (p != NULL) {
01030                                         size = p - cp;
01031                                         if (size > prec)
01032                                                 size = prec;
01033                                 } else
01034                                         size = prec;
01035                         } else
01036                                 size = strlen(cp);
01037 
01038                         break;
01039                 case 'U':
01040                         flags |= LONGINT;
01041                         /*FALLTHROUGH*/
01042                 case 'u':
01043                         _uquad = UARG();
01044                         base = DEC;
01045                         goto nosign;
01046                 case 'X':
01047                         xdigs = "0123456789ABCDEF";
01048                         goto hex;
01049                 case 'x':
01050                         xdigs = "0123456789abcdef";
01051 hex:                    _uquad = UARG();
01052                         base = HEX;
01053                         /* leading 0x/X only if non-zero */
01054                         if (flags & ALT && _uquad != 0)
01055                                 flags |= HEXPREFIX;
01056 
01057                         /* unsigned conversions */
01058 nosign:                 sign = '\0';
01059                         /*
01060                          * ``... diouXx conversions ... if a precision is
01061                          * specified, the 0 flag will be ignored.''
01062                          *      -- ANSI X3J11
01063                          */
01064 number:                 if ((dprec = prec) >= 0)
01065                                 flags &= ~ZEROPAD;
01066 
01067                         /*
01068                          * ``The result of converting a zero value with an
01069                          * explicit precision of zero is no characters.''
01070                          *      -- ANSI X3J11
01071                          */
01072                         cp = buf + BUF;
01073                         if (_uquad != 0 || prec != 0) {
01074                                 /*
01075                                  * Unsigned mod is hard, and unsigned mod
01076                                  * by a constant is easier than that by
01077                                  * a variable; hence this switch.
01078                                  */
01079                                 switch (base) {
01080                                 case OCT:
01081                                         do {
01082                                                 *--cp = to_char(_uquad & 7);
01083                                                 _uquad >>= 3;
01084                                         } while (_uquad);
01085                                         /* handle octal leading 0 */
01086                                         if (flags & ALT && *cp != '0')
01087                                                 *--cp = '0';
01088                                         break;
01089 
01090                                 case DEC:
01091                                         /* many numbers are 1 digit */
01092                                         while (_uquad >= 10) {
01093                                                 *--cp = to_char(_uquad % 10);
01094                                                 _uquad /= 10;
01095                                         }
01096                                         *--cp = to_char(_uquad);
01097                                         break;
01098 
01099                                 case HEX:
01100                                         do {
01101                                                 *--cp = xdigs[_uquad & 15];
01102                                                 _uquad >>= 4;
01103                                         } while (_uquad);
01104                                         break;
01105 
01106                                 default:
01107                                         cp = "bug in vfprintf: bad base";
01108                                         size = strlen(cp);
01109                                         goto skipsize;
01110                                 }
01111                         }
01112                        /*
01113                         * ...result is to be converted to an 'alternate form'.
01114                         * For o conversion, it increases the precision to force
01115                         * the first digit of the result to be a zero."
01116                         *     -- ANSI X3J11
01117                         *
01118                         * To demonstrate this case, compile and run:
01119                         *    printf ("%#.0o",0);
01120                         */
01121                        else if (base == OCT && (flags & ALT))
01122                          *--cp = '0';
01123 
01124                         size = buf + BUF - cp;
01125                 skipsize:
01126                         break;
01127                 default:        /* "%?" prints ?, unless ? is NUL */
01128                         if (ch == '\0')
01129                                 goto done;
01130                         /* pretend it was %c with argument ch */
01131                         cp = buf;
01132                         *cp = ch;
01133                         size = 1;
01134                         sign = '\0';
01135                         break;
01136                 }
01137 
01138                 /*
01139                  * All reasonable formats wind up here.  At this point, `cp'
01140                  * points to a string which (if not flags&LADJUST) should be
01141                  * padded out to `width' places.  If flags&ZEROPAD, it should
01142                  * first be prefixed by any sign or other prefix; otherwise,
01143                  * it should be blank padded before the prefix is emitted.
01144                  * After any left-hand padding and prefixing, emit zeroes
01145                  * required by a decimal [diouxX] precision, then print the
01146                  * string proper, then emit zeroes required by any leftover
01147                  * floating precision; finally, if LADJUST, pad with blanks.
01148                  *
01149                  * Compute actual size, so we know how much to pad.
01150                  * size excludes decimal prec; realsz includes it.
01151                  */
01152                 realsz = dprec > size ? dprec : size;
01153                 if (sign)
01154                         realsz++;
01155                 else if (flags & HEXPREFIX)
01156                         realsz+= 2;
01157 
01158                 /* right-adjusting blank padding */
01159                 if ((flags & (LADJUST|ZEROPAD)) == 0)
01160                         PAD(width - realsz, blanks, fp);
01161 
01162                 /* prefix */
01163                 if (sign) {
01164                         PRINT(&sign, 1, fp);
01165                 } else if (flags & HEXPREFIX) {
01166                         ox[0] = '0';
01167                         ox[1] = ch;
01168                         PRINT(ox, 2 ,fp);
01169                 }
01170 
01171                 /* right-adjusting zero padding */
01172                 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
01173                         PAD(width - realsz, zeroes, fp);
01174 
01175                 /* leading zeroes from decimal precision */
01176                 PAD(dprec - size, zeroes, fp);
01177 
01178                 /* the string or number proper */
01179 #ifdef FLOATING_POINT
01180                 if ((flags & FPT) == 0) {
01181                         PRINT(cp, size, fp);
01182                 } else {        /* glue together f_p fragments */
01183                         if (ch >= 'f') {        /* 'f' or 'g' */
01184                                 if (_fpvalue == 0) {
01185                                         /* kludge for __dtoa irregularity */
01186                                         PRINT("0", 1, fp);
01187                                         if (expt < ndig || (flags & ALT) != 0) {
01188                                                 PRINT(decimal_point, 1, fp);
01189                                                 PAD(ndig - 1, zeroes, fp);
01190                                         }
01191                                 } else if (expt <= 0) {
01192                                         PRINT("0", 1, fp);
01193                                         if(expt || ndig) {
01194                                                 PRINT(decimal_point, 1, fp);
01195                                                 PAD(-expt, zeroes, fp);
01196                                                 PRINT(cp, ndig, fp);
01197                                         }
01198                                 } else if (expt >= ndig) {
01199                                         PRINT(cp, ndig, fp);
01200                                         PAD(expt - ndig, zeroes, fp);
01201                                         if (flags & ALT)
01202                                                 PRINT(".", 1, fp);
01203                                 } else {
01204                                         PRINT(cp, expt, fp);
01205                                         cp += expt;
01206                                         PRINT(".", 1, fp);
01207                                         PRINT(cp, ndig-expt, fp);
01208                                 }
01209                         } else {        /* 'e' or 'E' */
01210                                 if (ndig > 1 || flags & ALT) {
01211                                         ox[0] = *cp++;
01212                                         ox[1] = '.';
01213                                         PRINT(ox, 2, fp);
01214                                        if (_fpvalue) {
01215                                                 PRINT(cp, ndig-1, fp);
01216                                         } else  /* 0.[0..] */
01217                                                 /* __dtoa irregularity */
01218                                                 PAD(ndig - 1, zeroes, fp);
01219                                 } else  /* XeYYY */
01220                                         PRINT(cp, 1, fp);
01221                                 PRINT(expstr, expsize, fp);
01222                         }
01223                 }
01224 #else
01225                 PRINT(cp, size, fp);
01226 #endif
01227                 /* left-adjusting padding (always blank) */
01228                 if (flags & LADJUST)
01229                         PAD(width - realsz, blanks, fp);
01230 
01231                 /* finally, adjust ret */
01232                 ret += width > realsz ? width : realsz;
01233 
01234                 FLUSH();        /* copy out the I/O vectors */
01235 
01236 #ifndef _SMALL_PRINTF
01237                 if (malloc_buf != NULL) {
01238                         free(malloc_buf);
01239                         malloc_buf = NULL;
01240                 }              
01241 #endif
01242         }
01243 done:
01244         FLUSH();
01245 error:
01246 
01247 #ifndef _SMALL_PRINTF
01248         if (malloc_buf != NULL)
01249                 free(malloc_buf);
01250         return (__sferror(fp) ? EOF : ret);
01251 #else
01252         return ret;
01253 #endif
01254         /* NOTREACHED */
01255 }
01256 
01257 #ifdef FLOATING_POINT
01258 
01259 #ifdef _NO_LONGDBL
01260 extern char *_dtoa_r _PARAMS((struct _reent *, double, int,
01261                               int, int *, int *, char **));
01262 #else
01263 extern char *_ldtoa_r _PARAMS((struct _reent *, _LONG_DOUBLE, int,
01264                               int, int *, int *, char **));
01265 #undef word0
01266 #define word0(x) ldword0(x)
01267 #endif
01268 
01269 static char *
01270 cvt(data, value, ndigits, flags, sign, decpt, ch, length)
01271         struct _reent *data;
01272 #ifdef _NO_LONGDBL
01273         double value;
01274 #else
01275         _LONG_DOUBLE value;
01276 #endif
01277         int ndigits, flags, *decpt, ch, *length;
01278         char *sign;
01279 {
01280         int mode, dsgn;
01281         char *digits, *bp, *rve;
01282 #ifdef _NO_LONGDBL
01283         union double_union tmp;
01284 #else
01285         struct ldieee *ldptr;
01286 #endif
01287 
01288         if (ch == 'f') {
01289                 mode = 3;               /* ndigits after the decimal point */
01290         } else {
01291                 /* To obtain ndigits after the decimal point for the 'e' 
01292                  * and 'E' formats, round to ndigits + 1 significant 
01293                  * figures.
01294                  */
01295                 if (ch == 'e' || ch == 'E') {
01296                         ndigits++;
01297                 }
01298                 mode = 2;               /* ndigits significant digits */
01299         }
01300 
01301 #ifdef _NO_LONGDBL
01302         tmp.d = value;
01303 
01304         if (word0(tmp) & Sign_bit) { /* this will check for < 0 and -0.0 */
01305                 value = -value;
01306                 *sign = '-';
01307         } else
01308                 *sign = '\000';
01309 
01310         digits = _dtoa_r(data, value, mode, ndigits, decpt, &dsgn, &rve);
01311 #else /* !_NO_LONGDBL */
01312         ldptr = (struct ldieee *)&value;
01313         if (ldptr->sign) { /* this will check for < 0 and -0.0 */
01314                 value = -value;
01315                 *sign = '-';
01316         } else
01317                 *sign = '\000';
01318 
01319         digits = _ldtoa_r(data, value, mode, ndigits, decpt, &dsgn, &rve);
01320 #endif /* !_NO_LONGDBL */
01321 
01322         if ((ch != 'g' && ch != 'G') || flags & ALT) {  /* Print trailing zeros */
01323                 bp = digits + ndigits;
01324                 if (ch == 'f') {
01325                         if (*digits == '0' && value)
01326                                 *decpt = -ndigits + 1;
01327                         bp += *decpt;
01328                 }
01329                 if (value == 0) /* kludge for __dtoa irregularity */
01330                         rve = bp;
01331                 while (rve < bp)
01332                         *rve++ = '0';
01333         }
01334         *length = rve - digits;
01335         return (digits);
01336 }
01337 
01338 static int
01339 exponent(p0, exp, fmtch)
01340         char *p0;
01341         int exp, fmtch;
01342 {
01343         register char *p, *t;
01344         char expbuf[40];
01345 
01346         p = p0;
01347         *p++ = fmtch;
01348         if (exp < 0) {
01349                 exp = -exp;
01350                 *p++ = '-';
01351         }
01352         else
01353                 *p++ = '+';
01354         t = expbuf + 40;
01355         if (exp > 9) {
01356                 do {
01357                         *--t = to_char(exp % 10);
01358                 } while ((exp /= 10) > 9);
01359                 *--t = to_char(exp);
01360                 for (; t < expbuf + 40; *p++ = *t++);
01361         }
01362         else {
01363                 *p++ = '0';
01364                 *p++ = to_char(exp);
01365         }
01366         return (p - p0);
01367 }
01368 #endif /* FLOATING_POINT */
01369 
01370 
01371 #ifndef _NO_POS_ARGS
01372 
01373 /* Positional argument support.
01374    Written by Jeff Johnston
01375 
01376    Copyright (c) 2002 Red Hat Incorporated.
01377    All rights reserved.
01378 
01379    Redistribution and use in source and binary forms, with or without
01380    modification, are permitted provided that the following conditions are met:
01381 
01382       Redistributions of source code must retain the above copyright
01383       notice, this list of conditions and the following disclaimer.
01384 
01385       Redistributions in binary form must reproduce the above copyright
01386       notice, this list of conditions and the following disclaimer in the
01387       documentation and/or other materials provided with the distribution.
01388       
01389       The name of Red Hat Incorporated may not be used to endorse
01390       or promote products derived from this software without specific
01391       prior written permission.
01392 
01393    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
01394    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
01395    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
01396    DISCLAIMED.  IN NO EVENT SHALL RED HAT INCORPORATED BE LIABLE FOR ANY
01397    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
01398    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
01399    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
01400    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
01401    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
01402    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
01403 
01404 typedef enum {
01405   ZERO,   /* '0' */
01406   DIGIT,  /* '1-9' */
01407   DOLLAR, /* '$' */
01408   MODFR,  /* spec modifier */
01409   SPEC,   /* format specifier */
01410   DOT,    /* '.' */
01411   STAR,   /* '*' */
01412   FLAG,   /* format flag */
01413   OTHER,  /* all other chars */ 
01414   MAX_CH_CLASS /* place-holder */
01415 } CH_CLASS;
01416 
01417 typedef enum { 
01418   START,  /* start */
01419   SFLAG,  /* seen a flag */
01420   WDIG,   /* seen digits in width area */
01421   WIDTH,  /* processed width */
01422   SMOD,   /* seen spec modifier */
01423   SDOT,   /* seen dot */ 
01424   VARW,   /* have variable width specifier */
01425   VARP,   /* have variable precision specifier */
01426   PREC,   /* processed precision */
01427   VWDIG,  /* have digits in variable width specification */
01428   VPDIG,  /* have digits in variable precision specification */
01429   DONE,   /* done */   
01430   MAX_STATE, /* place-holder */ 
01431 } STATE;
01432 
01433 typedef enum {
01434   NOOP,  /* do nothing */
01435   NUMBER, /* build a number from digits */
01436   SKIPNUM, /* skip over digits */
01437   GETMOD,  /* get and process format modifier */
01438   GETARG,  /* get and process argument */
01439   GETPW,   /* get variable precision or width */
01440   GETPWB,  /* get variable precision or width and pushback fmt char */
01441   GETPOS,  /* get positional parameter value */
01442   PWPOS,   /* get positional parameter value for variable width or precision */
01443 } ACTION;
01444 
01445 const static CH_CLASS chclass[256] = {
01446   /* 00-07 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01447   /* 08-0f */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01448   /* 10-17 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01449   /* 18-1f */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01450   /* 20-27 */  FLAG,    OTHER,   OTHER,   FLAG,    DOLLAR,  OTHER,   OTHER,   OTHER,
01451   /* 28-2f */  OTHER,   OTHER,   STAR,    FLAG,    OTHER,   FLAG,    DOT,     OTHER,
01452   /* 30-37 */  ZERO,    DIGIT,   DIGIT,   DIGIT,   DIGIT,   DIGIT,   DIGIT,   DIGIT,
01453   /* 38-3f */  DIGIT,   DIGIT,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01454   /* 40-47 */  OTHER,   OTHER,   OTHER,   SPEC,    SPEC,    SPEC,    OTHER,   SPEC, 
01455   /* 48-4f */  OTHER,   OTHER,   OTHER,   OTHER,   MODFR,   OTHER,   OTHER,   SPEC, 
01456   /* 50-57 */  OTHER,   OTHER,   OTHER,   SPEC,    OTHER,   SPEC,    OTHER,   SPEC, 
01457   /* 58-5f */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01458   /* 60-67 */  OTHER,   OTHER,   OTHER,   SPEC,    SPEC,    SPEC,    SPEC,    SPEC, 
01459   /* 68-6f */  MODFR,   SPEC,    OTHER,   OTHER,   MODFR,   OTHER,   OTHER,   SPEC, 
01460   /* 70-77 */  SPEC,    MODFR,   OTHER,   SPEC,    OTHER,   SPEC,    OTHER,   OTHER,
01461   /* 78-7f */  SPEC,    OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01462   /* 80-87 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01463   /* 88-8f */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01464   /* 90-97 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01465   /* 98-9f */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01466   /* a0-a7 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01467   /* a8-af */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01468   /* b0-b7 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01469   /* b8-bf */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01470   /* c0-c7 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01471   /* c8-cf */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01472   /* d0-d7 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01473   /* d8-df */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01474   /* e0-e7 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01475   /* e8-ef */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01476   /* f0-f7 */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01477   /* f8-ff */  OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,   OTHER,
01478 };
01479 
01480 const static STATE state_table[MAX_STATE][MAX_CH_CLASS] = {
01481   /*             '0'     '1-9'     '$'     MODFR    SPEC    '.'     '*'    FLAG    OTHER */ 
01482   /* START */  { SFLAG,   WDIG,    DONE,   SMOD,    DONE,   SDOT,  VARW,   SFLAG,  DONE },
01483   /* SFLAG */  { SFLAG,   WDIG,    DONE,   SMOD,    DONE,   SDOT,  VARW,   SFLAG,  DONE },
01484   /* WDIG  */  { DONE,    DONE,    WIDTH,  SMOD,    DONE,   SDOT,  DONE,   DONE,   DONE },
01485   /* WIDTH */  { DONE,    DONE,    DONE,   SMOD,    DONE,   SDOT,  DONE,   DONE,   DONE },
01486   /* SMOD  */  { DONE,    DONE,    DONE,   DONE,    DONE,   DONE,  DONE,   DONE,   DONE },
01487   /* SDOT  */  { SDOT,    PREC,    DONE,   SMOD,    DONE,   DONE,  VARP,   DONE,   DONE },
01488   /* VARW  */  { DONE,    VWDIG,   DONE,   SMOD,    DONE,   SDOT,  DONE,   DONE,   DONE },
01489   /* VARP  */  { DONE,    VPDIG,   DONE,   SMOD,    DONE,   DONE,  DONE,   DONE,   DONE },
01490   /* PREC  */  { DONE,    DONE,    DONE,   SMOD,    DONE,   DONE,  DONE,   DONE,   DONE },
01491   /* VWDIG */  { DONE,    DONE,    WIDTH,  DONE,    DONE,   DONE,  DONE,   DONE,   DONE },
01492   /* VPDIG */  { DONE,    DONE,    PREC,   DONE,    DONE,   DONE,  DONE,   DONE,   DONE },
01493 };
01494 
01495 const static ACTION action_table[MAX_STATE][MAX_CH_CLASS] = {
01496   /*             '0'     '1-9'     '$'     MODFR    SPEC    '.'     '*'    FLAG    OTHER */ 
01497   /* START */  { NOOP,    NUMBER,  NOOP,   GETMOD,  GETARG, NOOP,  NOOP,   NOOP,   NOOP },
01498   /* SFLAG */  { NOOP,    NUMBER,  NOOP,   GETMOD,  GETARG, NOOP,  NOOP,   NOOP,   NOOP },
01499   /* WDIG  */  { NOOP,    NOOP,    GETPOS, GETMOD,  GETARG, NOOP,  NOOP,   NOOP,   NOOP },
01500   /* WIDTH */  { NOOP,    NOOP,    NOOP,   GETMOD,  GETARG, NOOP,  NOOP,   NOOP,   NOOP },
01501   /* SMOD  */  { NOOP,    NOOP,    NOOP,   NOOP,    GETARG, NOOP,  NOOP,   NOOP,   NOOP },
01502   /* SDOT  */  { NOOP,    SKIPNUM, NOOP,   GETMOD,  GETARG, NOOP,  NOOP,   NOOP,   NOOP },
01503   /* VARW  */  { NOOP,    NUMBER,  NOOP,   GETPW,   GETPWB, GETPW, NOOP,   NOOP,   NOOP },
01504   /* VARP  */  { NOOP,    NUMBER,  NOOP,   GETPW,   GETPWB, NOOP,  NOOP,   NOOP,   NOOP },
01505   /* PREC  */  { NOOP,    NOOP,    NOOP,   GETMOD,  GETARG, NOOP,  NOOP,   NOOP,   NOOP },
01506   /* VWDIG */  { NOOP,    NOOP,    PWPOS,  NOOP,    NOOP,   NOOP,  NOOP,   NOOP,   NOOP },
01507   /* VPDIG */  { NOOP,    NOOP,    PWPOS,  NOOP,    NOOP,   NOOP,  NOOP,   NOOP,   NOOP },
01508 };
01509 
01510 /* function to get positional parameter N where n = N - 1 */
01511 static union arg_val *
01512 get_arg (struct _reent *data, int n, char *fmt, va_list *ap, 
01513          int *numargs_p, union arg_val *args, 
01514          int *arg_type, char **last_fmt) 
01515 {
01516   int ch;
01517   int number, flags;
01518   int spec_type;
01519   int numargs = *numargs_p;
01520   CH_CLASS chtype;
01521   STATE state, next_state;
01522   ACTION action;
01523   int pos, last_arg;
01524   int max_pos_arg = n;
01525   enum types { INT, LONG_INT, SHORT_INT, QUAD_INT, CHAR, CHAR_PTR, DOUBLE, LONG_DOUBLE, WIDE_CHAR };
01526 #ifdef MB_CAPABLE
01527   wchar_t wc;
01528   mbstate_t wc_state;
01529   int nbytes; 
01530 #endif
01531     
01532   /* if this isn't the first call, pick up where we left off last time */
01533   if (*last_fmt != NULL)
01534     fmt = *last_fmt;
01535 
01536 #ifdef MB_CAPABLE
01537   memset (&wc_state, '\0', sizeof (wc_state));
01538 #endif
01539 
01540   /* we need to process either to end of fmt string or until we have actually
01541      read the desired parameter from the vararg list. */
01542   while (*fmt && n >= numargs)
01543     {
01544 #ifdef MB_CAPABLE
01545       while ((nbytes = _mbtowc_r(data, &wc, fmt, MB_CUR_MAX, &wc_state)) > 0) 
01546         {
01547           fmt += nbytes;
01548           if (wc == '%') 
01549             break;
01550         }
01551 
01552       if (nbytes <= 0)
01553         break;
01554 #else
01555       while (*fmt != '\0' && *fmt != '%')
01556         fmt += 1;
01557 
01558       if (*fmt == '\0')
01559         break;
01560 #endif
01561       state = START;
01562       flags = 0;
01563       pos = -1;
01564       number = 0;
01565       spec_type = INT;
01566 
01567       /* Use state/action table to process format specifiers.  We ignore invalid
01568          formats and we are only interested in information that tells us how to
01569          read the vararg list. */
01570       while (state != DONE)
01571         {
01572           ch = *fmt++;
01573           chtype = chclass[ch];
01574           next_state = state_table[state][chtype];
01575           action = action_table[state][chtype];
01576           state = next_state;
01577           
01578           switch (action)
01579             {
01580             case GETMOD:  /* we have format modifier */
01581               switch (ch)
01582                 {
01583                 case 'h':
01584                   flags |= SHORTINT;
01585                   break;
01586                 case 'L':
01587                   flags |= LONGDBL;
01588                   break;
01589                 case 'q':
01590                   flags |= QUADINT;
01591                   break;
01592                 case 'l':
01593                 default:
01594                   if (*fmt == 'l')
01595                     {
01596                       flags |= QUADINT;
01597                       ++fmt;
01598                     }
01599                   else
01600                     flags |= LONGINT;
01601                   break;
01602                 }
01603               break;
01604             case GETARG: /* we have format specifier */
01605               {
01606                 numargs &= (MAX_POS_ARGS - 1);
01607                 /* process the specifier and translate it to a type to fetch from varargs */
01608                 switch (ch)
01609                   {
01610                   case 'd':
01611                   case 'i':
01612                   case 'o':
01613                   case 'x':
01614                   case 'X':
01615                   case 'u':
01616                     if (flags & LONGINT)
01617                       spec_type = LONG_INT;
01618                     else if (flags & SHORTINT)
01619                       spec_type = SHORT_INT;
01620 #ifndef _NO_LONGLONG
01621                     else if (flags & QUADINT)
01622                       spec_type = QUAD_INT;
01623 #endif
01624                     else
01625                       spec_type = INT;
01626                     break;
01627                   case 'D':
01628                   case 'U':
01629                   case 'O':
01630                     spec_type = LONG_INT;
01631                     break;
01632                   case 'f':
01633                   case 'g':
01634                   case 'G':
01635                   case 'E':
01636                   case 'e':
01637 #ifndef _NO_LONGDBL
01638                     if (flags & LONGDBL)
01639                       spec_type = LONG_DOUBLE;
01640                     else
01641 #endif
01642                       spec_type = DOUBLE;
01643                     break;
01644                   case 's':
01645                   case 'S':
01646                   case 'p':
01647                     spec_type = CHAR_PTR;
01648                     break;
01649                   case 'c':
01650                     spec_type = CHAR;
01651                     break;
01652                   case 'C':
01653                     spec_type = WIDE_CHAR;
01654                     break;
01655                   }
01656 
01657                 /* if we have a positional parameter, just store the type, otherwise
01658                    fetch the parameter from the vararg list */
01659                 if (pos != -1)
01660                   arg_type[pos] = spec_type;
01661                 else
01662                   {
01663                     switch (spec_type)
01664                       {
01665                       case LONG_INT:
01666                         args[numargs++].val_long = va_arg(*ap, long);
01667                         break;
01668                       case QUAD_INT:
01669                         args[numargs++].val_quad_t = va_arg(*ap, quad_t);
01670                         break;
01671                       case WIDE_CHAR:
01672                         args[numargs++].val_wint_t = va_arg(*ap, wint_t);
01673                         break;
01674                       case CHAR:
01675                       case SHORT_INT:
01676                       case INT:
01677                         args[numargs++].val_int = va_arg(*ap, int);
01678                         break;
01679                       case CHAR_PTR:
01680                         args[numargs++].val_char_ptr_t = va_arg(*ap, char *);
01681                         break;
01682                       case DOUBLE:
01683                         args[numargs++].val_double = va_arg(*ap, double);
01684                         break;
01685                       case LONG_DOUBLE:
01686                         args[numargs++].val__LONG_DOUBLE = va_arg(*ap, _LONG_DOUBLE);
01687                         break;
01688                       }
01689                   }
01690               }
01691               break;
01692             case GETPOS: /* we have positional specifier */
01693               if (arg_type[0] == -1)
01694                 memset (arg_type, 0, sizeof(int) * MAX_POS_ARGS);
01695               pos = number - 1;
01696               max_pos_arg = (max_pos_arg > pos ? max_pos_arg : pos);
01697               break;
01698             case PWPOS:  /* we have positional specifier for width or precision */
01699               if (arg_type[0] == -1)
01700                 memset (arg_type, 0, sizeof(int) * MAX_POS_ARGS);
01701               number -= 1;
01702               arg_type[number] = INT;
01703               max_pos_arg = (max_pos_arg > number ? max_pos_arg : number);
01704               break;
01705             case GETPWB: /* we require format pushback */
01706               --fmt;
01707               /* fallthrough */
01708             case GETPW:  /* we have a variable precision or width to acquire */
01709               args[numargs++].val_int = va_arg(*ap, int);
01710               break;
01711             case NUMBER: /* we have a number to process */
01712               number = (ch - '0');
01713               while ((ch = *fmt) != '\0' && is_digit(ch))
01714                 {
01715                   number = number * 10 + (ch - '0');
01716                   ++fmt;
01717                 }
01718               break;
01719             case SKIPNUM: /* we have a number to skip */
01720               while ((ch = *fmt) != '\0' && is_digit(ch))
01721                 ++fmt;
01722               break;
01723             case NOOP:
01724             default:
01725               break; /* do nothing */
01726             }
01727         }
01728     }
01729 
01730   /* process all arguments up to at least the one we are looking for and if we
01731      have seen the end of the string, then process up to the max argument needed */
01732   if (*fmt == '\0')
01733     last_arg = max_pos_arg;
01734   else
01735     last_arg = n;
01736 
01737   while (numargs <= last_arg)
01738     {
01739       switch (arg_type[numargs])
01740         {
01741         case LONG_INT:
01742           args[numargs++].val_long = va_arg(*ap, long);
01743           break;
01744         case QUAD_INT:
01745           args[numargs++].val_quad_t = va_arg(*ap, quad_t);
01746           break;
01747         case CHAR_PTR:
01748           args[numargs++].val_char_ptr_t = va_arg(*ap, char *);
01749           break;
01750         case DOUBLE:
01751           args[numargs++].val_double = va_arg(*ap, double);
01752           break;
01753         case LONG_DOUBLE:
01754           args[numargs++].val__LONG_DOUBLE = va_arg(*ap, _LONG_DOUBLE);
01755           break;
01756         case WIDE_CHAR:
01757           args[numargs++].val_wint_t = va_arg(*ap, wint_t);
01758           break;
01759         case INT:
01760         case SHORT_INT:
01761         case CHAR:
01762         default:
01763           args[numargs++].val_int = va_arg(*ap, int);
01764           break;
01765         }
01766     }
01767 
01768   /* alter the global numargs value and keep a reference to the last bit of the fmt
01769      string we processed here because the caller will continue processing where we started */
01770   *numargs_p = numargs;
01771   *last_fmt = fmt;
01772   return &args[n];
01773 }
01774 #endif /* !_NO_POS_ARGS */