Ruby  2.0.0p247(2013-06-27revision41674)
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 "floatio.h" */
00493 
00494 #ifndef MAXEXP
00495 # define MAXEXP 1024
00496 #endif
00497 
00498 #ifndef MAXFRACT
00499 # define MAXFRACT 64
00500 #endif
00501 
00502 #define BUF             (MAXEXP+MAXFRACT+1)     /* + decimal point */
00503 #define DEFPREC         6
00504 
00505 static char *cvt(double, int, int, char *, int *, int, int *, char *);
00506 static int exponent(char *, int, int);
00507 
00508 #else /* no FLOATING_POINT */
00509 
00510 #define BUF             68
00511 
00512 #endif /* FLOATING_POINT */
00513 
00514 
00515 /*
00516  * Flags used during conversion.
00517  */
00518 #define ALT             0x001           /* alternate form */
00519 #define HEXPREFIX       0x002           /* add 0x or 0X prefix */
00520 #define LADJUST         0x004           /* left adjustment */
00521 #define LONGDBL         0x008           /* long double; unimplemented */
00522 #define LONGINT         0x010           /* long integer */
00523 
00524 #ifdef _HAVE_SANE_QUAD_
00525 #define QUADINT         0x020           /* quad integer */
00526 #endif /* _HAVE_SANE_QUAD_ */
00527 
00528 #define SHORTINT        0x040           /* short integer */
00529 #define ZEROPAD         0x080           /* zero (as opposed to blank) pad */
00530 #define FPT             0x100           /* Floating point number */
00531 static ssize_t
00532 BSD_vfprintf(FILE *fp, const char *fmt0, va_list ap)
00533 {
00534         register const char *fmt; /* format string */
00535         register int ch;        /* character from fmt */
00536         register int n;         /* handy integer (short term usage) */
00537         register const char *cp;/* handy char pointer (short term usage) */
00538         register struct __siov *iovp;/* for PRINT macro */
00539         register int flags;     /* flags as above */
00540         ssize_t ret;            /* return value accumulator */
00541         int width;              /* width from format (%8d), or 0 */
00542         int prec;               /* precision from format (%.3d), or -1 */
00543         char sign;              /* sign prefix (' ', '+', '-', or \0) */
00544 #ifdef FLOATING_POINT
00545         char softsign;          /* temporary negative sign for floats */
00546         double _double = 0;     /* double precision arguments %[eEfgG] */
00547         int expt;               /* integer value of exponent */
00548         int expsize = 0;        /* character count for expstr */
00549         int ndig = 0;           /* actual number of digits returned by cvt */
00550         char expstr[7];         /* buffer for exponent string */
00551 #endif
00552         u_long UNINITIALIZED_VAR(ulval); /* integer arguments %[diouxX] */
00553 #ifdef _HAVE_SANE_QUAD_
00554         u_quad_t UNINITIALIZED_VAR(uqval); /* %q integers */
00555 #endif /* _HAVE_SANE_QUAD_ */
00556         int base;               /* base for [diouxX] conversion */
00557         int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
00558         long fieldsz;           /* field size expanded by sign, etc */
00559         long realsz;            /* field size expanded by dprec */
00560         int size;               /* size of converted field or string */
00561         const char *xdigs = 0;  /* digits for [xX] conversion */
00562 #define NIOV 8
00563         struct __suio uio;      /* output information: summary */
00564         struct __siov iov[NIOV];/* ... and individual io vectors */
00565         char buf[BUF];          /* space for %c, %[diouxX], %[eEfgG] */
00566         char ox[4];             /* space for 0x hex-prefix, hexadecimal's 1. */
00567         char *const ebuf = buf + sizeof(buf);
00568 #if SIZEOF_LONG > SIZEOF_INT
00569         long ln;
00570 #endif
00571 
00572         /*
00573          * Choose PADSIZE to trade efficiency vs. size.  If larger printf
00574          * fields occur frequently, increase PADSIZE and make the initializers
00575          * below longer.
00576          */
00577 #define PADSIZE 16              /* pad chunk size */
00578         static const char blanks[PADSIZE] =
00579          {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
00580         static const char zeroes[PADSIZE] =
00581          {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
00582 
00583         /*
00584          * BEWARE, these `goto error' on error, and PAD uses `n'.
00585          */
00586 #define PRINT(ptr, len) { \
00587         iovp->iov_base = (ptr); \
00588         iovp->iov_len = (len); \
00589         uio.uio_resid += (len); \
00590         iovp++; \
00591         if (++uio.uio_iovcnt >= NIOV) { \
00592                 if (BSD__sprint(fp, &uio)) \
00593                         goto error; \
00594                 iovp = iov; \
00595         } \
00596 }
00597 #define PAD(howmany, with) { \
00598         if ((n = (howmany)) > 0) { \
00599                 while (n > PADSIZE) { \
00600                         PRINT((with), PADSIZE); \
00601                         n -= PADSIZE; \
00602                 } \
00603                 PRINT((with), n); \
00604         } \
00605 }
00606 #if SIZEOF_LONG > SIZEOF_INT
00607         /* abandon if too larger padding */
00608 #define PAD_L(howmany, with) { \
00609         ln = (howmany); \
00610         if ((long)((int)ln) != ln) { \
00611             errno = ENOMEM; \
00612             goto error; \
00613         } \
00614         if (ln > 0) PAD((int)ln, (with)); \
00615 }
00616 #else
00617 #define PAD_L(howmany, with) PAD((howmany), (with))
00618 #endif
00619 #define FLUSH() { \
00620         if (uio.uio_resid && BSD__sprint(fp, &uio)) \
00621                 goto error; \
00622         uio.uio_iovcnt = 0; \
00623         iovp = iov; \
00624 }
00625 
00626         /*
00627          * To extend shorts properly, we need both signed and unsigned
00628          * argument extraction methods.
00629          */
00630 #define SARG() \
00631         (flags&LONGINT ? va_arg(ap, long) : \
00632             flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
00633             (long)va_arg(ap, int))
00634 #define UARG() \
00635         (flags&LONGINT ? va_arg(ap, u_long) : \
00636             flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
00637             (u_long)va_arg(ap, u_int))
00638 
00639         /* optimise fprintf(stderr) (and other unbuffered Unix files) */
00640         if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
00641             fp->_file >= 0)
00642                 return (BSD__sbprintf(fp, fmt0, ap));
00643 
00644         fmt = fmt0;
00645         uio.uio_iov = iovp = iov;
00646         uio.uio_resid = 0;
00647         uio.uio_iovcnt = 0;
00648         ret = 0;
00649         xdigs = 0;
00650 
00651         /*
00652          * Scan the format for conversions (`%' character).
00653          */
00654         for (;;) {
00655                 size_t nc;
00656                 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
00657                         /* void */;
00658                 if ((nc = fmt - cp) != 0) {
00659                         PRINT(cp, nc);
00660                         ret += nc;
00661                 }
00662                 if (ch == '\0')
00663                         goto done;
00664                 fmt++;          /* skip over '%' */
00665 
00666                 flags = 0;
00667                 dprec = 0;
00668                 width = 0;
00669                 prec = -1;
00670                 sign = '\0';
00671 
00672 rflag:          ch = *fmt++;
00673 reswitch:       switch (ch) {
00674                 case ' ':
00675                         /*
00676                          * ``If the space and + flags both appear, the space
00677                          * flag will be ignored.''
00678                          *      -- ANSI X3J11
00679                          */
00680                         if (!sign)
00681                                 sign = ' ';
00682                         goto rflag;
00683                 case '#':
00684                         flags |= ALT;
00685                         goto rflag;
00686                 case '*':
00687                         /*
00688                          * ``A negative field width argument is taken as a
00689                          * - flag followed by a positive field width.''
00690                          *      -- ANSI X3J11
00691                          * They don't exclude field widths read from args.
00692                          */
00693                         if ((width = va_arg(ap, int)) >= 0)
00694                                 goto rflag;
00695                         width = -width;
00696                         /* FALLTHROUGH */
00697                 case '-':
00698                         flags |= LADJUST;
00699                         goto rflag;
00700                 case '+':
00701                         sign = '+';
00702                         goto rflag;
00703                 case '.':
00704                         if ((ch = *fmt++) == '*') {
00705                                 n = va_arg(ap, int);
00706                                 prec = n < 0 ? -1 : n;
00707                                 goto rflag;
00708                         }
00709                         n = 0;
00710                         while (is_digit(ch)) {
00711                                 n = 10 * n + to_digit(ch);
00712                                 ch = *fmt++;
00713                         }
00714                         prec = n < 0 ? -1 : n;
00715                         goto reswitch;
00716                 case '0':
00717                         /*
00718                          * ``Note that 0 is taken as a flag, not as the
00719                          * beginning of a field width.''
00720                          *      -- ANSI X3J11
00721                          */
00722                         flags |= ZEROPAD;
00723                         goto rflag;
00724                 case '1': case '2': case '3': case '4':
00725                 case '5': case '6': case '7': case '8': case '9':
00726                         n = 0;
00727                         do {
00728                                 n = 10 * n + to_digit(ch);
00729                                 ch = *fmt++;
00730                         } while (is_digit(ch));
00731                         width = n;
00732                         goto reswitch;
00733 #ifdef FLOATING_POINT
00734                 case 'L':
00735                         flags |= LONGDBL;
00736                         goto rflag;
00737 #endif
00738                 case 'h':
00739                         flags |= SHORTINT;
00740                         goto rflag;
00741 #if SIZEOF_PTRDIFF_T == SIZEOF_LONG
00742                 case 't':
00743 #endif
00744 #if SIZEOF_SIZE_T == SIZEOF_LONG
00745                 case 'z':
00746 #endif
00747                 case 'l':
00748 #ifdef _HAVE_SANE_QUAD_
00749                         if (*fmt == 'l') {
00750                                 fmt++;
00751                                 flags |= QUADINT;
00752                         } else {
00753                                 flags |= LONGINT;
00754                         }
00755 #else
00756                         flags |= LONGINT;
00757 #endif
00758                         goto rflag;
00759 #ifdef _HAVE_SANE_QUAD_
00760 #if SIZEOF_PTRDIFF_T == SIZEOF_LONG_LONG
00761                 case 't':
00762 #endif
00763 #if SIZEOF_SIZE_T == SIZEOF_LONG_LONG
00764                 case 'z':
00765 #endif
00766                 case 'q':
00767                         flags |= QUADINT;
00768                         goto rflag;
00769 #endif /* _HAVE_SANE_QUAD_ */
00770 #ifdef _WIN32
00771                 case 'I':
00772                         if (*fmt == '3' && *(fmt + 1) == '2') {
00773                             fmt += 2;
00774                             flags |= LONGINT;
00775                         }
00776 #ifdef _HAVE_SANE_QUAD_
00777                         else if (*fmt == '6' && *(fmt + 1) == '4') {
00778                             fmt += 2;
00779                             flags |= QUADINT;
00780                         }
00781 #endif
00782                         else
00783 #if defined(_HAVE_SANE_QUAD_) && SIZEOF_SIZE_T == SIZEOF_LONG_LONG
00784                             flags |= QUADINT;
00785 #else
00786                             flags |= LONGINT;
00787 #endif
00788                         goto rflag;
00789 #endif
00790                 case 'c':
00791                         cp = buf;
00792                         *buf = (char)va_arg(ap, int);
00793                         size = 1;
00794                         sign = '\0';
00795                         break;
00796                 case 'i':
00797 #ifdef _HAVE_SANE_QUAD_
00798 # define INTPTR_MASK (QUADINT|LONGINT|SHORTINT)
00799 #else
00800 # define INTPTR_MASK (LONGINT|SHORTINT)
00801 #endif
00802 #if defined _HAVE_SANE_QUAD_ && SIZEOF_VOIDP == SIZEOF_LONG_LONG
00803 # define INTPTR_FLAG QUADINT
00804 #elif SIZEOF_VOIDP == SIZEOF_LONG
00805 # define INTPTR_FLAG LONGINT
00806 #else
00807 # define INTPTR_FLAG 0
00808 #endif
00809                         if (fp->vextra && (flags & INTPTR_MASK) == INTPTR_FLAG) {
00810                                 FLUSH();
00811 #if defined _HAVE_SANE_QUAD_ && SIZEOF_VOIDP == SIZEOF_LONG_LONG
00812                                 uqval = va_arg(ap, u_quad_t);
00813                                 cp = (*fp->vextra)(fp, sizeof(uqval), &uqval, &fieldsz, sign);
00814 #else
00815                                 ulval = va_arg(ap, u_long);
00816                                 cp = (*fp->vextra)(fp, sizeof(ulval), &ulval, &fieldsz, sign);
00817 #endif
00818                                 sign = '\0';
00819                                 if (!cp) goto error;
00820                                 if (prec < 0) goto long_len;
00821                                 size = fieldsz < prec ? (int)fieldsz : prec;
00822                                 break;
00823                         }
00824                         goto decimal;
00825                 case 'D':
00826                         flags |= LONGINT;
00827                         /*FALLTHROUGH*/
00828                 case 'd':
00829                 decimal:
00830 #ifdef _HAVE_SANE_QUAD_
00831                         if (flags & QUADINT) {
00832                                 uqval = va_arg(ap, quad_t);
00833                                 if ((quad_t)uqval < 0) {
00834                                         uqval = -(quad_t)uqval;
00835                                         sign = '-';
00836                                 }
00837                         } else
00838 #endif /* _HAVE_SANE_QUAD_ */
00839                         {
00840                                 ulval = SARG();
00841                                 if ((long)ulval < 0) {
00842                                         ulval = (u_long)(-(long)ulval);
00843                                         sign = '-';
00844                                 }
00845                         }
00846                         base = 10;
00847                         goto number;
00848 #ifdef FLOATING_POINT
00849                 case 'a':
00850                 case 'A':
00851                         if (prec > 0) {
00852                                 flags |= ALT;
00853                                 prec++;
00854                         }
00855                         goto fp_begin;
00856                 case 'e':               /* anomalous precision */
00857                 case 'E':
00858                         if (prec != 0)
00859                                 flags |= ALT;
00860                         prec = (prec == -1) ?
00861                                 DEFPREC + 1 : prec + 1;
00862                         /* FALLTHROUGH */
00863                         goto fp_begin;
00864                 case 'f':               /* always print trailing zeroes */
00865                         if (prec != 0)
00866                                 flags |= ALT;
00867                 case 'g':
00868                 case 'G':
00869                         if (prec == -1)
00870                                 prec = DEFPREC;
00871 fp_begin:               _double = va_arg(ap, double);
00872                         /* do this before tricky precision changes */
00873                         if (isinf(_double)) {
00874                                 if (_double < 0)
00875                                         sign = '-';
00876                                 cp = "Inf";
00877                                 size = 3;
00878                                 break;
00879                         }
00880                         if (isnan(_double)) {
00881                                 cp = "NaN";
00882                                 size = 3;
00883                                 break;
00884                         }
00885                         flags |= FPT;
00886                         cp = cvt(_double, prec, flags, &softsign,
00887                                 &expt, ch, &ndig, buf);
00888                         if (ch == 'g' || ch == 'G') {
00889                                 if (expt <= -4 || (expt > prec && expt > 1))
00890                                         ch = (ch == 'g') ? 'e' : 'E';
00891                                 else
00892                                         ch = 'g';
00893                         }
00894                         if (ch == 'a' || ch == 'A') {
00895                                 flags |= HEXPREFIX;
00896                                 --expt;
00897                                 expsize = exponent(expstr, expt, ch + 'p' - 'a');
00898                                 ch += 'x' - 'a';
00899                                 size = expsize + ndig;
00900                                 if (ndig > 1 || flags & ALT)
00901                                         ++size; /* floating point */
00902                         }
00903                         else if (ch <= 'e') {   /* 'e' or 'E' fmt */
00904                                 --expt;
00905                                 expsize = exponent(expstr, expt, ch);
00906                                 size = expsize + ndig;
00907                                 if (ndig > 1 || flags & ALT)
00908                                         ++size;
00909                         } else if (ch == 'f') {         /* f fmt */
00910                                 if (expt > 0) {
00911                                         size = expt;
00912                                         if (prec || flags & ALT)
00913                                                 size += prec + 1;
00914                                 } else if (!prec) { /* "0" */
00915                                         size = 1;
00916                                         if (flags & ALT)
00917                                                 size += 1;
00918                                 } else  /* "0.X" */
00919                                         size = prec + 2;
00920                         } else if (expt >= ndig) {      /* fixed g fmt */
00921                                 size = expt;
00922                                 if (flags & ALT)
00923                                         ++size;
00924                         } else
00925                                 size = ndig + (expt > 0 ?
00926                                         1 : 2 - expt);
00927 
00928                         if (softsign)
00929                                 sign = '-';
00930                         break;
00931 #endif /* FLOATING_POINT */
00932                 case 'n':
00933 #ifdef _HAVE_SANE_QUAD_
00934                         if (flags & QUADINT)
00935                                 *va_arg(ap, quad_t *) = ret;
00936                         else if (flags & LONGINT)
00937 #else /* _HAVE_SANE_QUAD_ */
00938                         if (flags & LONGINT)
00939 #endif /* _HAVE_SANE_QUAD_ */
00940                                 *va_arg(ap, long *) = ret;
00941                         else if (flags & SHORTINT)
00942                                 *va_arg(ap, short *) = (short)ret;
00943                         else
00944                                 *va_arg(ap, int *) = (int)ret;
00945                         continue;       /* no output */
00946                 case 'O':
00947                         flags |= LONGINT;
00948                         /*FALLTHROUGH*/
00949                 case 'o':
00950 #ifdef _HAVE_SANE_QUAD_
00951                         if (flags & QUADINT)
00952                                 uqval = va_arg(ap, u_quad_t);
00953                         else
00954 #endif /* _HAVE_SANE_QUAD_ */
00955                                 ulval = UARG();
00956                         base = 8;
00957                         goto nosign;
00958                 case 'p':
00959                         /*
00960                          * ``The argument shall be a pointer to void.  The
00961                          * value of the pointer is converted to a sequence
00962                          * of printable characters, in an implementation-
00963                          * defined manner.''
00964                          *      -- ANSI X3J11
00965                          */
00966                         prec = (int)(sizeof(void*)*CHAR_BIT/4);
00967 #ifdef _HAVE_LLP64_
00968                         uqval = (u_quad_t)va_arg(ap, void *);
00969                         flags = (flags) | QUADINT | HEXPREFIX;
00970 #else
00971                         ulval = (u_long)va_arg(ap, void *);
00972 #ifdef _HAVE_SANE_QUAD_
00973                         flags = (flags & ~QUADINT) | HEXPREFIX;
00974 #else /* _HAVE_SANE_QUAD_ */
00975                         flags = (flags) | HEXPREFIX;
00976 #endif /* _HAVE_SANE_QUAD_ */
00977 #endif
00978                         base = 16;
00979                         xdigs = "0123456789abcdef";
00980                         ch = 'x';
00981                         goto nosign;
00982                 case 's':
00983                         if ((cp = va_arg(ap, char *)) == NULL)
00984                                 cp = "(null)";
00985                         if (prec >= 0) {
00986                                 /*
00987                                  * can't use strlen; can only look for the
00988                                  * NUL in the first `prec' characters, and
00989                                  * strlen() will go further.
00990                                  */
00991                                 const char *p = (char *)memchr(cp, 0, prec);
00992 
00993                                 if (p != NULL && (p - cp) > prec)
00994                                         size = (int)(p - cp);
00995                                 else
00996                                         size = prec;
00997                         }
00998                         else {
00999                                 fieldsz = strlen(cp);
01000                                 goto long_len;
01001                         }
01002                         sign = '\0';
01003                         break;
01004                 case 'U':
01005                         flags |= LONGINT;
01006                         /*FALLTHROUGH*/
01007                 case 'u':
01008 #ifdef _HAVE_SANE_QUAD_
01009                         if (flags & QUADINT)
01010                                 uqval = va_arg(ap, u_quad_t);
01011                         else
01012 #endif /* _HAVE_SANE_QUAD_ */
01013                                 ulval = UARG();
01014                         base = 10;
01015                         goto nosign;
01016                 case 'X':
01017                         xdigs = "0123456789ABCDEF";
01018                         goto hex;
01019                 case 'x':
01020                         xdigs = "0123456789abcdef";
01021 hex:
01022 #ifdef _HAVE_SANE_QUAD_
01023                         if (flags & QUADINT)
01024                                 uqval = va_arg(ap, u_quad_t);
01025                         else
01026 #endif /* _HAVE_SANE_QUAD_ */
01027                                 ulval = UARG();
01028                         base = 16;
01029                         /* leading 0x/X only if non-zero */
01030                         if (flags & ALT &&
01031 #ifdef _HAVE_SANE_QUAD_
01032                             (flags & QUADINT ? uqval != 0 : ulval != 0)
01033 #else /* _HAVE_SANE_QUAD_ */
01034                             ulval != 0
01035 #endif /* _HAVE_SANE_QUAD_ */
01036                             )
01037                                 flags |= HEXPREFIX;
01038 
01039                         /* unsigned conversions */
01040 nosign:                 sign = '\0';
01041                         /*
01042                          * ``... diouXx conversions ... if a precision is
01043                          * specified, the 0 flag will be ignored.''
01044                          *      -- ANSI X3J11
01045                          */
01046 number:                 if ((dprec = prec) >= 0)
01047                                 flags &= ~ZEROPAD;
01048 
01049                         /*
01050                          * ``The result of converting a zero value with an
01051                          * explicit precision of zero is no characters.''
01052                          *      -- ANSI X3J11
01053                          */
01054 #ifdef _HAVE_SANE_QUAD_
01055                         if (flags & QUADINT) {
01056                                 if (uqval != 0 || prec != 0)
01057                                         cp = BSD__uqtoa(uqval, ebuf, base,
01058                                             flags & ALT, xdigs);
01059                         } else
01060 #else /* _HAVE_SANE_QUAD_ */
01061 #endif /* _HAVE_SANE_QUAD_ */
01062                         {
01063                                 if (ulval != 0 || prec != 0)
01064                                         cp = BSD__ultoa(ulval, ebuf, base,
01065                                             flags & ALT, xdigs);
01066                         }
01067                         size = (int)(ebuf - cp);
01068                         break;
01069                 default:        /* "%?" prints ?, unless ? is NUL */
01070                         if (ch == '\0')
01071                                 goto done;
01072                         /* pretend it was %c with argument ch */
01073                         cp = buf;
01074                         *buf = ch;
01075                         size = 1;
01076                         sign = '\0';
01077                         break;
01078                 }
01079 
01080                 /*
01081                  * All reasonable formats wind up here.  At this point, `cp'
01082                  * points to a string which (if not flags&LADJUST) should be
01083                  * padded out to `width' places.  If flags&ZEROPAD, it should
01084                  * first be prefixed by any sign or other prefix; otherwise,
01085                  * it should be blank padded before the prefix is emitted.
01086                  * After any left-hand padding and prefixing, emit zeroes
01087                  * required by a decimal [diouxX] precision, then print the
01088                  * string proper, then emit zeroes required by any leftover
01089                  * floating precision; finally, if LADJUST, pad with blanks.
01090                  *
01091                  * Compute actual size, so we know how much to pad.
01092                  * fieldsz excludes decimal prec; realsz includes it.
01093                  */
01094                 fieldsz = size;
01095 long_len:
01096                 if (sign)
01097                         fieldsz++;
01098                 if (flags & HEXPREFIX)
01099                         fieldsz += 2;
01100                 realsz = dprec > fieldsz ? dprec : fieldsz;
01101 
01102                 /* right-adjusting blank padding */
01103                 if ((flags & (LADJUST|ZEROPAD)) == 0)
01104                         PAD_L(width - realsz, blanks);
01105 
01106                 /* prefix */
01107                 if (sign) {
01108                         PRINT(&sign, 1);
01109                 }
01110                 if (flags & HEXPREFIX) {
01111                         ox[0] = '0';
01112                         ox[1] = ch;
01113                         PRINT(ox, 2);
01114                 }
01115 
01116                 /* right-adjusting zero padding */
01117                 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
01118                         PAD_L(width - realsz, zeroes);
01119 
01120                 /* leading zeroes from decimal precision */
01121                 PAD_L(dprec - fieldsz, zeroes);
01122                 if (sign)
01123                         fieldsz--;
01124                 if (flags & HEXPREFIX)
01125                         fieldsz -= 2;
01126 
01127                 /* the string or number proper */
01128 #ifdef FLOATING_POINT
01129                 if ((flags & FPT) == 0) {
01130                         PRINT(cp, fieldsz);
01131                 } else {        /* glue together f_p fragments */
01132                         if (flags & HEXPREFIX) {
01133                                 if (ndig > 1 || flags & ALT) {
01134                                         ox[2] = *cp++;
01135                                         ox[3] = '.';
01136                                         PRINT(ox+2, 2);
01137                                         if (ndig > 0) PRINT(cp, ndig-1);
01138                                 } else  /* XpYYY */
01139                                         PRINT(cp, 1);
01140                                 PRINT(expstr, expsize);
01141                         }
01142                         else if (ch >= 'f') {   /* 'f' or 'g' */
01143                                 if (_double == 0) {
01144                                 /* kludge for __dtoa irregularity */
01145                                         if (ndig <= 1 &&
01146                                             (flags & ALT) == 0) {
01147                                                 PRINT("0", 1);
01148                                         } else {
01149                                                 PRINT("0.", 2);
01150                                                 PAD(ndig - 1, zeroes);
01151                                         }
01152                                 } else if (expt == 0 && ndig == 0 && (flags & ALT) == 0) {
01153                                         PRINT("0", 1);
01154                                 } else if (expt <= 0) {
01155                                         PRINT("0.", 2);
01156                                         PAD(-expt, zeroes);
01157                                         PRINT(cp, ndig);
01158                                 } else if (expt >= ndig) {
01159                                         PRINT(cp, ndig);
01160                                         PAD(expt - ndig, zeroes);
01161                                         if (flags & ALT)
01162                                                 PRINT(".", 1);
01163                                 } else {
01164                                         PRINT(cp, expt);
01165                                         cp += expt;
01166                                         PRINT(".", 1);
01167                                         PRINT(cp, ndig-expt);
01168                                 }
01169                         } else {        /* 'e' or 'E' */
01170                                 if (ndig > 1 || flags & ALT) {
01171                                         ox[0] = *cp++;
01172                                         ox[1] = '.';
01173                                         PRINT(ox, 2);
01174                                         if (_double /*|| flags & ALT == 0*/) {
01175                                                 PRINT(cp, ndig-1);
01176                                         } else  /* 0.[0..] */
01177                                                 /* __dtoa irregularity */
01178                                                 PAD(ndig - 1, zeroes);
01179                                 } else  /* XeYYY */
01180                                         PRINT(cp, 1);
01181                                 PRINT(expstr, expsize);
01182                         }
01183                 }
01184 #else
01185                 PRINT(cp, fieldsz);
01186 #endif
01187                 /* left-adjusting padding (always blank) */
01188                 if (flags & LADJUST)
01189                         PAD_L(width - realsz, blanks);
01190 
01191                 /* finally, adjust ret */
01192                 ret += width > realsz ? width : realsz;
01193 
01194                 FLUSH();        /* copy out the I/O vectors */
01195         }
01196 done:
01197         FLUSH();
01198 error:
01199         return (BSD__sferror(fp) ? EOF : ret);
01200         /* NOTREACHED */
01201 }
01202 
01203 #ifdef FLOATING_POINT
01204 
01205 extern char *BSD__dtoa(double, int, int, int *, int *, char **);
01206 extern char *BSD__hdtoa(double, const char *, int, int *, int *, char **);
01207 
01208 static char *
01209 cvt(double value, int ndigits, int flags, char *sign, int *decpt, int ch, int *length, char *buf)
01210 {
01211         int mode, dsgn;
01212         char *digits, *bp, *rve;
01213 
01214         if (ch == 'f')
01215                 mode = 3;
01216         else {
01217                 mode = 2;
01218         }
01219         if (value < 0) {
01220                 value = -value;
01221                 *sign = '-';
01222         } else if (value == 0.0 && 1.0/value < 0) {
01223             *sign = '-';
01224         } else {
01225             *sign = '\000';
01226         }
01227         if (ch == 'a' || ch =='A') {
01228             digits = BSD__hdtoa(value,
01229                     ch == 'a' ? "0123456789abcdef" : "0123456789ABCDEF",
01230                     ndigits, decpt, &dsgn, &rve);
01231         }
01232         else {
01233             digits = BSD__dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
01234         }
01235         buf[0] = 0; /* rve - digits may be 0 */
01236         memcpy(buf, digits, rve - digits);
01237         xfree(digits);
01238         rve = buf + (rve - digits);
01239         digits = buf;
01240         if (flags & ALT) {      /* Print trailing zeros */
01241                 bp = digits + ndigits;
01242                 if (ch == 'f') {
01243                         if (*digits == '0' && value)
01244                                 *decpt = -ndigits + 1;
01245                         bp += *decpt;
01246                 }
01247                 while (rve < bp)
01248                         *rve++ = '0';
01249         }
01250         *length = (int)(rve - digits);
01251         return (digits);
01252 }
01253 
01254 static int
01255 exponent(char *p0, int exp, int fmtch)
01256 {
01257         register char *p, *t;
01258         char expbuf[MAXEXP];
01259 
01260         p = p0;
01261         *p++ = fmtch;
01262         if (exp < 0) {
01263                 exp = -exp;
01264                 *p++ = '-';
01265         }
01266         else
01267                 *p++ = '+';
01268         t = expbuf + MAXEXP;
01269         if (exp > 9) {
01270                 do {
01271                         *--t = to_char(exp % 10);
01272                 } while ((exp /= 10) > 9);
01273                 *--t = to_char(exp);
01274                 for (; t < expbuf + MAXEXP; *p++ = *t++);
01275         }
01276         else {
01277                 if (fmtch & 15) *p++ = '0'; /* other than p or P */
01278                 *p++ = to_char(exp);
01279         }
01280         return (int)(p - p0);
01281 }
01282 #endif /* FLOATING_POINT */
01283 
01284 int
01285 ruby_vsnprintf(char *str, size_t n, const char *fmt, va_list ap)
01286 {
01287         int ret;
01288         FILE f;
01289 
01290         if ((int)n < 1)
01291                 return (EOF);
01292         f._flags = __SWR | __SSTR;
01293         f._bf._base = f._p = (unsigned char *)str;
01294         f._bf._size = f._w = n - 1;
01295         f.vwrite = BSD__sfvwrite;
01296         f.vextra = 0;
01297         ret = (int)BSD_vfprintf(&f, fmt, ap);
01298         *f._p = 0;
01299         return (ret);
01300 }
01301 
01302 int
01303 ruby_snprintf(char *str, size_t n, char const *fmt, ...)
01304 {
01305         int ret;
01306         va_list ap;
01307         FILE f;
01308 
01309         if ((int)n < 1)
01310                 return (EOF);
01311 
01312         va_start(ap, fmt);
01313         f._flags = __SWR | __SSTR;
01314         f._bf._base = f._p = (unsigned char *)str;
01315         f._bf._size = f._w = n - 1;
01316         f.vwrite = BSD__sfvwrite;
01317         f.vextra = 0;
01318         ret = (int)BSD_vfprintf(&f, fmt, ap);
01319         *f._p = 0;
01320         va_end(ap);
01321         return (ret);
01322 }
01323