Ruby  2.0.0p481(2014-05-08revision45883)
vsnprintf.c
Go to the documentation of this file.
00001 /*-
00002  * Copyright (c) 1990, 1993
00003  *      The Regents of the University of California.  All rights reserved.
00004  *
00005  * This code is derived from software contributed to Berkeley by
00006  * Chris Torek.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  * 3. Neither the name of the University nor the names of its contributors
00017  *    may be used to endorse or promote products derived from this software
00018  *    without specific prior written permission.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00021  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00022  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00023  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00024  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00025  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00026  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00027  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00028  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00029  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00030  * SUCH DAMAGE.
00031  */
00032 
00033 /*
00034  * IMPORTANT NOTE:
00035  * --------------
00036  * From ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
00037  * paragraph 3 above is now null and void.
00038  */
00039 
00040 /* SNPRINTF.C
00041  * fjc 7-31-97 Modified by Mib Software to be a standalone snprintf.c module.
00042  *      http://www.mibsoftware.com
00043  * Mib Software does not warrant this software any differently than the
00044  * University of California, Berkeley as described above.  All warranties
00045  * are disclaimed.  Use this software at your own risk.
00046  *
00047  *      All code referencing FILE * functions was eliminated, since it could
00048  *      never be called.  All header files and necessary files are collapsed
00049  *      into one file, internal functions are declared static.  This should
00050  *      allow inclusion into libraries with less chance of namespace collisions.
00051  *
00052  *      snprintf should be the only externally visible item.
00053  *
00054  *      As of 7-31-97 FLOATING_POINT is NOT provided.  The code is somewhat
00055  *        non-portable, so it is disabled.
00056  */
00057 
00058 /* Define FLOATING_POINT to get floating point. */
00059 /*
00060 #define FLOATING_POINT
00061 */
00062 
00063 #include <sys/types.h>
00064 #define u_long unsigned long
00065 #define u_short unsigned short
00066 #define u_int unsigned int
00067 
00068 #if !defined(HAVE_STDARG_PROTOTYPES)
00069 #if defined(__STDC__)
00070 #define HAVE_STDARG_PROTOTYPES 1
00071 #endif
00072 #endif
00073 
00074 #undef __P
00075 #if defined(HAVE_STDARG_PROTOTYPES)
00076 # include <stdarg.h>
00077 # if !defined(__P)
00078 #  define __P(x) x
00079 # endif
00080 #else
00081 # define __P(x) ()
00082 # if !defined(const)
00083 #  define const
00084 # endif
00085 # include <varargs.h>
00086 #endif
00087 #ifndef _BSD_VA_LIST_
00088 #define _BSD_VA_LIST_ va_list
00089 #endif
00090 
00091 #ifdef __STDC__
00092 # include <limits.h>
00093 #else
00094 # ifndef LONG_MAX
00095 #  ifdef HAVE_LIMITS_H
00096 #   include <limits.h>
00097 #  else
00098     /* assuming 32bit(2's compliment) long */
00099 #   define LONG_MAX 2147483647
00100 #  endif
00101 # endif
00102 #endif
00103 
00104 #if defined(__hpux) && !defined(__GNUC__) && !defined(__STDC__)
00105 #define const
00106 #endif
00107 
00108 #if defined(sgi)
00109 #undef __const
00110 #define __const
00111 #endif /* People who don't like const sys_error */
00112 
00113 #include <stddef.h>
00114 #if defined(__hpux) && !defined(__GNUC__) || defined(__DECC)
00115 #include <string.h>
00116 #endif
00117 
00118 #if !defined(__CYGWIN32__) && defined(__hpux) && !defined(__GNUC__)
00119 #include <stdlib.h>
00120 #endif
00121 
00122 #ifndef NULL
00123 #define NULL    0
00124 #endif
00125 
00126 #if SIZEOF_LONG > SIZEOF_INT
00127 # include <errno.h>
00128 #endif
00129 
00130 #if __GNUC__ >= 3
00131 #define UNINITIALIZED_VAR(x) x = x
00132 #else
00133 #define UNINITIALIZED_VAR(x) x
00134 #endif
00135 
00136 /*
00137  * NB: to fit things in six character monocase externals, the stdio
00138  * code uses the prefix `__s' for stdio objects, typically followed
00139  * by a three-character attempt at a mnemonic.
00140  */
00141 
00142 /* stdio buffers */
00143 struct __sbuf {
00144         unsigned char *_base;
00145         size_t  _size;
00146 };
00147 
00148 
00149 /*
00150  * stdio state variables.
00151  *
00152  * The following always hold:
00153  *
00154  *      if (_flags&(__SLBF|__SWR)) == (__SLBF|__SWR),
00155  *              _lbfsize is -_bf._size, else _lbfsize is 0
00156  *      if _flags&__SRD, _w is 0
00157  *      if _flags&__SWR, _r is 0
00158  *
00159  * This ensures that the getc and putc macros (or inline functions) never
00160  * try to write or read from a file that is in `read' or `write' mode.
00161  * (Moreover, they can, and do, automatically switch from read mode to
00162  * write mode, and back, on "r+" and "w+" files.)
00163  *
00164  * _lbfsize is used only to make the inline line-buffered output stream
00165  * code as compact as possible.
00166  *
00167  * _ub, _up, and _ur are used when ungetc() pushes back more characters
00168  * than fit in the current _bf, or when ungetc() pushes back a character
00169  * that does not match the previous one in _bf.  When this happens,
00170  * _ub._base becomes non-nil (i.e., a stream has ungetc() data iff
00171  * _ub._base!=NULL) and _up and _ur save the current values of _p and _r.
00172  *
00173  * NB: see WARNING above before changing the layout of this structure!
00174  */
00175 typedef struct __sFILE {
00176         unsigned char *_p;      /* current position in (some) buffer */
00177 #if 0
00178         size_t  _r;             /* read space left for getc() */
00179 #endif
00180         size_t  _w;             /* write space left for putc() */
00181         short   _flags;         /* flags, below; this FILE is free if 0 */
00182         short   _file;          /* fileno, if Unix descriptor, else -1 */
00183         struct  __sbuf _bf;     /* the buffer (at least 1 byte, if !NULL) */
00184         size_t  _lbfsize;       /* 0 or -_bf._size, for inline putc */
00185         int     (*vwrite)(/* struct __sFILE*, struct __suio * */);
00186         char    *(*vextra)(/* struct __sFILE*, size_t, void*, long*, int */);
00187 } FILE;
00188 
00189 
00190 #define __SLBF  0x0001          /* line buffered */
00191 #define __SNBF  0x0002          /* unbuffered */
00192 #define __SRD   0x0004          /* OK to read */
00193 #define __SWR   0x0008          /* OK to write */
00194         /* RD and WR are never simultaneously asserted */
00195 #define __SRW   0x0010          /* open for reading & writing */
00196 #define __SEOF  0x0020          /* found EOF */
00197 #define __SERR  0x0040          /* found error */
00198 #define __SMBF  0x0080          /* _buf is from malloc */
00199 #define __SAPP  0x0100          /* fdopen()ed in append mode */
00200 #define __SSTR  0x0200          /* this is an sprintf/snprintf string */
00201 #define __SOPT  0x0400          /* do fseek() optimisation */
00202 #define __SNPT  0x0800          /* do not do fseek() optimisation */
00203 #define __SOFF  0x1000          /* set iff _offset is in fact correct */
00204 #define __SMOD  0x2000          /* true => fgetln modified _p text */
00205 
00206 
00207 #define EOF     (-1)
00208 
00209 
00210 #define BSD__sfeof(p)   (((p)->_flags & __SEOF) != 0)
00211 #define BSD__sferror(p) (((p)->_flags & __SERR) != 0)
00212 #define BSD__sclearerr(p)       ((void)((p)->_flags &= ~(__SERR|__SEOF)))
00213 #define BSD__sfileno(p) ((p)->_file)
00214 
00215 #undef feof
00216 #undef ferror
00217 #undef clearerr
00218 #define feof(p)         BSD__sfeof(p)
00219 #define ferror(p)       BSD__sferror(p)
00220 #define clearerr(p)     BSD__sclearerr(p)
00221 
00222 #ifndef _ANSI_SOURCE
00223 #define fileno(p)       BSD__sfileno(p)
00224 #endif
00225 
00226 
00227 /*
00228  * I/O descriptors for __sfvwrite().
00229  */
00230 struct __siov {
00231         const void *iov_base;
00232         size_t  iov_len;
00233 };
00234 struct __suio {
00235         struct  __siov *uio_iov;
00236         int     uio_iovcnt;
00237         size_t  uio_resid;
00238 };
00239 
00240 /*
00241  * Write some memory regions.  Return zero on success, EOF on error.
00242  *
00243  * This routine is large and unsightly, but most of the ugliness due
00244  * to the three different kinds of output buffering is handled here.
00245  */
00246 static int
00247 BSD__sfvwrite(register FILE *fp, register struct __suio *uio)
00248 {
00249         register size_t len;
00250         register const char *p;
00251         register struct __siov *iov;
00252         register size_t w;
00253 
00254         if ((len = uio->uio_resid) == 0)
00255                 return (0);
00256 #ifndef __hpux
00257 #define MIN(a, b) ((a) < (b) ? (a) : (b))
00258 #endif
00259 #define COPY(n)   (void)memcpy((void *)fp->_p, (void *)p, (size_t)(n))
00260 
00261         iov = uio->uio_iov;
00262         p = iov->iov_base;
00263         len = iov->iov_len;
00264         iov++;
00265 #define GETIOV(extra_work) \
00266         while (len == 0) { \
00267                 extra_work; \
00268                 p = iov->iov_base; \
00269                 len = iov->iov_len; \
00270                 iov++; \
00271         }
00272         if (fp->_flags & __SNBF) {
00273         /* fjc 7-31-97 Will never happen.  We are working with
00274                                            strings only
00275         */
00276         } else if ((fp->_flags & __SLBF) == 0) {
00277         /*
00278                  * Fully buffered: fill partially full buffer, if any,
00279                  * and then flush.  If there is no partial buffer, write
00280                  * one _bf._size byte chunk directly (without copying).
00281                  *
00282                  * String output is a special case: write as many bytes
00283                  * as fit, but pretend we wrote everything.  This makes
00284                  * snprintf() return the number of bytes needed, rather
00285                  * than the number used, and avoids its write function
00286                  * (so that the write function can be invalid).
00287                  */
00288                 do {
00289                         GETIOV(;);
00290                         w = fp->_w;
00291                         if (fp->_flags & __SSTR) {
00292                                 if (len < w)
00293                                         w = len;
00294                                 COPY(w);        /* copy MIN(fp->_w,len), */
00295                                 fp->_w -= w;
00296                                 fp->_p += w;
00297                                 w = len;        /* but pretend copied all */
00298                         } else {
00299                                 /* fjc 7-31-97 Will never happen.  We are working with
00300                                                                    strings only
00301                                 */
00302                         }
00303                         p += w;
00304                         len -= w;
00305                 } while ((uio->uio_resid -= w) != 0);
00306         } else {
00307                 /* fjc 7-31-97 Will never happen.  We are working with
00308                                                    strings only
00309                 */
00310         }
00311         return (0);
00312 }
00313 
00314 /*
00315  * Actual printf innards.
00316  *
00317  * This code is large and complicated...
00318  */
00319 
00320 /*
00321  * Flush out all the vectors defined by the given uio,
00322  * then reset it so that it can be reused.
00323  */
00324 static int
00325 BSD__sprint(FILE *fp, register struct __suio *uio)
00326 {
00327         register int err;
00328 
00329         if (uio->uio_resid == 0) {
00330                 uio->uio_iovcnt = 0;
00331                 return (0);
00332         }
00333         err = (*fp->vwrite)(fp, uio);
00334         uio->uio_resid = 0;
00335         uio->uio_iovcnt = 0;
00336         return (err);
00337 }
00338 
00339 
00340 /*
00341  * Helper function for `fprintf to unbuffered unix file': creates a
00342  * temporary buffer.  We only work on write-only files; this avoids
00343  * worries about ungetc buffers and so forth.
00344  */
00345 static int
00346 BSD__sbprintf(register FILE *fp, const char *fmt, va_list ap)
00347 {
00348 /* We don't support files. */
00349         return 0;
00350 }
00351 
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)      (char)((n) + '0')
00359 
00360 #ifdef _HAVE_SANE_QUAD_
00361 /*
00362  * Convert an unsigned long long to ASCII for printf purposes, returning
00363  * a pointer to the first character of the string representation.
00364  * Octal numbers can be forced to have a leading zero; hex numbers
00365  * use the given digits.
00366  */
00367 static char *
00368 BSD__uqtoa(register u_quad_t val, char *endp, int base, int octzero, const char *xdigs)
00369 {
00370         register char *cp = endp;
00371         register quad_t sval;
00372 
00373         /*
00374          * Handle the three cases separately, in the hope of getting
00375          * better/faster code.
00376          */
00377         switch (base) {
00378         case 10:
00379                 if (val < 10) { /* many numbers are 1 digit */
00380                         *--cp = to_char(val);
00381                         return (cp);
00382                 }
00383                 /*
00384                  * On many machines, unsigned arithmetic is harder than
00385                  * signed arithmetic, so we do at most one unsigned mod and
00386                  * divide; this is sufficient to reduce the range of
00387                  * the incoming value to where signed arithmetic works.
00388                  */
00389                 if (val > LLONG_MAX) {
00390                         *--cp = to_char(val % 10);
00391                         sval = val / 10;
00392                 } else
00393                         sval = val;
00394                 do {
00395                         *--cp = to_char(sval % 10);
00396                         sval /= 10;
00397                 } while (sval != 0);
00398                 break;
00399 
00400         case 8:
00401                 do {
00402                         *--cp = to_char(val & 7);
00403                         val >>= 3;
00404                 } while (val);
00405                 if (octzero && *cp != '0')
00406                         *--cp = '0';
00407                 break;
00408 
00409         case 16:
00410                 do {
00411                         *--cp = xdigs[val & 15];
00412                         val >>= 4;
00413                 } while (val);
00414                 break;
00415 
00416         default:                        /* oops */
00417                 /*
00418                 abort();
00419                 */
00420                 break;  /* fjc 7-31-97.  Don't reference abort() here */
00421         }
00422         return (cp);
00423 }
00424 #endif /* _HAVE_SANE_QUAD_ */
00425 
00426 /*
00427  * Convert an unsigned long to ASCII for printf purposes, returning
00428  * a pointer to the first character of the string representation.
00429  * Octal numbers can be forced to have a leading zero; hex numbers
00430  * use the given digits.
00431  */
00432 static char *
00433 BSD__ultoa(register u_long val, char *endp, int base, int octzero, const char *xdigs)
00434 {
00435         register char *cp = endp;
00436         register long sval;
00437 
00438         /*
00439          * Handle the three cases separately, in the hope of getting
00440          * better/faster code.
00441          */
00442         switch (base) {
00443         case 10:
00444                 if (val < 10) { /* many numbers are 1 digit */
00445                         *--cp = to_char(val);
00446                         return (cp);
00447                 }
00448                 /*
00449                  * On many machines, unsigned arithmetic is harder than
00450                  * signed arithmetic, so we do at most one unsigned mod and
00451                  * divide; this is sufficient to reduce the range of
00452                  * the incoming value to where signed arithmetic works.
00453                  */
00454                 if (val > LONG_MAX) {
00455                         *--cp = to_char(val % 10);
00456                         sval = val / 10;
00457                 } else
00458                         sval = val;
00459                 do {
00460                         *--cp = to_char(sval % 10);
00461                         sval /= 10;
00462                 } while (sval != 0);
00463                 break;
00464 
00465         case 8:
00466                 do {
00467                         *--cp = to_char(val & 7);
00468                         val >>= 3;
00469                 } while (val);
00470                 if (octzero && *cp != '0')
00471                         *--cp = '0';
00472                 break;
00473 
00474         case 16:
00475                 do {
00476                         *--cp = xdigs[val & 15];
00477                         val >>= 4;
00478                 } while (val);
00479                 break;
00480 
00481         default:                        /* oops */
00482                 /*
00483                 abort();
00484                 */
00485                 break;  /* fjc 7-31-97.  Don't reference abort() here */
00486         }
00487         return (cp);
00488 }
00489 
00490 #ifdef FLOATING_POINT
00491 #include <math.h>
00492 #include <float.h>
00493 /* #include "floatio.h" */
00494 
00495 #ifndef MAXEXP
00496 # if DBL_MAX_10_EXP > -DBL_MIN_10_EXP
00497 #   define MAXEXP (DBL_MAX_10_EXP)
00498 # else
00499 #   define MAXEXP (-DBL_MIN_10_EXP)
00500 # endif
00501 #endif
00502 
00503 #ifndef MAXFRACT
00504 # define MAXFRACT (MAXEXP*10/3)
00505 #endif
00506 
00507 #define BUF             (MAXEXP+MAXFRACT+1)     /* + decimal point */
00508 #define DEFPREC         6
00509 
00510 static char *cvt(double, int, int, char *, int *, int, int *, char *);
00511 static int exponent(char *, int, int);
00512 
00513 #else /* no FLOATING_POINT */
00514 
00515 #define BUF             68
00516 
00517 #endif /* FLOATING_POINT */
00518 
00519 
00520 /*
00521  * Flags used during conversion.
00522  */
00523 #define ALT             0x001           /* alternate form */
00524 #define HEXPREFIX       0x002           /* add 0x or 0X prefix */
00525 #define LADJUST         0x004           /* left adjustment */
00526 #define LONGDBL         0x008           /* long double; unimplemented */
00527 #define LONGINT         0x010           /* long integer */
00528 
00529 #ifdef _HAVE_SANE_QUAD_
00530 #define QUADINT         0x020           /* quad integer */
00531 #endif /* _HAVE_SANE_QUAD_ */
00532 
00533 #define SHORTINT        0x040           /* short integer */
00534 #define ZEROPAD         0x080           /* zero (as opposed to blank) pad */
00535 #define FPT             0x100           /* Floating point number */
00536 static ssize_t
00537 BSD_vfprintf(FILE *fp, const char *fmt0, va_list ap)
00538 {
00539         register const char *fmt; /* format string */
00540         register int ch;        /* character from fmt */
00541         register int n;         /* handy integer (short term usage) */
00542         register const char *cp;/* handy char pointer (short term usage) */
00543         register struct __siov *iovp;/* for PRINT macro */
00544         register int flags;     /* flags as above */
00545         ssize_t ret;            /* return value accumulator */
00546         int width;              /* width from format (%8d), or 0 */
00547         int prec;               /* precision from format (%.3d), or -1 */
00548         char sign;              /* sign prefix (' ', '+', '-', or \0) */
00549 #ifdef FLOATING_POINT
00550         char softsign;          /* temporary negative sign for floats */
00551         double _double = 0;     /* double precision arguments %[eEfgG] */
00552         int expt;               /* integer value of exponent */
00553         int expsize = 0;        /* character count for expstr */
00554         int ndig = 0;           /* actual number of digits returned by cvt */
00555         int fprec = 0;          /* floating point precision */
00556         char expstr[7];         /* buffer for exponent string */
00557 #endif
00558         u_long UNINITIALIZED_VAR(ulval); /* integer arguments %[diouxX] */
00559 #ifdef _HAVE_SANE_QUAD_
00560         u_quad_t UNINITIALIZED_VAR(uqval); /* %q integers */
00561 #endif /* _HAVE_SANE_QUAD_ */
00562         int base;               /* base for [diouxX] conversion */
00563         int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
00564         long fieldsz;           /* field size expanded by sign, etc */
00565         long realsz;            /* field size expanded by dprec */
00566         int size;               /* size of converted field or string */
00567         const char *xdigs = 0;  /* digits for [xX] conversion */
00568 #define NIOV 8
00569         struct __suio uio;      /* output information: summary */
00570         struct __siov iov[NIOV];/* ... and individual io vectors */
00571         char buf[BUF];          /* space for %c, %[diouxX], %[eEfgG] */
00572         char ox[4];             /* space for 0x hex-prefix, hexadecimal's 1. */
00573         char *const ebuf = buf + sizeof(buf);
00574 #if SIZEOF_LONG > SIZEOF_INT
00575         long ln;
00576 #endif
00577 
00578         /*
00579          * Choose PADSIZE to trade efficiency vs. size.  If larger printf
00580          * fields occur frequently, increase PADSIZE and make the initializers
00581          * below longer.
00582          */
00583 #define PADSIZE 16              /* pad chunk size */
00584         static const char blanks[PADSIZE] =
00585          {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
00586         static const char zeroes[PADSIZE] =
00587          {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
00588 
00589         /*
00590          * BEWARE, these `goto error' on error, and PAD uses `n'.
00591          */
00592 #define PRINT(ptr, len) { \
00593         iovp->iov_base = (ptr); \
00594         iovp->iov_len = (len); \
00595         uio.uio_resid += (len); \
00596         iovp++; \
00597         if (++uio.uio_iovcnt >= NIOV) { \
00598                 if (BSD__sprint(fp, &uio)) \
00599                         goto error; \
00600                 iovp = iov; \
00601         } \
00602 }
00603 #define PAD(howmany, with) { \
00604         if ((n = (howmany)) > 0) { \
00605                 while (n > PADSIZE) { \
00606                         PRINT((with), PADSIZE); \
00607                         n -= PADSIZE; \
00608                 } \
00609                 PRINT((with), n); \
00610         } \
00611 }
00612 #if SIZEOF_LONG > SIZEOF_INT
00613         /* abandon if too larger padding */
00614 #define PAD_L(howmany, with) { \
00615         ln = (howmany); \
00616         if ((long)((int)ln) != ln) { \
00617             errno = ENOMEM; \
00618             goto error; \
00619         } \
00620         if (ln > 0) PAD((int)ln, (with)); \
00621 }
00622 #else
00623 #define PAD_L(howmany, with) PAD((howmany), (with))
00624 #endif
00625 #define FLUSH() { \
00626         if (uio.uio_resid && BSD__sprint(fp, &uio)) \
00627                 goto error; \
00628         uio.uio_iovcnt = 0; \
00629         iovp = iov; \
00630 }
00631 
00632         /*
00633          * To extend shorts properly, we need both signed and unsigned
00634          * argument extraction methods.
00635          */
00636 #define SARG() \
00637         (flags&LONGINT ? va_arg(ap, long) : \
00638             flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
00639             (long)va_arg(ap, int))
00640 #define UARG() \
00641         (flags&LONGINT ? va_arg(ap, u_long) : \
00642             flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
00643             (u_long)va_arg(ap, u_int))
00644 
00645         /* optimise fprintf(stderr) (and other unbuffered Unix files) */
00646         if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
00647             fp->_file >= 0)
00648                 return (BSD__sbprintf(fp, fmt0, ap));
00649 
00650         fmt = fmt0;
00651         uio.uio_iov = iovp = iov;
00652         uio.uio_resid = 0;
00653         uio.uio_iovcnt = 0;
00654         ret = 0;
00655         xdigs = 0;
00656 
00657         /*
00658          * Scan the format for conversions (`%' character).
00659          */
00660         for (;;) {
00661                 size_t nc;
00662                 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
00663                         /* void */;
00664                 if ((nc = fmt - cp) != 0) {
00665                         PRINT(cp, nc);
00666                         ret += nc;
00667                 }
00668                 if (ch == '\0')
00669                         goto done;
00670                 fmt++;          /* skip over '%' */
00671 
00672                 flags = 0;
00673                 dprec = 0;
00674                 width = 0;
00675                 prec = -1;
00676                 sign = '\0';
00677 
00678 rflag:          ch = *fmt++;
00679 reswitch:       switch (ch) {
00680                 case ' ':
00681                         /*
00682                          * ``If the space and + flags both appear, the space
00683                          * flag will be ignored.''
00684                          *      -- ANSI X3J11
00685                          */
00686                         if (!sign)
00687                                 sign = ' ';
00688                         goto rflag;
00689                 case '#':
00690                         flags |= ALT;
00691                         goto rflag;
00692                 case '*':
00693                         /*
00694                          * ``A negative field width argument is taken as a
00695                          * - flag followed by a positive field width.''
00696                          *      -- ANSI X3J11
00697                          * They don't exclude field widths read from args.
00698                          */
00699                         if ((width = va_arg(ap, int)) >= 0)
00700                                 goto rflag;
00701                         width = -width;
00702                         /* FALLTHROUGH */
00703                 case '-':
00704                         flags |= LADJUST;
00705                         goto rflag;
00706                 case '+':
00707                         sign = '+';
00708                         goto rflag;
00709                 case '.':
00710                         if ((ch = *fmt++) == '*') {
00711                                 n = va_arg(ap, int);
00712                                 prec = n < 0 ? -1 : n;
00713                                 goto rflag;
00714                         }
00715                         n = 0;
00716                         while (is_digit(ch)) {
00717                                 n = 10 * n + to_digit(ch);
00718                                 ch = *fmt++;
00719                         }
00720                         prec = n < 0 ? -1 : n;
00721                         goto reswitch;
00722                 case '0':
00723                         /*
00724                          * ``Note that 0 is taken as a flag, not as the
00725                          * beginning of a field width.''
00726                          *      -- ANSI X3J11
00727                          */
00728                         flags |= ZEROPAD;
00729                         goto rflag;
00730                 case '1': case '2': case '3': case '4':
00731                 case '5': case '6': case '7': case '8': case '9':
00732                         n = 0;
00733                         do {
00734                                 n = 10 * n + to_digit(ch);
00735                                 ch = *fmt++;
00736                         } while (is_digit(ch));
00737                         width = n;
00738                         goto reswitch;
00739 #ifdef FLOATING_POINT
00740                 case 'L':
00741                         flags |= LONGDBL;
00742                         goto rflag;
00743 #endif
00744                 case 'h':
00745                         flags |= SHORTINT;
00746                         goto rflag;
00747 #if SIZEOF_PTRDIFF_T == SIZEOF_LONG
00748                 case 't':
00749 #endif
00750 #if SIZEOF_SIZE_T == SIZEOF_LONG
00751                 case 'z':
00752 #endif
00753                 case 'l':
00754 #ifdef _HAVE_SANE_QUAD_
00755                         if (*fmt == 'l') {
00756                                 fmt++;
00757                                 flags |= QUADINT;
00758                         } else {
00759                                 flags |= LONGINT;
00760                         }
00761 #else
00762                         flags |= LONGINT;
00763 #endif
00764                         goto rflag;
00765 #ifdef _HAVE_SANE_QUAD_
00766 #if SIZEOF_PTRDIFF_T == SIZEOF_LONG_LONG
00767                 case 't':
00768 #endif
00769 #if SIZEOF_SIZE_T == SIZEOF_LONG_LONG
00770                 case 'z':
00771 #endif
00772                 case 'q':
00773                         flags |= QUADINT;
00774                         goto rflag;
00775 #endif /* _HAVE_SANE_QUAD_ */
00776 #ifdef _WIN32
00777                 case 'I':
00778                         if (*fmt == '3' && *(fmt + 1) == '2') {
00779                             fmt += 2;
00780                             flags |= LONGINT;
00781                         }
00782 #ifdef _HAVE_SANE_QUAD_
00783                         else if (*fmt == '6' && *(fmt + 1) == '4') {
00784                             fmt += 2;
00785                             flags |= QUADINT;
00786                         }
00787 #endif
00788                         else
00789 #if defined(_HAVE_SANE_QUAD_) && SIZEOF_SIZE_T == SIZEOF_LONG_LONG
00790                             flags |= QUADINT;
00791 #else
00792                             flags |= LONGINT;
00793 #endif
00794                         goto rflag;
00795 #endif
00796                 case 'c':
00797                         cp = buf;
00798                         *buf = (char)va_arg(ap, int);
00799                         size = 1;
00800                         sign = '\0';
00801                         break;
00802                 case 'i':
00803 #ifdef _HAVE_SANE_QUAD_
00804 # define INTPTR_MASK (QUADINT|LONGINT|SHORTINT)
00805 #else
00806 # define INTPTR_MASK (LONGINT|SHORTINT)
00807 #endif
00808 #if defined _HAVE_SANE_QUAD_ && SIZEOF_VOIDP == SIZEOF_LONG_LONG
00809 # define INTPTR_FLAG QUADINT
00810 #elif SIZEOF_VOIDP == SIZEOF_LONG
00811 # define INTPTR_FLAG LONGINT
00812 #else
00813 # define INTPTR_FLAG 0
00814 #endif
00815                         if (fp->vextra && (flags & INTPTR_MASK) == INTPTR_FLAG) {
00816                                 FLUSH();
00817 #if defined _HAVE_SANE_QUAD_ && SIZEOF_VOIDP == SIZEOF_LONG_LONG
00818                                 uqval = va_arg(ap, u_quad_t);
00819                                 cp = (*fp->vextra)(fp, sizeof(uqval), &uqval, &fieldsz, sign);
00820 #else
00821                                 ulval = va_arg(ap, u_long);
00822                                 cp = (*fp->vextra)(fp, sizeof(ulval), &ulval, &fieldsz, sign);
00823 #endif
00824                                 sign = '\0';
00825                                 if (!cp) goto error;
00826                                 if (prec < 0) goto long_len;
00827                                 size = fieldsz < prec ? (int)fieldsz : prec;
00828                                 break;
00829                         }
00830                         goto decimal;
00831                 case 'D':
00832                         flags |= LONGINT;
00833                         /*FALLTHROUGH*/
00834                 case 'd':
00835                 decimal:
00836 #ifdef _HAVE_SANE_QUAD_
00837                         if (flags & QUADINT) {
00838                                 uqval = va_arg(ap, quad_t);
00839                                 if ((quad_t)uqval < 0) {
00840                                         uqval = -(quad_t)uqval;
00841                                         sign = '-';
00842                                 }
00843                         } else
00844 #endif /* _HAVE_SANE_QUAD_ */
00845                         {
00846                                 ulval = SARG();
00847                                 if ((long)ulval < 0) {
00848                                         ulval = (u_long)(-(long)ulval);
00849                                         sign = '-';
00850                                 }
00851                         }
00852                         base = 10;
00853                         goto number;
00854 #ifdef FLOATING_POINT
00855                 case 'a':
00856                 case 'A':
00857                         if (prec > 0) {
00858                                 flags |= ALT;
00859                                 prec++;
00860                                 fprec = prec;
00861                         }
00862                         goto fp_begin;
00863                 case 'e':               /* anomalous precision */
00864                 case 'E':
00865                         if (prec != 0)
00866                                 flags |= ALT;
00867                         prec = (prec == -1) ?
00868                                 DEFPREC + 1 : (fprec = prec + 1);
00869                         /* FALLTHROUGH */
00870                         goto fp_begin;
00871                 case 'f':               /* always print trailing zeroes */
00872                         if (prec != 0)
00873                                 flags |= ALT;
00874                 case 'g':
00875                 case 'G':
00876                         if (prec == -1)
00877                                 prec = DEFPREC;
00878                         else
00879                                 fprec = prec;
00880 fp_begin:               _double = va_arg(ap, double);
00881                         /* do this before tricky precision changes */
00882                         if (isinf(_double)) {
00883                                 if (_double < 0)
00884                                         sign = '-';
00885                                 cp = "Inf";
00886                                 size = 3;
00887                                 break;
00888                         }
00889                         if (isnan(_double)) {
00890                                 cp = "NaN";
00891                                 size = 3;
00892                                 break;
00893                         }
00894                         flags |= FPT;
00895                         cp = cvt(_double, (prec < MAXFRACT ? prec : MAXFRACT), flags, &softsign,
00896                                 &expt, ch, &ndig, buf);
00897                         if (ch == 'g' || ch == 'G') {
00898                                 if (expt <= -4 || (expt > prec && expt > 1))
00899                                         ch = (ch == 'g') ? 'e' : 'E';
00900                                 else
00901                                         ch = 'g';
00902                         }
00903                         if (ch == 'a' || ch == 'A') {
00904                                 flags |= HEXPREFIX;
00905                                 --expt;
00906                                 expsize = exponent(expstr, expt, ch + 'p' - 'a');
00907                                 ch += 'x' - 'a';
00908                                 size = expsize + ndig;
00909                                 if (ndig > 1 || flags & ALT)
00910                                         ++size; /* floating point */
00911                         }
00912                         else if (ch <= 'e') {   /* 'e' or 'E' fmt */
00913                                 --expt;
00914                                 expsize = exponent(expstr, expt, ch);
00915                                 size = expsize + ndig;
00916                                 if (ndig > 1 || flags & ALT)
00917                                         ++fprec, ++size;
00918                         } else if (ch == 'f') {         /* f fmt */
00919                                 if (expt > 0) {
00920                                         size = expt;
00921                                         if (prec || flags & ALT)
00922                                                 size += prec + 1;
00923                                 } else if (!prec) { /* "0" */
00924                                         size = 1;
00925                                         if (flags & ALT)
00926                                                 size += 1;
00927                                 } else  /* "0.X" */
00928                                         size = prec + 2;
00929                         } else if (expt >= ndig) {      /* fixed g fmt */
00930                                 size = expt;
00931                                 if (flags & ALT)
00932                                         ++size;
00933                         } else
00934                                 size = ndig + (expt > 0 ?
00935                                         1 : 2 - expt);
00936 
00937                         if (softsign)
00938                                 sign = '-';
00939                         break;
00940 #endif /* FLOATING_POINT */
00941                 case 'n':
00942 #ifdef _HAVE_SANE_QUAD_
00943                         if (flags & QUADINT)
00944                                 *va_arg(ap, quad_t *) = ret;
00945                         else if (flags & LONGINT)
00946 #else /* _HAVE_SANE_QUAD_ */
00947                         if (flags & LONGINT)
00948 #endif /* _HAVE_SANE_QUAD_ */
00949                                 *va_arg(ap, long *) = ret;
00950                         else if (flags & SHORTINT)
00951                                 *va_arg(ap, short *) = (short)ret;
00952                         else
00953                                 *va_arg(ap, int *) = (int)ret;
00954                         continue;       /* no output */
00955                 case 'O':
00956                         flags |= LONGINT;
00957                         /*FALLTHROUGH*/
00958                 case 'o':
00959 #ifdef _HAVE_SANE_QUAD_
00960                         if (flags & QUADINT)
00961                                 uqval = va_arg(ap, u_quad_t);
00962                         else
00963 #endif /* _HAVE_SANE_QUAD_ */
00964                                 ulval = UARG();
00965                         base = 8;
00966                         goto nosign;
00967                 case 'p':
00968                         /*
00969                          * ``The argument shall be a pointer to void.  The
00970                          * value of the pointer is converted to a sequence
00971                          * of printable characters, in an implementation-
00972                          * defined manner.''
00973                          *      -- ANSI X3J11
00974                          */
00975                         prec = (int)(sizeof(void*)*CHAR_BIT/4);
00976 #ifdef _HAVE_LLP64_
00977                         uqval = (u_quad_t)va_arg(ap, void *);
00978                         flags = (flags) | QUADINT | HEXPREFIX;
00979 #else
00980                         ulval = (u_long)va_arg(ap, void *);
00981 #ifdef _HAVE_SANE_QUAD_
00982                         flags = (flags & ~QUADINT) | HEXPREFIX;
00983 #else /* _HAVE_SANE_QUAD_ */
00984                         flags = (flags) | HEXPREFIX;
00985 #endif /* _HAVE_SANE_QUAD_ */
00986 #endif
00987                         base = 16;
00988                         xdigs = "0123456789abcdef";
00989                         ch = 'x';
00990                         goto nosign;
00991                 case 's':
00992                         if ((cp = va_arg(ap, char *)) == NULL)
00993                                 cp = "(null)";
00994                         if (prec >= 0) {
00995                                 /*
00996                                  * can't use strlen; can only look for the
00997                                  * NUL in the first `prec' characters, and
00998                                  * strlen() will go further.
00999                                  */
01000                                 const char *p = (char *)memchr(cp, 0, prec);
01001 
01002                                 if (p != NULL && (p - cp) > prec)
01003                                         size = (int)(p - cp);
01004                                 else
01005                                         size = prec;
01006                         }
01007                         else {
01008                                 fieldsz = strlen(cp);
01009                                 goto long_len;
01010                         }
01011                         sign = '\0';
01012                         break;
01013                 case 'U':
01014                         flags |= LONGINT;
01015                         /*FALLTHROUGH*/
01016                 case 'u':
01017 #ifdef _HAVE_SANE_QUAD_
01018                         if (flags & QUADINT)
01019                                 uqval = va_arg(ap, u_quad_t);
01020                         else
01021 #endif /* _HAVE_SANE_QUAD_ */
01022                                 ulval = UARG();
01023                         base = 10;
01024                         goto nosign;
01025                 case 'X':
01026                         xdigs = "0123456789ABCDEF";
01027                         goto hex;
01028                 case 'x':
01029                         xdigs = "0123456789abcdef";
01030 hex:
01031 #ifdef _HAVE_SANE_QUAD_
01032                         if (flags & QUADINT)
01033                                 uqval = va_arg(ap, u_quad_t);
01034                         else
01035 #endif /* _HAVE_SANE_QUAD_ */
01036                                 ulval = UARG();
01037                         base = 16;
01038                         /* leading 0x/X only if non-zero */
01039                         if (flags & ALT &&
01040 #ifdef _HAVE_SANE_QUAD_
01041                             (flags & QUADINT ? uqval != 0 : ulval != 0)
01042 #else /* _HAVE_SANE_QUAD_ */
01043                             ulval != 0
01044 #endif /* _HAVE_SANE_QUAD_ */
01045                             )
01046                                 flags |= HEXPREFIX;
01047 
01048                         /* unsigned conversions */
01049 nosign:                 sign = '\0';
01050                         /*
01051                          * ``... diouXx conversions ... if a precision is
01052                          * specified, the 0 flag will be ignored.''
01053                          *      -- ANSI X3J11
01054                          */
01055 number:                 if ((dprec = prec) >= 0)
01056                                 flags &= ~ZEROPAD;
01057 
01058                         /*
01059                          * ``The result of converting a zero value with an
01060                          * explicit precision of zero is no characters.''
01061                          *      -- ANSI X3J11
01062                          */
01063 #ifdef _HAVE_SANE_QUAD_
01064                         if (flags & QUADINT) {
01065                                 if (uqval != 0 || prec != 0)
01066                                         cp = BSD__uqtoa(uqval, ebuf, base,
01067                                             flags & ALT, xdigs);
01068                         } else
01069 #else /* _HAVE_SANE_QUAD_ */
01070 #endif /* _HAVE_SANE_QUAD_ */
01071                         {
01072                                 if (ulval != 0 || prec != 0)
01073                                         cp = BSD__ultoa(ulval, ebuf, base,
01074                                             flags & ALT, xdigs);
01075                         }
01076                         size = (int)(ebuf - cp);
01077                         break;
01078                 default:        /* "%?" prints ?, unless ? is NUL */
01079                         if (ch == '\0')
01080                                 goto done;
01081                         /* pretend it was %c with argument ch */
01082                         cp = buf;
01083                         *buf = ch;
01084                         size = 1;
01085                         sign = '\0';
01086                         break;
01087                 }
01088 
01089                 /*
01090                  * All reasonable formats wind up here.  At this point, `cp'
01091                  * points to a string which (if not flags&LADJUST) should be
01092                  * padded out to `width' places.  If flags&ZEROPAD, it should
01093                  * first be prefixed by any sign or other prefix; otherwise,
01094                  * it should be blank padded before the prefix is emitted.
01095                  * After any left-hand padding and prefixing, emit zeroes
01096                  * required by a decimal [diouxX] precision, then print the
01097                  * string proper, then emit zeroes required by any leftover
01098                  * floating precision; finally, if LADJUST, pad with blanks.
01099                  *
01100                  * Compute actual size, so we know how much to pad.
01101                  * fieldsz excludes decimal prec; realsz includes it.
01102                  */
01103                 fieldsz = size;
01104 long_len:
01105                 if (sign)
01106                         fieldsz++;
01107                 if (flags & HEXPREFIX)
01108                         fieldsz += 2;
01109                 realsz = dprec > fieldsz ? dprec : fieldsz;
01110 
01111                 /* right-adjusting blank padding */
01112                 if ((flags & (LADJUST|ZEROPAD)) == 0)
01113                         PAD_L(width - realsz, blanks);
01114 
01115                 /* prefix */
01116                 if (sign) {
01117                         PRINT(&sign, 1);
01118                 }
01119                 if (flags & HEXPREFIX) {
01120                         ox[0] = '0';
01121                         ox[1] = ch;
01122                         PRINT(ox, 2);
01123                 }
01124 
01125                 /* right-adjusting zero padding */
01126                 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
01127                         PAD_L(width - realsz, zeroes);
01128 
01129                 /* leading zeroes from decimal precision */
01130                 PAD_L(dprec - fieldsz, zeroes);
01131                 if (sign)
01132                         fieldsz--;
01133                 if (flags & HEXPREFIX)
01134                         fieldsz -= 2;
01135 
01136                 /* the string or number proper */
01137 #ifdef FLOATING_POINT
01138                 if ((flags & FPT) == 0) {
01139                         PRINT(cp, fieldsz);
01140                 } else {        /* glue together f_p fragments */
01141                         if (flags & HEXPREFIX) {
01142                                 if (ndig > 1 || flags & ALT) {
01143                                         ox[2] = *cp++;
01144                                         ox[3] = '.';
01145                                         PRINT(ox+2, 2);
01146                                         if (ndig > 0) PRINT(cp, ndig-1);
01147                                 } else  /* XpYYY */
01148                                         PRINT(cp, 1);
01149                                 PAD(fprec-ndig, zeroes);
01150                                 PRINT(expstr, expsize);
01151                         }
01152                         else if (ch >= 'f') {   /* 'f' or 'g' */
01153                                 if (_double == 0) {
01154                                 /* kludge for __dtoa irregularity */
01155                                         if (ndig <= 1 &&
01156                                             (flags & ALT) == 0) {
01157                                                 PRINT("0", 1);
01158                                         } else {
01159                                                 PRINT("0.", 2);
01160                                                 PAD((ndig >= fprec ? ndig - 1 : fprec - (ch != 'f')),
01161                                                     zeroes);
01162                                         }
01163                                 } else if (expt == 0 && ndig == 0 && (flags & ALT) == 0) {
01164                                         PRINT("0", 1);
01165                                 } else if (expt <= 0) {
01166                                         PRINT("0.", 2);
01167                                         PAD(-expt, zeroes);
01168                                         PRINT(cp, ndig);
01169                                         if (flags & ALT)
01170                                                 PAD(fprec - ndig + (ch == 'f' ? expt : 0), zeroes);
01171                                 } else if (expt >= ndig) {
01172                                         PRINT(cp, ndig);
01173                                         PAD(expt - ndig, zeroes);
01174                                         if (flags & ALT)
01175                                                 PRINT(".", 1);
01176                                 } else {
01177                                         PRINT(cp, expt);
01178                                         cp += expt;
01179                                         PRINT(".", 1);
01180                                         PRINT(cp, ndig-expt);
01181                                         if (flags & ALT)
01182                                                 PAD(fprec - ndig + (ch == 'f' ? expt : 0), zeroes);
01183                                 }
01184                         } else {        /* 'e' or 'E' */
01185                                 if (ndig > 1 || flags & ALT) {
01186                                         ox[0] = *cp++;
01187                                         ox[1] = '.';
01188                                         PRINT(ox, 2);
01189                                         if (_double /*|| flags & ALT == 0*/) {
01190                                                 PRINT(cp, ndig-1);
01191                                         } else  /* 0.[0..] */
01192                                                 /* __dtoa irregularity */
01193                                                 PAD(ndig - 1, zeroes);
01194                                         if (flags & ALT) PAD(fprec - ndig - 1, zeroes);
01195                                 } else  /* XeYYY */
01196                                         PRINT(cp, 1);
01197                                 PRINT(expstr, expsize);
01198                         }
01199                 }
01200 #else
01201                 PRINT(cp, fieldsz);
01202 #endif
01203                 /* left-adjusting padding (always blank) */
01204                 if (flags & LADJUST)
01205                         PAD_L(width - realsz, blanks);
01206 
01207                 /* finally, adjust ret */
01208                 ret += width > realsz ? width : realsz;
01209 
01210                 FLUSH();        /* copy out the I/O vectors */
01211         }
01212 done:
01213         FLUSH();
01214 error:
01215         return (BSD__sferror(fp) ? EOF : ret);
01216         /* NOTREACHED */
01217 }
01218 
01219 #ifdef FLOATING_POINT
01220 
01221 extern char *BSD__dtoa(double, int, int, int *, int *, char **);
01222 extern char *BSD__hdtoa(double, const char *, int, int *, int *, char **);
01223 
01224 static char *
01225 cvt(double value, int ndigits, int flags, char *sign, int *decpt, int ch, int *length, char *buf)
01226 {
01227         int mode, dsgn;
01228         char *digits, *bp, *rve;
01229 
01230         if (ch == 'f')
01231                 mode = 3;
01232         else {
01233                 mode = 2;
01234         }
01235         if (value < 0) {
01236                 value = -value;
01237                 *sign = '-';
01238         } else if (value == 0.0 && 1.0/value < 0) {
01239             *sign = '-';
01240         } else {
01241             *sign = '\000';
01242         }
01243         if (ch == 'a' || ch =='A') {
01244             digits = BSD__hdtoa(value,
01245                     ch == 'a' ? "0123456789abcdef" : "0123456789ABCDEF",
01246                     ndigits, decpt, &dsgn, &rve);
01247         }
01248         else {
01249             digits = BSD__dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
01250         }
01251         buf[0] = 0; /* rve - digits may be 0 */
01252         memcpy(buf, digits, rve - digits);
01253         xfree(digits);
01254         rve = buf + (rve - digits);
01255         digits = buf;
01256         if (flags & ALT) {      /* Print trailing zeros */
01257                 bp = digits + ndigits;
01258                 if (ch == 'f') {
01259                         if (*digits == '0' && value)
01260                                 *decpt = -ndigits + 1;
01261                         bp += *decpt;
01262                 }
01263                 while (rve < bp)
01264                         *rve++ = '0';
01265         }
01266         *length = (int)(rve - digits);
01267         return (digits);
01268 }
01269 
01270 static int
01271 exponent(char *p0, int exp, int fmtch)
01272 {
01273         register char *p, *t;
01274         char expbuf[2 + (MAXEXP < 1000 ? 3 : MAXEXP < 10000 ? 4 : 5)]; /* >= 2 + ceil(log10(MAXEXP)) */
01275 
01276         p = p0;
01277         *p++ = fmtch;
01278         if (exp < 0) {
01279                 exp = -exp;
01280                 *p++ = '-';
01281         }
01282         else
01283                 *p++ = '+';
01284         t = expbuf + sizeof(expbuf);
01285         if (exp > 9) {
01286                 do {
01287                         *--t = to_char(exp % 10);
01288                 } while ((exp /= 10) > 9);
01289                 *--t = to_char(exp);
01290                 for (; t < expbuf + sizeof(expbuf); *p++ = *t++);
01291         }
01292         else {
01293                 if (fmtch & 15) *p++ = '0'; /* other than p or P */
01294                 *p++ = to_char(exp);
01295         }
01296         return (int)(p - p0);
01297 }
01298 #endif /* FLOATING_POINT */
01299 
01300 int
01301 ruby_vsnprintf(char *str, size_t n, const char *fmt, va_list ap)
01302 {
01303         int ret;
01304         FILE f;
01305 
01306         if ((int)n < 1)
01307                 return (EOF);
01308         f._flags = __SWR | __SSTR;
01309         f._bf._base = f._p = (unsigned char *)str;
01310         f._bf._size = f._w = n - 1;
01311         f.vwrite = BSD__sfvwrite;
01312         f.vextra = 0;
01313         ret = (int)BSD_vfprintf(&f, fmt, ap);
01314         *f._p = 0;
01315         return (ret);
01316 }
01317 
01318 int
01319 ruby_snprintf(char *str, size_t n, char const *fmt, ...)
01320 {
01321         int ret;
01322         va_list ap;
01323         FILE f;
01324 
01325         if ((int)n < 1)
01326                 return (EOF);
01327 
01328         va_start(ap, fmt);
01329         f._flags = __SWR | __SSTR;
01330         f._bf._base = f._p = (unsigned char *)str;
01331         f._bf._size = f._w = n - 1;
01332         f.vwrite = BSD__sfvwrite;
01333         f.vextra = 0;
01334         ret = (int)BSD_vfprintf(&f, fmt, ap);
01335         *f._p = 0;
01336         va_end(ap);
01337         return (ret);
01338 }
01339