Ruby 1.9.3p327(2012-11-10revision37606)
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 } FILE;
00187 
00188 
00189 #define __SLBF  0x0001          /* line buffered */
00190 #define __SNBF  0x0002          /* unbuffered */
00191 #define __SRD   0x0004          /* OK to read */
00192 #define __SWR   0x0008          /* OK to write */
00193         /* RD and WR are never simultaneously asserted */
00194 #define __SRW   0x0010          /* open for reading & writing */
00195 #define __SEOF  0x0020          /* found EOF */
00196 #define __SERR  0x0040          /* found error */
00197 #define __SMBF  0x0080          /* _buf is from malloc */
00198 #define __SAPP  0x0100          /* fdopen()ed in append mode */
00199 #define __SSTR  0x0200          /* this is an sprintf/snprintf string */
00200 #define __SOPT  0x0400          /* do fseek() optimisation */
00201 #define __SNPT  0x0800          /* do not do fseek() optimisation */
00202 #define __SOFF  0x1000          /* set iff _offset is in fact correct */
00203 #define __SMOD  0x2000          /* true => fgetln modified _p text */
00204 
00205 
00206 #define EOF     (-1)
00207 
00208 
00209 #define __sfeof(p)      (((p)->_flags & __SEOF) != 0)
00210 #define __sferror(p)    (((p)->_flags & __SERR) != 0)
00211 #define __sclearerr(p)  ((void)((p)->_flags &= ~(__SERR|__SEOF)))
00212 #define __sfileno(p)    ((p)->_file)
00213 
00214 #undef feof
00215 #undef ferror
00216 #undef clearerr
00217 #define feof(p)         __sfeof(p)
00218 #define ferror(p)       __sferror(p)
00219 #define clearerr(p)     __sclearerr(p)
00220 
00221 #ifndef _ANSI_SOURCE
00222 #define fileno(p)       __sfileno(p)
00223 #endif
00224 
00225 
00226 /*
00227  * I/O descriptors for __sfvwrite().
00228  */
00229 struct __siov {
00230         const void *iov_base;
00231         size_t  iov_len;
00232 };
00233 struct __suio {
00234         struct  __siov *uio_iov;
00235         int     uio_iovcnt;
00236         size_t  uio_resid;
00237 };
00238 
00239 /*
00240  * Write some memory regions.  Return zero on success, EOF on error.
00241  *
00242  * This routine is large and unsightly, but most of the ugliness due
00243  * to the three different kinds of output buffering is handled here.
00244  */
00245 static int BSD__sfvwrite(fp, uio)
00246         register FILE *fp;
00247         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 __P((double, int, int, char *, int *, int, int *, char *));
00506 static int exponent __P((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                         flags |= LONGINT;
00749                         goto rflag;
00750 #ifdef _HAVE_SANE_QUAD_
00751 #if SIZEOF_PTRDIFF_T == SIZEOF_LONG_LONG
00752                 case 't':
00753 #endif
00754 #if SIZEOF_SIZE_T == SIZEOF_LONG_LONG
00755                 case 'z':
00756 #endif
00757                 case 'q':
00758                         flags |= QUADINT;
00759                         goto rflag;
00760 #endif /* _HAVE_SANE_QUAD_ */
00761 #ifdef _WIN32
00762                 case 'I':
00763                         if (*fmt == '3' && *(fmt + 1) == '2') {
00764                             fmt += 2;
00765                             flags |= LONGINT;
00766                         }
00767 #ifdef _HAVE_SANE_QUAD_
00768                         else if (*fmt == '6' && *(fmt + 1) == '4') {
00769                             fmt += 2;
00770                             flags |= QUADINT;
00771                         }
00772 #endif
00773                         else
00774 #if defined(_HAVE_SANE_QUAD_) && SIZEOF_SIZE_T == SIZEOF_LONG_LONG
00775                             flags |= QUADINT;
00776 #else
00777                             flags |= LONGINT;
00778 #endif
00779                         goto rflag;
00780 #endif
00781                 case 'c':
00782                         cp = buf;
00783                         *buf = (char)va_arg(ap, int);
00784                         size = 1;
00785                         sign = '\0';
00786                         break;
00787                 case 'D':
00788                         flags |= LONGINT;
00789                         /*FALLTHROUGH*/
00790                 case 'd':
00791                 case 'i':
00792 #ifdef _HAVE_SANE_QUAD_
00793                         if (flags & QUADINT) {
00794                                 uqval = va_arg(ap, quad_t);
00795                                 if ((quad_t)uqval < 0) {
00796                                         uqval = -(quad_t)uqval;
00797                                         sign = '-';
00798                                 }
00799                         } else
00800 #endif /* _HAVE_SANE_QUAD_ */
00801                         {
00802                                 ulval = SARG();
00803                                 if ((long)ulval < 0) {
00804                                         ulval = (u_long)(-(long)ulval);
00805                                         sign = '-';
00806                                 }
00807                         }
00808                         base = 10;
00809                         goto number;
00810 #ifdef FLOATING_POINT
00811                 case 'a':
00812                 case 'A':
00813                         if (prec > 0) {
00814                                 flags |= ALT;
00815                                 prec++;
00816                         }
00817                         goto fp_begin;
00818                 case 'e':               /* anomalous precision */
00819                 case 'E':
00820                         if (prec != 0)
00821                                 flags |= ALT;
00822                         prec = (prec == -1) ?
00823                                 DEFPREC + 1 : prec + 1;
00824                         /* FALLTHROUGH */
00825                         goto fp_begin;
00826                 case 'f':               /* always print trailing zeroes */
00827                         if (prec != 0)
00828                                 flags |= ALT;
00829                 case 'g':
00830                 case 'G':
00831                         if (prec == -1)
00832                                 prec = DEFPREC;
00833 fp_begin:               _double = va_arg(ap, double);
00834                         /* do this before tricky precision changes */
00835                         if (isinf(_double)) {
00836                                 if (_double < 0)
00837                                         sign = '-';
00838                                 cp = "Inf";
00839                                 size = 3;
00840                                 break;
00841                         }
00842                         if (isnan(_double)) {
00843                                 cp = "NaN";
00844                                 size = 3;
00845                                 break;
00846                         }
00847                         flags |= FPT;
00848                         cp = cvt(_double, prec, flags, &softsign,
00849                                 &expt, ch, &ndig, buf);
00850                         if (ch == 'g' || ch == 'G') {
00851                                 if (expt <= -4 || (expt > prec && expt > 1))
00852                                         ch = (ch == 'g') ? 'e' : 'E';
00853                                 else
00854                                         ch = 'g';
00855                         }
00856                         if (ch == 'a' || ch == 'A') {
00857                                 flags |= HEXPREFIX;
00858                                 --expt;
00859                                 expsize = exponent(expstr, expt, ch + 'p' - 'a');
00860                                 ch += 'x' - 'a';
00861                                 size = expsize + ndig;
00862                                 if (ndig > 1 || flags & ALT)
00863                                         ++size; /* floating point */
00864                         }
00865                         else if (ch <= 'e') {   /* 'e' or 'E' fmt */
00866                                 --expt;
00867                                 expsize = exponent(expstr, expt, ch);
00868                                 size = expsize + ndig;
00869                                 if (ndig > 1 || flags & ALT)
00870                                         ++size;
00871                         } else if (ch == 'f') {         /* f fmt */
00872                                 if (expt > 0) {
00873                                         size = expt;
00874                                         if (prec || flags & ALT)
00875                                                 size += prec + 1;
00876                                 } else if (!prec) { /* "0" */
00877                                         size = 1;
00878                                         if (flags & ALT)
00879                                                 size += 1;
00880                                 } else  /* "0.X" */
00881                                         size = prec + 2;
00882                         } else if (expt >= ndig) {      /* fixed g fmt */
00883                                 size = expt;
00884                                 if (flags & ALT)
00885                                         ++size;
00886                         } else
00887                                 size = ndig + (expt > 0 ?
00888                                         1 : 2 - expt);
00889 
00890                         if (softsign)
00891                                 sign = '-';
00892                         break;
00893 #endif /* FLOATING_POINT */
00894                 case 'n':
00895 #ifdef _HAVE_SANE_QUAD_
00896                         if (flags & QUADINT)
00897                                 *va_arg(ap, quad_t *) = ret;
00898                         else if (flags & LONGINT)
00899 #else /* _HAVE_SANE_QUAD_ */
00900                         if (flags & LONGINT)
00901 #endif /* _HAVE_SANE_QUAD_ */
00902                                 *va_arg(ap, long *) = ret;
00903                         else if (flags & SHORTINT)
00904                                 *va_arg(ap, short *) = (short)ret;
00905                         else
00906                                 *va_arg(ap, int *) = (int)ret;
00907                         continue;       /* no output */
00908                 case 'O':
00909                         flags |= LONGINT;
00910                         /*FALLTHROUGH*/
00911                 case 'o':
00912 #ifdef _HAVE_SANE_QUAD_
00913                         if (flags & QUADINT)
00914                                 uqval = va_arg(ap, u_quad_t);
00915                         else
00916 #endif /* _HAVE_SANE_QUAD_ */
00917                                 ulval = UARG();
00918                         base = 8;
00919                         goto nosign;
00920                 case 'p':
00921                         /*
00922                          * ``The argument shall be a pointer to void.  The
00923                          * value of the pointer is converted to a sequence
00924                          * of printable characters, in an implementation-
00925                          * defined manner.''
00926                          *      -- ANSI X3J11
00927                          */
00928                         prec = (int)(sizeof(void*)*CHAR_BIT/4);
00929 #ifdef _HAVE_LLP64_
00930                         uqval = (u_quad_t)va_arg(ap, void *);
00931                         flags = (flags) | QUADINT | HEXPREFIX;
00932 #else
00933                         ulval = (u_long)va_arg(ap, void *);
00934 #ifdef _HAVE_SANE_QUAD_
00935                         flags = (flags & ~QUADINT) | HEXPREFIX;
00936 #else /* _HAVE_SANE_QUAD_ */
00937                         flags = (flags) | HEXPREFIX;
00938 #endif /* _HAVE_SANE_QUAD_ */
00939 #endif
00940                         base = 16;
00941                         xdigs = "0123456789abcdef";
00942                         ch = 'x';
00943                         goto nosign;
00944                 case 's':
00945                         if ((cp = va_arg(ap, char *)) == NULL)
00946                                 cp = "(null)";
00947                         if (prec >= 0) {
00948                                 /*
00949                                  * can't use strlen; can only look for the
00950                                  * NUL in the first `prec' characters, and
00951                                  * strlen() will go further.
00952                                  */
00953                                 const char *p = (char *)memchr(cp, 0, prec);
00954 
00955                                 if (p != NULL && (p - cp) > prec)
00956                                         size = (int)(p - cp);
00957                                 else
00958                                         size = prec;
00959                         }
00960                         else {
00961                                 fieldsz = strlen(cp);
00962                                 goto long_len;
00963                         }
00964                         sign = '\0';
00965                         break;
00966                 case 'U':
00967                         flags |= LONGINT;
00968                         /*FALLTHROUGH*/
00969                 case 'u':
00970 #ifdef _HAVE_SANE_QUAD_
00971                         if (flags & QUADINT)
00972                                 uqval = va_arg(ap, u_quad_t);
00973                         else
00974 #endif /* _HAVE_SANE_QUAD_ */
00975                                 ulval = UARG();
00976                         base = 10;
00977                         goto nosign;
00978                 case 'X':
00979                         xdigs = "0123456789ABCDEF";
00980                         goto hex;
00981                 case 'x':
00982                         xdigs = "0123456789abcdef";
00983 hex:
00984 #ifdef _HAVE_SANE_QUAD_
00985                         if (flags & QUADINT)
00986                                 uqval = va_arg(ap, u_quad_t);
00987                         else
00988 #endif /* _HAVE_SANE_QUAD_ */
00989                                 ulval = UARG();
00990                         base = 16;
00991                         /* leading 0x/X only if non-zero */
00992                         if (flags & ALT &&
00993 #ifdef _HAVE_SANE_QUAD_
00994                             (flags & QUADINT ? uqval != 0 : ulval != 0)
00995 #else /* _HAVE_SANE_QUAD_ */
00996                             ulval != 0
00997 #endif /* _HAVE_SANE_QUAD_ */
00998                             )
00999                                 flags |= HEXPREFIX;
01000 
01001                         /* unsigned conversions */
01002 nosign:                 sign = '\0';
01003                         /*
01004                          * ``... diouXx conversions ... if a precision is
01005                          * specified, the 0 flag will be ignored.''
01006                          *      -- ANSI X3J11
01007                          */
01008 number:                 if ((dprec = prec) >= 0)
01009                                 flags &= ~ZEROPAD;
01010 
01011                         /*
01012                          * ``The result of converting a zero value with an
01013                          * explicit precision of zero is no characters.''
01014                          *      -- ANSI X3J11
01015                          */
01016 #ifdef _HAVE_SANE_QUAD_
01017                         if (flags & QUADINT) {
01018                                 if (uqval != 0 || prec != 0)
01019                                         cp = BSD__uqtoa(uqval, ebuf, base,
01020                                             flags & ALT, xdigs);
01021                         } else
01022 #else /* _HAVE_SANE_QUAD_ */
01023 #endif /* _HAVE_SANE_QUAD_ */
01024                         {
01025                                 if (ulval != 0 || prec != 0)
01026                                         cp = BSD__ultoa(ulval, ebuf, base,
01027                                             flags & ALT, xdigs);
01028                         }
01029                         size = (int)(ebuf - cp);
01030                         break;
01031                 default:        /* "%?" prints ?, unless ? is NUL */
01032                         if (ch == '\0')
01033                                 goto done;
01034                         /* pretend it was %c with argument ch */
01035                         cp = buf;
01036                         *buf = ch;
01037                         size = 1;
01038                         sign = '\0';
01039                         break;
01040                 }
01041 
01042                 /*
01043                  * All reasonable formats wind up here.  At this point, `cp'
01044                  * points to a string which (if not flags&LADJUST) should be
01045                  * padded out to `width' places.  If flags&ZEROPAD, it should
01046                  * first be prefixed by any sign or other prefix; otherwise,
01047                  * it should be blank padded before the prefix is emitted.
01048                  * After any left-hand padding and prefixing, emit zeroes
01049                  * required by a decimal [diouxX] precision, then print the
01050                  * string proper, then emit zeroes required by any leftover
01051                  * floating precision; finally, if LADJUST, pad with blanks.
01052                  *
01053                  * Compute actual size, so we know how much to pad.
01054                  * fieldsz excludes decimal prec; realsz includes it.
01055                  */
01056                 fieldsz = size;
01057 long_len:
01058                 if (sign)
01059                         fieldsz++;
01060                 if (flags & HEXPREFIX)
01061                         fieldsz += 2;
01062                 realsz = dprec > fieldsz ? dprec : fieldsz;
01063 
01064                 /* right-adjusting blank padding */
01065                 if ((flags & (LADJUST|ZEROPAD)) == 0)
01066                         PAD_L(width - realsz, blanks);
01067 
01068                 /* prefix */
01069                 if (sign) {
01070                         PRINT(&sign, 1);
01071                 }
01072                 if (flags & HEXPREFIX) {
01073                         ox[0] = '0';
01074                         ox[1] = ch;
01075                         PRINT(ox, 2);
01076                 }
01077 
01078                 /* right-adjusting zero padding */
01079                 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
01080                         PAD_L(width - realsz, zeroes);
01081 
01082                 /* leading zeroes from decimal precision */
01083                 PAD_L(dprec - fieldsz, zeroes);
01084                 if (sign)
01085                         fieldsz--;
01086                 if (flags & HEXPREFIX)
01087                         fieldsz -= 2;
01088 
01089                 /* the string or number proper */
01090 #ifdef FLOATING_POINT
01091                 if ((flags & FPT) == 0) {
01092                         PRINT(cp, fieldsz);
01093                 } else {        /* glue together f_p fragments */
01094                         if (flags & HEXPREFIX) {
01095                                 if (ndig > 1 || flags & ALT) {
01096                                         ox[2] = *cp++;
01097                                         ox[3] = '.';
01098                                         PRINT(ox+2, 2);
01099                                         if (ndig > 0) PRINT(cp, ndig-1);
01100                                 } else  /* XpYYY */
01101                                         PRINT(cp, 1);
01102                                 PRINT(expstr, expsize);
01103                         }
01104                         else if (ch >= 'f') {   /* 'f' or 'g' */
01105                                 if (_double == 0) {
01106                                 /* kludge for __dtoa irregularity */
01107                                         if (ndig <= 1 &&
01108                                             (flags & ALT) == 0) {
01109                                                 PRINT("0", 1);
01110                                         } else {
01111                                                 PRINT("0.", 2);
01112                                                 PAD(ndig - 1, zeroes);
01113                                         }
01114                                 } else if (expt == 0 && ndig == 0 && (flags & ALT) == 0) {
01115                                         PRINT("0", 1);
01116                                 } else if (expt <= 0) {
01117                                         PRINT("0.", 2);
01118                                         PAD(-expt, zeroes);
01119                                         PRINT(cp, ndig);
01120                                 } else if (expt >= ndig) {
01121                                         PRINT(cp, ndig);
01122                                         PAD(expt - ndig, zeroes);
01123                                         if (flags & ALT)
01124                                                 PRINT(".", 1);
01125                                 } else {
01126                                         PRINT(cp, expt);
01127                                         cp += expt;
01128                                         PRINT(".", 1);
01129                                         PRINT(cp, ndig-expt);
01130                                 }
01131                         } else {        /* 'e' or 'E' */
01132                                 if (ndig > 1 || flags & ALT) {
01133                                         ox[0] = *cp++;
01134                                         ox[1] = '.';
01135                                         PRINT(ox, 2);
01136                                         if (_double /*|| flags & ALT == 0*/) {
01137                                                 PRINT(cp, ndig-1);
01138                                         } else  /* 0.[0..] */
01139                                                 /* __dtoa irregularity */
01140                                                 PAD(ndig - 1, zeroes);
01141                                 } else  /* XeYYY */
01142                                         PRINT(cp, 1);
01143                                 PRINT(expstr, expsize);
01144                         }
01145                 }
01146 #else
01147                 PRINT(cp, fieldsz);
01148 #endif
01149                 /* left-adjusting padding (always blank) */
01150                 if (flags & LADJUST)
01151                         PAD_L(width - realsz, blanks);
01152 
01153                 /* finally, adjust ret */
01154                 ret += width > realsz ? width : realsz;
01155 
01156                 FLUSH();        /* copy out the I/O vectors */
01157         }
01158 done:
01159         FLUSH();
01160 error:
01161         return (__sferror(fp) ? EOF : ret);
01162         /* NOTREACHED */
01163 }
01164 
01165 #ifdef FLOATING_POINT
01166 
01167 extern char *BSD__dtoa __P((double, int, int, int *, int *, char **));
01168 extern char *BSD__hdtoa(double, const char *, int, int *, int *, char **);
01169 
01170 static char *
01171 cvt(value, ndigits, flags, sign, decpt, ch, length, buf)
01172         double value;
01173         int ndigits, flags, *decpt, ch, *length;
01174         char *sign, *buf;
01175 {
01176         int mode, dsgn;
01177         char *digits, *bp, *rve;
01178 
01179         if (ch == 'f')
01180                 mode = 3;
01181         else {
01182                 mode = 2;
01183         }
01184         if (value < 0) {
01185                 value = -value;
01186                 *sign = '-';
01187         } else if (value == 0.0 && 1.0/value < 0) {
01188             *sign = '-';
01189         } else {
01190             *sign = '\000';
01191         }
01192         if (ch == 'a' || ch =='A') {
01193             digits = BSD__hdtoa(value,
01194                     ch == 'a' ? "0123456789abcdef" : "0123456789ABCDEF",
01195                     ndigits, decpt, &dsgn, &rve);
01196         }
01197         else {
01198             digits = BSD__dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
01199         }
01200         buf[0] = 0; /* rve - digits may be 0 */
01201         memcpy(buf, digits, rve - digits);
01202         xfree(digits);
01203         rve = buf + (rve - digits);
01204         digits = buf;
01205         if (flags & ALT) {      /* Print trailing zeros */
01206                 bp = digits + ndigits;
01207                 if (ch == 'f') {
01208                         if (*digits == '0' && value)
01209                                 *decpt = -ndigits + 1;
01210                         bp += *decpt;
01211                 }
01212                 while (rve < bp)
01213                         *rve++ = '0';
01214         }
01215         *length = (int)(rve - digits);
01216         return (digits);
01217 }
01218 
01219 static int
01220 exponent(p0, exp, fmtch)
01221         char *p0;
01222         int exp, fmtch;
01223 {
01224         register char *p, *t;
01225         char expbuf[MAXEXP];
01226 
01227         p = p0;
01228         *p++ = fmtch;
01229         if (exp < 0) {
01230                 exp = -exp;
01231                 *p++ = '-';
01232         }
01233         else
01234                 *p++ = '+';
01235         t = expbuf + MAXEXP;
01236         if (exp > 9) {
01237                 do {
01238                         *--t = to_char(exp % 10);
01239                 } while ((exp /= 10) > 9);
01240                 *--t = to_char(exp);
01241                 for (; t < expbuf + MAXEXP; *p++ = *t++);
01242         }
01243         else {
01244                 if (fmtch & 15) *p++ = '0'; /* other than p or P */
01245                 *p++ = to_char(exp);
01246         }
01247         return (int)(p - p0);
01248 }
01249 #endif /* FLOATING_POINT */
01250 
01251 int
01252 ruby_vsnprintf(char *str, size_t n, const char *fmt, va_list ap)
01253 {
01254         int ret;
01255         FILE f;
01256 
01257         if ((int)n < 1)
01258                 return (EOF);
01259         f._flags = __SWR | __SSTR;
01260         f._bf._base = f._p = (unsigned char *)str;
01261         f._bf._size = f._w = n - 1;
01262         f.vwrite = BSD__sfvwrite;
01263         ret = (int)BSD_vfprintf(&f, fmt, ap);
01264         *f._p = 0;
01265         return (ret);
01266 }
01267 
01268 int
01269 ruby_snprintf(char *str, size_t n, char const *fmt, ...)
01270 {
01271         int ret;
01272         va_list ap;
01273         FILE f;
01274 
01275         if ((int)n < 1)
01276                 return (EOF);
01277 
01278         va_start(ap, fmt);
01279         f._flags = __SWR | __SSTR;
01280         f._bf._base = f._p = (unsigned char *)str;
01281         f._bf._size = f._w = n - 1;
01282         f.vwrite = BSD__sfvwrite;
01283         ret = (int)BSD_vfprintf(&f, fmt, ap);
01284         *f._p = 0;
01285         va_end(ap);
01286         return (ret);
01287 }
01288