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

Generated on Mon Apr 11 14:23:39 2011 for Contiki 2.5 by  doxygen 1.6.1