Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# 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 /*
    00131  * NB: to fit things in six character monocase externals, the stdio
    00132  * code uses the prefix `__s' for stdio objects, typically followed
    00133  * by a three-character attempt at a mnemonic.
    00134  */
    00135
    00136 /* stdio buffers */
    00137 struct __sbuf {
    00138         unsigned char *_base;
    00139         size_t  _size;
    00140 };
    00141
    00142
    00143 /*
    00144  * stdio state variables.
    00145  *
    00146  * The following always hold:
    00147  *
    00148  *      if (_flags&(__SLBF|__SWR)) == (__SLBF|__SWR),
    00149  *              _lbfsize is -_bf._size, else _lbfsize is 0
    00150  *      if _flags&__SRD, _w is 0
    00151  *      if _flags&__SWR, _r is 0
    00152  *
    00153  * This ensures that the getc and putc macros (or inline functions) never
    00154  * try to write or read from a file that is in `read' or `write' mode.
    00155  * (Moreover, they can, and do, automatically switch from read mode to
    00156  * write mode, and back, on "r+" and "w+" files.)
    00157  *
    00158  * _lbfsize is used only to make the inline line-buffered output stream
    00159  * code as compact as possible.
    00160  *
    00161  * _ub, _up, and _ur are used when ungetc() pushes back more characters
    00162  * than fit in the current _bf, or when ungetc() pushes back a character
    00163  * that does not match the previous one in _bf.  When this happens,
    00164  * _ub._base becomes non-nil (i.e., a stream has ungetc() data iff
    00165  * _ub._base!=NULL) and _up and _ur save the current values of _p and _r.
    00166  *
    00167  * NB: see WARNING above before changing the layout of this structure!
    00168  */
    00169 typedef struct __sFILE {
    00170         unsigned char *_p;      /* current position in (some) buffer */
    00171 #if 0
    00172         size_t  _r;             /* read space left for getc() */
    00173 #endif
    00174         size_t  _w;             /* write space left for putc() */
    00175         short   _flags;         /* flags, below; this FILE is free if 0 */
    00176         short   _file;          /* fileno, if Unix descriptor, else -1 */
    00177         struct  __sbuf _bf;     /* the buffer (at least 1 byte, if !NULL) */
    00178         size_t  _lbfsize;       /* 0 or -_bf._size, for inline putc */
    00179         int     (*vwrite)(/* struct __sFILE*, struct __suio * */);
    00180 } FILE;
    00181
    00182
    00183 #define __SLBF  0x0001          /* line buffered */
    00184 #define __SNBF  0x0002          /* unbuffered */
    00185 #define __SRD   0x0004          /* OK to read */
    00186 #define __SWR   0x0008          /* OK to write */
    00187         /* RD and WR are never simultaneously asserted */
    00188 #define __SRW   0x0010          /* open for reading & writing */
    00189 #define __SEOF  0x0020          /* found EOF */
    00190 #define __SERR  0x0040          /* found error */
    00191 #define __SMBF  0x0080          /* _buf is from malloc */
    00192 #define __SAPP  0x0100          /* fdopen()ed in append mode */
    00193 #define __SSTR  0x0200          /* this is an sprintf/snprintf string */
    00194 #define __SOPT  0x0400          /* do fseek() optimisation */
    00195 #define __SNPT  0x0800          /* do not do fseek() optimisation */
    00196 #define __SOFF  0x1000          /* set iff _offset is in fact correct */
    00197 #define __SMOD  0x2000          /* true => fgetln modified _p text */
    00198
    00199
    00200 #define EOF     (-1)
    00201
    00202
    00203 #define __sfeof(p)      (((p)->_flags & __SEOF) != 0)
    00204 #define __sferror(p)    (((p)->_flags & __SERR) != 0)
    00205 #define __sclearerr(p)  ((void)((p)->_flags &= ~(__SERR|__SEOF)))
    00206 #define __sfileno(p)    ((p)->_file)
    00207
    00208 #undef feof
    00209 #undef ferror
    00210 #undef clearerr
    00211 #define feof(p)         __sfeof(p)
    00212 #define ferror(p)       __sferror(p)
    00213 #define clearerr(p)     __sclearerr(p)
    00214
    00215 #ifndef _ANSI_SOURCE
    00216 #define fileno(p)       __sfileno(p)
    00217 #endif
    00218
    00219
    00220 /*
    00221  * I/O descriptors for __sfvwrite().
    00222  */
    00223 struct __siov {
    00224         const void *iov_base;
    00225         size_t  iov_len;
    00226 };
    00227 struct __suio {
    00228         struct  __siov *uio_iov;
    00229         int     uio_iovcnt;
    00230         size_t  uio_resid;
    00231 };
    00232
    00233 /*
    00234  * Write some memory regions.  Return zero on success, EOF on error.
    00235  *
    00236  * This routine is large and unsightly, but most of the ugliness due
    00237  * to the three different kinds of output buffering is handled here.
    00238  */
    00239 static int BSD__sfvwrite(fp, uio)
    00240         register FILE *fp;
    00241         register struct __suio *uio;
    00242 {
    00243         register size_t len;
    00244         register const char *p;
    00245         register struct __siov *iov;
    00246         register size_t w;
    00247
    00248         if ((len = uio->uio_resid) == 0)
    00249                 return (0);
    00250 #ifndef __hpux
    00251 #define MIN(a, b) ((a) < (b) ? (a) : (b))
    00252 #endif
    00253 #define COPY(n)   (void)memcpy((void *)fp->_p, (void *)p, (size_t)(n))
    00254
    00255         iov = uio->uio_iov;
    00256         p = iov->iov_base;
    00257         len = iov->iov_len;
    00258         iov++;
    00259 #define GETIOV(extra_work) \
    00260         while (len == 0) { \
    00261                 extra_work; \
    00262                 p = iov->iov_base; \
    00263                 len = iov->iov_len; \
    00264                 iov++; \
    00265         }
    00266         if (fp->_flags & __SNBF) {
    00267         /* fjc 7-31-97 Will never happen.  We are working with
    00268                                            strings only
    00269         */
    00270         } else if ((fp->_flags & __SLBF) == 0) {
    00271         /*
    00272                  * Fully buffered: fill partially full buffer, if any,
    00273                  * and then flush.  If there is no partial buffer, write
    00274                  * one _bf._size byte chunk directly (without copying).
    00275                  *
    00276                  * String output is a special case: write as many bytes
    00277                  * as fit, but pretend we wrote everything.  This makes
    00278                  * snprintf() return the number of bytes needed, rather
    00279                  * than the number used, and avoids its write function
    00280                  * (so that the write function can be invalid).
    00281                  */
    00282                 do {
    00283                         GETIOV(;);
    00284                         w = fp->_w;
    00285                         if (fp->_flags & __SSTR) {
    00286                                 if (len < w)
    00287                                         w = len;
    00288                                 COPY(w);        /* copy MIN(fp->_w,len), */
    00289                                 fp->_w -= w;
    00290                                 fp->_p += w;
    00291                                 w = len;        /* but pretend copied all */
    00292                         } else {
    00293                                 /* fjc 7-31-97 Will never happen.  We are working with
    00294                                                                    strings only
    00295                                 */
    00296                         }
    00297                         p += w;
    00298                         len -= w;
    00299                 } while ((uio->uio_resid -= w) != 0);
    00300         } else {
    00301                 /* fjc 7-31-97 Will never happen.  We are working with
    00302                                                    strings only
    00303                 */
    00304         }
    00305         return (0);
    00306 }
    00307
    00308 /*
    00309  * Actual printf innards.
    00310  *
    00311  * This code is large and complicated...
    00312  */
    00313
    00314 /*
    00315  * Flush out all the vectors defined by the given uio,
    00316  * then reset it so that it can be reused.
    00317  */
    00318 static int
    00319 BSD__sprint(FILE *fp, register struct __suio *uio)
    00320 {
    00321         register int err;
    00322
    00323         if (uio->uio_resid == 0) {
    00324                 uio->uio_iovcnt = 0;
    00325                 return (0);
    00326         }
    00327         err = (*fp->vwrite)(fp, uio);
    00328         uio->uio_resid = 0;
    00329         uio->uio_iovcnt = 0;
    00330         return (err);
    00331 }
    00332
    00333
    00334 /*
    00335  * Helper function for `fprintf to unbuffered unix file': creates a
    00336  * temporary buffer.  We only work on write-only files; this avoids
    00337  * worries about ungetc buffers and so forth.
    00338  */
    00339 static int
    00340 BSD__sbprintf(register FILE *fp, const char *fmt, va_list ap)
    00341 {
    00342 /* We don't support files. */
    00343         return 0;
    00344 }
    00345
    00346
    00347 /*
    00348  * Macros for converting digits to letters and vice versa
    00349  */
    00350 #define to_digit(c)     ((c) - '0')
    00351 #define is_digit(c)     ((unsigned)to_digit(c) <= 9)
    00352 #define to_char(n)      (char)((n) + '0')
    00353
    00354 #ifdef _HAVE_SANE_QUAD_
    00355 /*
    00356  * Convert an unsigned long long to ASCII for printf purposes, returning
    00357  * a pointer to the first character of the string representation.
    00358  * Octal numbers can be forced to have a leading zero; hex numbers
    00359  * use the given digits.
    00360  */
    00361 static char *
    00362 BSD__uqtoa(register u_quad_t val, char *endp, int base, int octzero, const char *xdigs)
    00363 {
    00364         register char *cp = endp;
    00365         register long sval;
    00366
    00367         /*
    00368          * Handle the three cases separately, in the hope of getting
    00369          * better/faster code.
    00370          */
    00371         switch (base) {
    00372         case 10:
    00373                 if (val < 10) { /* many numbers are 1 digit */
    00374                         *--cp = to_char(val);
    00375                         return (cp);
    00376                 }
    00377                 /*
    00378                  * On many machines, unsigned arithmetic is harder than
    00379                  * signed arithmetic, so we do at most one unsigned mod and
    00380                  * divide; this is sufficient to reduce the range of
    00381                  * the incoming value to where signed arithmetic works.
    00382                  */
    00383                 if (val > LLONG_MAX) {
    00384                         *--cp = to_char(val % 10);
    00385                         sval = val / 10;
    00386                 } else
    00387                         sval = val;
    00388                 do {
    00389                         *--cp = to_char(sval % 10);
    00390                         sval /= 10;
    00391                 } while (sval != 0);
    00392                 break;
    00393
    00394         case 8:
    00395                 do {
    00396                         *--cp = to_char(val & 7);
    00397                         val >>= 3;
    00398                 } while (val);
    00399                 if (octzero && *cp != '0')
    00400                         *--cp = '0';
    00401                 break;
    00402
    00403         case 16:
    00404                 do {
    00405                         *--cp = xdigs[val & 15];
    00406                         val >>= 4;
    00407                 } while (val);
    00408                 break;
    00409
    00410         default:                        /* oops */
    00411                 /*
    00412                 abort();
    00413                 */
    00414                 break;  /* fjc 7-31-97.  Don't reference abort() here */
    00415         }
    00416         return (cp);
    00417 }
    00418 #endif /* _HAVE_SANE_QUAD_ */
    00419
    00420 /*
    00421  * Convert an unsigned long to ASCII for printf purposes, returning
    00422  * a pointer to the first character of the string representation.
    00423  * Octal numbers can be forced to have a leading zero; hex numbers
    00424  * use the given digits.
    00425  */
    00426 static char *
    00427 BSD__ultoa(register u_long val, char *endp, int base, int octzero, const char *xdigs)
    00428 {
    00429         register char *cp = endp;
    00430         register long sval;
    00431
    00432         /*
    00433          * Handle the three cases separately, in the hope of getting
    00434          * better/faster code.
    00435          */
    00436         switch (base) {
    00437         case 10:
    00438                 if (val < 10) { /* many numbers are 1 digit */
    00439                         *--cp = to_char(val);
    00440                         return (cp);
    00441                 }
    00442                 /*
    00443                  * On many machines, unsigned arithmetic is harder than
    00444                  * signed arithmetic, so we do at most one unsigned mod and
    00445                  * divide; this is sufficient to reduce the range of
    00446                  * the incoming value to where signed arithmetic works.
    00447                  */
    00448                 if (val > LONG_MAX) {
    00449                         *--cp = to_char(val % 10);
    00450                         sval = val / 10;
    00451                 } else
    00452                         sval = val;
    00453                 do {
    00454                         *--cp = to_char(sval % 10);
    00455                         sval /= 10;
    00456                 } while (sval != 0);
    00457                 break;
    00458
    00459         case 8:
    00460                 do {
    00461                         *--cp = to_char(val & 7);
    00462                         val >>= 3;
    00463                 } while (val);
    00464                 if (octzero && *cp != '0')
    00465                         *--cp = '0';
    00466                 break;
    00467
    00468         case 16:
    00469                 do {
    00470                         *--cp = xdigs[val & 15];
    00471                         val >>= 4;
    00472                 } while (val);
    00473                 break;
    00474
    00475         default:                        /* oops */
    00476                 /*
    00477                 abort();
    00478                 */
    00479                 break;  /* fjc 7-31-97.  Don't reference abort() here */
    00480         }
    00481         return (cp);
    00482 }
    00483
    00484 #ifdef FLOATING_POINT
    00485 #include <math.h>
    00486 /* #include "floatio.h" */
    00487
    00488 #ifndef MAXEXP
    00489 # define MAXEXP 1024
    00490 #endif
    00491
    00492 #ifndef MAXFRACT
    00493 # define MAXFRACT 64
    00494 #endif
    00495
    00496 #define BUF             (MAXEXP+MAXFRACT+1)     /* + decimal point */
    00497 #define DEFPREC         6
    00498
    00499 static char *cvt __P((double, int, int, char *, int *, int, int *, char *));
    00500 static int exponent __P((char *, int, int));
    00501
    00502 #else /* no FLOATING_POINT */
    00503
    00504 #define BUF             68
    00505
    00506 #endif /* FLOATING_POINT */
    00507
    00508
    00509 /*
    00510  * Flags used during conversion.
    00511  */
    00512 #define ALT             0x001           /* alternate form */
    00513 #define HEXPREFIX       0x002           /* add 0x or 0X prefix */
    00514 #define LADJUST         0x004           /* left adjustment */
    00515 #define LONGDBL         0x008           /* long double; unimplemented */
    00516 #define LONGINT         0x010           /* long integer */
    00517
    00518 #ifdef _HAVE_SANE_QUAD_
    00519 #define QUADINT         0x020           /* quad integer */
    00520 #endif /* _HAVE_SANE_QUAD_ */
    00521
    00522 #define SHORTINT        0x040           /* short integer */
    00523 #define ZEROPAD         0x080           /* zero (as opposed to blank) pad */
    00524 #define FPT             0x100           /* Floating point number */
    00525 static ssize_t
    00526 BSD_vfprintf(FILE *fp, const char *fmt0, va_list ap)
    00527 {
    00528         register const char *fmt; /* format string */
    00529         register int ch;        /* character from fmt */
    00530         register int n;         /* handy integer (short term usage) */
    00531         register const char *cp;/* handy char pointer (short term usage) */
    00532         register struct __siov *iovp;/* for PRINT macro */
    00533         register int flags;     /* flags as above */
    00534         ssize_t ret;            /* return value accumulator */
    00535         int width;              /* width from format (%8d), or 0 */
    00536         int prec;               /* precision from format (%.3d), or -1 */
    00537         char sign;              /* sign prefix (' ', '+', '-', or \0) */
    00538 #ifdef FLOATING_POINT
    00539         char softsign;          /* temporary negative sign for floats */
    00540         double _double = 0;     /* double precision arguments %[eEfgG] */
    00541         int expt;               /* integer value of exponent */
    00542         int expsize = 0;        /* character count for expstr */
    00543         int ndig = 0;           /* actual number of digits returned by cvt */
    00544         char expstr[7];         /* buffer for exponent string */
    00545 #endif
    00546         u_long  ulval;          /* integer arguments %[diouxX] */
    00547 #ifdef _HAVE_SANE_QUAD_
    00548         u_quad_t uqval;         /* %q integers */
    00549 #endif /* _HAVE_SANE_QUAD_ */
    00550         int base;               /* base for [diouxX] conversion */
    00551         int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
    00552         long fieldsz;           /* field size expanded by sign, etc */
    00553         long realsz;            /* field size expanded by dprec */
    00554         int size;               /* size of converted field or string */
    00555         const char *xdigs = 0;  /* digits for [xX] conversion */
    00556 #define NIOV 8
    00557         struct __suio uio;      /* output information: summary */
    00558         struct __siov iov[NIOV];/* ... and individual io vectors */
    00559         char buf[BUF];          /* space for %c, %[diouxX], %[eEfgG] */
    00560         char ox[4];             /* space for 0x hex-prefix, hexadecimal's 1. */
    00561         char *const ebuf = buf + sizeof(buf);
    00562 #if SIZEOF_LONG > SIZEOF_INT
    00563         long ln;
    00564 #endif
    00565
    00566         /*
    00567          * Choose PADSIZE to trade efficiency vs. size.  If larger printf
    00568          * fields occur frequently, increase PADSIZE and make the initializers
    00569          * below longer.
    00570          */
    00571 #define PADSIZE 16              /* pad chunk size */
    00572         static const char blanks[PADSIZE] =
    00573          {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
    00574         static const char zeroes[PADSIZE] =
    00575          {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
    00576
    00577         /*
    00578          * BEWARE, these `goto error' on error, and PAD uses `n'.
    00579          */
    00580 #define PRINT(ptr, len) { \
    00581         iovp->iov_base = (ptr); \
    00582         iovp->iov_len = (len); \
    00583         uio.uio_resid += (len); \
    00584         iovp++; \
    00585         if (++uio.uio_iovcnt >= NIOV) { \
    00586                 if (BSD__sprint(fp, &uio)) \
    00587                         goto error; \
    00588                 iovp = iov; \
    00589         } \
    00590 }
    00591 #define PAD(howmany, with) { \
    00592         if ((n = (howmany)) > 0) { \
    00593                 while (n > PADSIZE) { \
    00594                         PRINT(with, PADSIZE); \
    00595                         n -= PADSIZE; \
    00596                 } \
    00597                 PRINT(with, n); \
    00598         } \
    00599 }
    00600 #if SIZEOF_LONG > SIZEOF_INT
    00601         /* abandon if too larger padding */
    00602 #define PAD_L(howmany, with) { \
    00603         ln = (howmany); \
    00604         if ((long)((int)ln) != ln) { \
    00605             errno = ENOMEM; \
    00606             goto error; \
    00607         } \
    00608         if (ln > 0) PAD((int)ln, with); \
    00609 }
    00610 #else
    00611 #define PAD_L(howmany, with) PAD(howmany, with)
    00612 #endif
    00613 #define FLUSH() { \
    00614         if (uio.uio_resid && BSD__sprint(fp, &uio)) \
    00615                 goto error; \
    00616         uio.uio_iovcnt = 0; \
    00617         iovp = iov; \
    00618 }
    00619
    00620         /*
    00621          * To extend shorts properly, we need both signed and unsigned
    00622          * argument extraction methods.
    00623          */
    00624 #define SARG() \
    00625         (flags&LONGINT ? va_arg(ap, long) : \
    00626             flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
    00627             (long)va_arg(ap, int))
    00628 #define UARG() \
    00629         (flags&LONGINT ? va_arg(ap, u_long) : \
    00630             flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
    00631             (u_long)va_arg(ap, u_int))
    00632
    00633         /* optimise fprintf(stderr) (and other unbuffered Unix files) */
    00634         if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
    00635             fp->_file >= 0)
    00636                 return (BSD__sbprintf(fp, fmt0, ap));
    00637
    00638         fmt = fmt0;
    00639         uio.uio_iov = iovp = iov;
    00640         uio.uio_resid = 0;
    00641         uio.uio_iovcnt = 0;
    00642         ret = 0;
    00643         xdigs = 0;
    00644
    00645         /*
    00646          * Scan the format for conversions (`%' character).
    00647          */
    00648         for (;;) {
    00649                 size_t nc;
    00650                 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
    00651                         /* void */;
    00652                 if ((nc = fmt - cp) != 0) {
    00653                         PRINT(cp, nc);
    00654                         ret += nc;
    00655                 }
    00656                 if (ch == '\0')
    00657                         goto done;
    00658                 fmt++;          /* skip over '%' */
    00659
    00660                 flags = 0;
    00661                 dprec = 0;
    00662                 width = 0;
    00663                 prec = -1;
    00664                 sign = '\0';
    00665
    00666 rflag:          ch = *fmt++;
    00667 reswitch:       switch (ch) {
    00668                 case ' ':
    00669                         /*
    00670                          * ``If the space and + flags both appear, the space
    00671                          * flag will be ignored.''
    00672                          *      -- ANSI X3J11
    00673                          */
    00674                         if (!sign)
    00675                                 sign = ' ';
    00676                         goto rflag;
    00677                 case '#':
    00678                         flags |= ALT;
    00679                         goto rflag;
    00680                 case '*':
    00681                         /*
    00682                          * ``A negative field width argument is taken as a
    00683                          * - flag followed by a positive field width.''
    00684                          *      -- ANSI X3J11
    00685                          * They don't exclude field widths read from args.
    00686                          */
    00687                         if ((width = va_arg(ap, int)) >= 0)
    00688                                 goto rflag;
    00689                         width = -width;
    00690                         /* FALLTHROUGH */
    00691                 case '-':
    00692                         flags |= LADJUST;
    00693                         goto rflag;
    00694                 case '+':
    00695                         sign = '+';
    00696                         goto rflag;
    00697                 case '.':
    00698                         if ((ch = *fmt++) == '*') {
    00699                                 n = va_arg(ap, int);
    00700                                 prec = n < 0 ? -1 : n;
    00701                                 goto rflag;
    00702                         }
    00703                         n = 0;
    00704                         while (is_digit(ch)) {
    00705                                 n = 10 * n + to_digit(ch);
    00706                                 ch = *fmt++;
    00707                         }
    00708                         prec = n < 0 ? -1 : n;
    00709                         goto reswitch;
    00710                 case '0':
    00711                         /*
    00712                          * ``Note that 0 is taken as a flag, not as the
    00713                          * beginning of a field width.''
    00714                          *      -- ANSI X3J11
    00715                          */
    00716                         flags |= ZEROPAD;
    00717                         goto rflag;
    00718                 case '1': case '2': case '3': case '4':
    00719                 case '5': case '6': case '7': case '8': case '9':
    00720                         n = 0;
    00721                         do {
    00722                                 n = 10 * n + to_digit(ch);
    00723                                 ch = *fmt++;
    00724                         } while (is_digit(ch));
    00725                         width = n;
    00726                         goto reswitch;
    00727 #ifdef FLOATING_POINT
    00728                 case 'L':
    00729                         flags |= LONGDBL;
    00730                         goto rflag;
    00731 #endif
    00732                 case 'h':
    00733                         flags |= SHORTINT;
    00734                         goto rflag;
    00735 #if SIZEOF_PTRDIFF_T == SIZEOF_LONG
    00736                 case 't':
    00737 #endif
    00738 #if SIZEOF_SIZE_T == SIZEOF_LONG
    00739                 case 'z':
    00740 #endif
    00741                 case 'l':
    00742                         flags |= LONGINT;
    00743                         goto rflag;
    00744 #ifdef _HAVE_SANE_QUAD_
    00745 #if SIZEOF_PTRDIFF_T == SIZEOF_LONG_LONG
    00746                 case 't':
    00747 #endif
    00748 #if SIZEOF_SIZE_T == SIZEOF_LONG_LONG
    00749                 case 'z':
    00750 #endif
    00751                 case 'q':
    00752                         flags |= QUADINT;
    00753                         goto rflag;
    00754 #endif /* _HAVE_SANE_QUAD_ */
    00755                 case 'c':
    00756                         cp = buf;
    00757                         *buf = (char)va_arg(ap, int);
    00758                         size = 1;
    00759                         sign = '\0';
    00760                         break;
    00761                 case 'D':
    00762                         flags |= LONGINT;
    00763                         /*FALLTHROUGH*/
    00764                 case 'd':
    00765                 case 'i':
    00766 #ifdef _HAVE_SANE_QUAD_
    00767                         if (flags & QUADINT) {
    00768                                 uqval = va_arg(ap, quad_t);
    00769                                 if ((quad_t)uqval < 0) {
    00770                                         uqval = -(quad_t)uqval;
    00771                                         sign = '-';
    00772                                 }
    00773                         } else
    00774 #endif /* _HAVE_SANE_QUAD_ */
    00775                         {
    00776                                 ulval = SARG();
    00777                                 if ((long)ulval < 0) {
    00778                                         ulval = (u_long)(-(long)ulval);
    00779                                         sign = '-';
    00780                                 }
    00781                         }
    00782                         base = 10;
    00783                         goto number;
    00784 #ifdef FLOATING_POINT
    00785                 case 'a':
    00786                 case 'A':
    00787                         if (prec >= 0)
    00788                                 prec++;
    00789                         goto fp_begin;
    00790                 case 'e':               /* anomalous precision */
    00791                 case 'E':
    00792                         if (prec != 0)
    00793                                 flags |= ALT;
    00794                         prec = (prec == -1) ?
    00795                                 DEFPREC + 1 : prec + 1;
    00796                         /* FALLTHROUGH */
    00797                         goto fp_begin;
    00798                 case 'f':               /* always print trailing zeroes */
    00799                         if (prec != 0)
    00800                                 flags |= ALT;
    00801                 case 'g':
    00802                 case 'G':
    00803                         if (prec == -1)
    00804                                 prec = DEFPREC;
    00805 fp_begin:               _double = va_arg(ap, double);
    00806                         /* do this before tricky precision changes */
    00807                         if (isinf(_double)) {
    00808                                 if (_double < 0)
    00809                                         sign = '-';
    00810                                 cp = "Inf";
    00811                                 size = 3;
    00812                                 break;
    00813                         }
    00814                         if (isnan(_double)) {
    00815                                 cp = "NaN";
    00816                                 size = 3;
    00817                                 break;
    00818                         }
    00819                         flags |= FPT;
    00820                         cp = cvt(_double, prec, flags, &softsign,
    00821                                 &expt, ch, &ndig, buf);
    00822                         if (ch == 'g' || ch == 'G') {
    00823                                 if (expt <= -4 || (expt > prec && expt > 1))
    00824                                         ch = (ch == 'g') ? 'e' : 'E';
    00825                                 else
    00826                                         ch = 'g';
    00827                         }
    00828                         if (ch == 'a' || ch == 'A') {
    00829                                 --expt;
    00830                                 expsize = exponent(expstr, expt, ch + 'p' - 'a');
    00831                                 size = expsize + ndig;
    00832                         }
    00833                         else if (ch <= 'e') {   /* 'e' or 'E' fmt */
    00834                                 --expt;
    00835                                 expsize = exponent(expstr, expt, ch);
    00836                                 size = expsize + ndig;
    00837                                 if (ndig > 1 || flags & ALT)
    00838                                         ++size;
    00839                         } else if (ch == 'f') {         /* f fmt */
    00840                                 if (expt > 0) {
    00841                                         size = expt;
    00842                                         if (prec || flags & ALT)
    00843                                                 size += prec + 1;
    00844                                 } else if (!prec) { /* "0" */
    00845                                         size = 1;
    00846                                 } else  /* "0.X" */
    00847                                         size = prec + 2;
    00848                         } else if (expt >= ndig) {      /* fixed g fmt */
    00849                                 size = expt;
    00850                                 if (flags & ALT)
    00851                                         ++size;
    00852                         } else
    00853                                 size = ndig + (expt > 0 ?
    00854                                         1 : 2 - expt);
    00855
    00856                         if (softsign)
    00857                                 sign = '-';
    00858                         break;
    00859 #endif /* FLOATING_POINT */
    00860                 case 'n':
    00861 #ifdef _HAVE_SANE_QUAD_
    00862                         if (flags & QUADINT)
    00863                                 *va_arg(ap, quad_t *) = ret;
    00864                         else if (flags & LONGINT)
    00865 #else /* _HAVE_SANE_QUAD_ */
    00866                         if (flags & LONGINT)
    00867 #endif /* _HAVE_SANE_QUAD_ */
    00868                                 *va_arg(ap, long *) = ret;
    00869                         else if (flags & SHORTINT)
    00870                                 *va_arg(ap, short *) = (short)ret;
    00871                         else
    00872                                 *va_arg(ap, int *) = (int)ret;
    00873                         continue;       /* no output */
    00874                 case 'O':
    00875                         flags |= LONGINT;
    00876                         /*FALLTHROUGH*/
    00877                 case 'o':
    00878 #ifdef _HAVE_SANE_QUAD_
    00879                         if (flags & QUADINT)
    00880                                 uqval = va_arg(ap, u_quad_t);
    00881                         else
    00882 #endif /* _HAVE_SANE_QUAD_ */
    00883                                 ulval = UARG();
    00884                         base = 8;
    00885                         goto nosign;
    00886                 case 'p':
    00887                         /*
    00888                          * ``The argument shall be a pointer to void.  The
    00889                          * value of the pointer is converted to a sequence
    00890                          * of printable characters, in an implementation-
    00891                          * defined manner.''
    00892                          *      -- ANSI X3J11
    00893                          */
    00894                         prec = (int)(sizeof(void*)*CHAR_BIT/4);
    00895 #ifdef _HAVE_LLP64_
    00896                         uqval = (u_quad_t)va_arg(ap, void *);
    00897                         flags = (flags) | QUADINT | HEXPREFIX;
    00898 #else
    00899                         ulval = (u_long)va_arg(ap, void *);
    00900 #ifdef _HAVE_SANE_QUAD_
    00901                         flags = (flags & ~QUADINT) | HEXPREFIX;
    00902 #else /* _HAVE_SANE_QUAD_ */
    00903                         flags = (flags) | HEXPREFIX;
    00904 #endif /* _HAVE_SANE_QUAD_ */
    00905 #endif
    00906                         base = 16;
    00907                         xdigs = "0123456789abcdef";
    00908                         ch = 'x';
    00909                         goto nosign;
    00910                 case 's':
    00911                         if ((cp = va_arg(ap, char *)) == NULL)
    00912                                 cp = "(null)";
    00913                         if (prec >= 0) {
    00914                                 /*
    00915                                  * can't use strlen; can only look for the
    00916                                  * NUL in the first `prec' characters, and
    00917                                  * strlen() will go further.
    00918                                  */
    00919                                 const char *p = (char *)memchr(cp, 0, prec);
    00920
    00921                                 if (p != NULL && (p - cp) > prec)
    00922                                         size = (int)(p - cp);
    00923                                 else
    00924                                         size = prec;
    00925                         }
    00926                         else {
    00927                                 fieldsz = strlen(cp);
    00928                                 goto long_len;
    00929                         }
    00930                         sign = '\0';
    00931                         break;
    00932                 case 'U':
    00933                         flags |= LONGINT;
    00934                         /*FALLTHROUGH*/
    00935                 case 'u':
    00936 #ifdef _HAVE_SANE_QUAD_
    00937                         if (flags & QUADINT)
    00938                                 uqval = va_arg(ap, u_quad_t);
    00939                         else
    00940 #endif /* _HAVE_SANE_QUAD_ */
    00941                                 ulval = UARG();
    00942                         base = 10;
    00943                         goto nosign;
    00944                 case 'X':
    00945                         xdigs = "0123456789ABCDEF";
    00946                         goto hex;
    00947                 case 'x':
    00948                         xdigs = "0123456789abcdef";
    00949 hex:
    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 = 16;
    00957                         /* leading 0x/X only if non-zero */
    00958                         if (flags & ALT &&
    00959 #ifdef _HAVE_SANE_QUAD_
    00960                             (flags & QUADINT ? uqval != 0 : ulval != 0)
    00961 #else /* _HAVE_SANE_QUAD_ */
    00962                             ulval != 0
    00963 #endif /* _HAVE_SANE_QUAD_ */
    00964                             )
    00965                                 flags |= HEXPREFIX;
    00966
    00967                         /* unsigned conversions */
    00968 nosign:                 sign = '\0';
    00969                         /*
    00970                          * ``... diouXx conversions ... if a precision is
    00971                          * specified, the 0 flag will be ignored.''
    00972                          *      -- ANSI X3J11
    00973                          */
    00974 number:                 if ((dprec = prec) >= 0)
    00975                                 flags &= ~ZEROPAD;
    00976
    00977                         /*
    00978                          * ``The result of converting a zero value with an
    00979                          * explicit precision of zero is no characters.''
    00980                          *      -- ANSI X3J11
    00981                          */
    00982 #ifdef _HAVE_SANE_QUAD_
    00983                         if (flags & QUADINT) {
    00984                                 if (uqval != 0 || prec != 0)
    00985                                         cp = BSD__uqtoa(uqval, ebuf, base,
    00986                                             flags & ALT, xdigs);
    00987                         } else
    00988 #else /* _HAVE_SANE_QUAD_ */
    00989 #endif /* _HAVE_SANE_QUAD_ */
    00990                         {
    00991                                 if (ulval != 0 || prec != 0)
    00992                                         cp = BSD__ultoa(ulval, ebuf, base,
    00993                                             flags & ALT, xdigs);
    00994                         }
    00995                         size = (int)(ebuf - cp);
    00996                         break;
    00997                 default:        /* "%?" prints ?, unless ? is NUL */
    00998                         if (ch == '\0')
    00999                                 goto done;
    01000                         /* pretend it was %c with argument ch */
    01001                         cp = buf;
    01002                         *buf = ch;
    01003                         size = 1;
    01004                         sign = '\0';
    01005                         break;
    01006                 }
    01007
    01008                 /*
    01009                  * All reasonable formats wind up here.  At this point, `cp'
    01010                  * points to a string which (if not flags&LADJUST) should be
    01011                  * padded out to `width' places.  If flags&ZEROPAD, it should
    01012                  * first be prefixed by any sign or other prefix; otherwise,
    01013                  * it should be blank padded before the prefix is emitted.
    01014                  * After any left-hand padding and prefixing, emit zeroes
    01015                  * required by a decimal [diouxX] precision, then print the
    01016                  * string proper, then emit zeroes required by any leftover
    01017                  * floating precision; finally, if LADJUST, pad with blanks.
    01018                  *
    01019                  * Compute actual size, so we know how much to pad.
    01020                  * fieldsz excludes decimal prec; realsz includes it.
    01021                  */
    01022                 fieldsz = size;
    01023 long_len:
    01024                 if (sign)
    01025                         fieldsz++;
    01026                 else if (flags & HEXPREFIX)
    01027                         fieldsz += 2;
    01028                 realsz = dprec > fieldsz ? dprec : fieldsz;
    01029
    01030                 /* right-adjusting blank padding */
    01031                 if ((flags & (LADJUST|ZEROPAD)) == 0)
    01032                         PAD_L(width - realsz, blanks);
    01033
    01034                 /* prefix */
    01035                 if (sign) {
    01036                         PRINT(&sign, 1);
    01037                 } else if (flags & HEXPREFIX) {
    01038                         ox[0] = '0';
    01039                         ox[1] = ch;
    01040                         PRINT(ox, 2);
    01041                 }
    01042
    01043                 /* right-adjusting zero padding */
    01044                 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
    01045                         PAD_L(width - realsz, zeroes);
    01046
    01047                 /* leading zeroes from decimal precision */
    01048                 PAD_L(dprec - fieldsz, zeroes);
    01049                 if (sign)
    01050                         fieldsz--;
    01051                 else if (flags & HEXPREFIX)
    01052                         fieldsz -= 2;
    01053
    01054                 /* the string or number proper */
    01055 #ifdef FLOATING_POINT
    01056                 if ((flags & FPT) == 0) {
    01057                         PRINT(cp, fieldsz);
    01058                 } else {        /* glue together f_p fragments */
    01059                         if (ch == 'a' || ch == 'A') {
    01060                                 ox[0] = '0';
    01061                                 ox[1] = ch + ('x' - 'a');
    01062                                 PRINT(ox, 2);
    01063                                 if (ndig > 1 || flags & ALT) {
    01064                                         ox[2] = *cp++;
    01065                                         ox[3] = '.';
    01066                                         PRINT(ox+2, 2);
    01067                                         PRINT(cp, ndig-1);
    01068                                 } else  /* XpYYY */
    01069                                         PRINT(cp, 1);
    01070                                 PRINT(expstr, expsize);
    01071                         }
    01072                         else if (ch >= 'f') {   /* 'f' or 'g' */
    01073                                 if (_double == 0) {
    01074                                 /* kludge for __dtoa irregularity */
    01075                                         if (ndig <= 1 &&
    01076                                             (flags & ALT) == 0) {
    01077                                                 PRINT("0", 1);
    01078                                         } else {
    01079                                                 PRINT("0.", 2);
    01080                                                 PAD(ndig - 1, zeroes);
    01081                                         }
    01082                                 } else if (expt == 0 && ndig == 0 && (flags & ALT) == 0) {
    01083                                         PRINT("0", 1);
    01084                                 } else if (expt <= 0) {
    01085                                         PRINT("0.", 2);
    01086                                         PAD(-expt, zeroes);
    01087                                         PRINT(cp, ndig);
    01088                                 } else if (expt >= ndig) {
    01089                                         PRINT(cp, ndig);
    01090                                         PAD(expt - ndig, zeroes);
    01091                                         if (flags & ALT)
    01092                                                 PRINT(".", 1);
    01093                                 } else {
    01094                                         PRINT(cp, expt);
    01095                                         cp += expt;
    01096                                         PRINT(".", 1);
    01097                                         PRINT(cp, ndig-expt);
    01098                                 }
    01099                         } else {        /* 'e' or 'E' */
    01100                                 if (ndig > 1 || flags & ALT) {
    01101                                         ox[0] = *cp++;
    01102                                         ox[1] = '.';
    01103                                         PRINT(ox, 2);
    01104                                         if (_double /*|| flags & ALT == 0*/) {
    01105                                                 PRINT(cp, ndig-1);
    01106                                         } else  /* 0.[0..] */
    01107                                                 /* __dtoa irregularity */
    01108                                                 PAD(ndig - 1, zeroes);
    01109                                 } else  /* XeYYY */
    01110                                         PRINT(cp, 1);
    01111                                 PRINT(expstr, expsize);
    01112                         }
    01113                 }
    01114 #else
    01115                 PRINT(cp, fieldsz);
    01116 #endif
    01117                 /* left-adjusting padding (always blank) */
    01118                 if (flags & LADJUST)
    01119                         PAD_L(width - realsz, blanks);
    01120
    01121                 /* finally, adjust ret */
    01122                 ret += width > realsz ? width : realsz;
    01123
    01124                 FLUSH();        /* copy out the I/O vectors */
    01125         }
    01126 done:
    01127         FLUSH();
    01128 error:
    01129         return (__sferror(fp) ? EOF : ret);
    01130         /* NOTREACHED */
    01131 }
    01132
    01133 #ifdef FLOATING_POINT
    01134
    01135 extern char *BSD__dtoa __P((double, int, int, int *, int *, char **));
    01136 extern char *BSD__hdtoa(double, const char *, int, int *, int *, char **);
    01137
    01138 static char *
    01139 cvt(value, ndigits, flags, sign, decpt, ch, length, buf)
    01140         double value;
    01141         int ndigits, flags, *decpt, ch, *length;
    01142         char *sign, *buf;
    01143 {
    01144         int mode, dsgn;
    01145         char *digits, *bp, *rve;
    01146
    01147         if (ch == 'f')
    01148                 mode = 3;
    01149         else {
    01150                 mode = 2;
    01151         }
    01152         if (value < 0) {
    01153                 value = -value;
    01154                 *sign = '-';
    01155         } else if (value == 0.0 && 1.0/value < 0) {
    01156             *sign = '-';
    01157         } else {
    01158             *sign = '\000';
    01159         }
    01160         if (ch == 'a' || ch =='A') {
    01161             digits = BSD__hdtoa(value,
    01162                     ch == 'a' ? "0123456789abcdef" : "0123456789ABCDEF",
    01163                     ndigits, decpt, &dsgn, &rve);
    01164         }
    01165         else {
    01166             digits = BSD__dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
    01167         }
    01168         memcpy(buf, digits, rve - digits);
    01169         xfree(digits);
    01170         rve = buf + (rve - digits);
    01171         digits = buf;
    01172         if (flags & ALT) {      /* Print trailing zeros */
    01173                 bp = digits + ndigits;
    01174                 if (ch == 'f') {
    01175                         if (*digits == '0' && value)
    01176                                 *decpt = -ndigits + 1;
    01177                         bp += *decpt;
    01178                 }
    01179                 if (value == 0) /* kludge for __dtoa irregularity */
    01180                         rve = bp;
    01181                 while (rve < bp)
    01182                         *rve++ = '0';
    01183         }
    01184         *length = (int)(rve - digits);
    01185         return (digits);
    01186 }
    01187
    01188 static int
    01189 exponent(p0, exp, fmtch)
    01190         char *p0;
    01191         int exp, fmtch;
    01192 {
    01193         register char *p, *t;
    01194         char expbuf[MAXEXP];
    01195
    01196         p = p0;
    01197         *p++ = fmtch;
    01198         if (exp < 0) {
    01199                 exp = -exp;
    01200                 *p++ = '-';
    01201         }
    01202         else
    01203                 *p++ = '+';
    01204         t = expbuf + MAXEXP;
    01205         if (exp > 9) {
    01206                 do {
    01207                         *--t = to_char(exp % 10);
    01208                 } while ((exp /= 10) > 9);
    01209                 *--t = to_char(exp);
    01210                 for (; t < expbuf + MAXEXP; *p++ = *t++);
    01211         }
    01212         else {
    01213                 if (fmtch & 15) *p++ = '0'; /* other than p or P */
    01214                 *p++ = to_char(exp);
    01215         }
    01216         return (int)(p - p0);
    01217 }
    01218 #endif /* FLOATING_POINT */
    01219
    01220 int
    01221 ruby_vsnprintf(char *str, size_t n, const char *fmt, va_list ap)
    01222 {
    01223         int ret;
    01224         FILE f;
    01225
    01226         if ((int)n < 1)
    01227                 return (EOF);
    01228         f._flags = __SWR | __SSTR;
    01229         f._bf._base = f._p = (unsigned char *)str;
    01230         f._bf._size = f._w = n - 1;
    01231         f.vwrite = BSD__sfvwrite;
    01232         ret = (int)BSD_vfprintf(&f, fmt, ap);
    01233         *f._p = 0;
    01234         return (ret);
    01235 }
    01236
    01237 int
    01238 ruby_snprintf(char *str, size_t n, char const *fmt, ...)
    01239 {
    01240         int ret;
    01241         va_list ap;
    01242         FILE f;
    01243
    01244         if ((int)n < 1)
    01245                 return (EOF);
    01246
    01247         va_start(ap, fmt);
    01248         f._flags = __SWR | __SSTR;
    01249         f._bf._base = f._p = (unsigned char *)str;
    01250         f._bf._size = f._w = n - 1;
    01251         f.vwrite = BSD__sfvwrite;
    01252         ret = (int)BSD_vfprintf(&f, fmt, ap);
    01253         *f._p = 0;
    01254         va_end(ap);
    01255         return (ret);
    01256 }
    01257