• 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 quad_t 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         buf[0] = 0; /* rve - digits may be 0 */
01169         memcpy(buf, digits, rve - digits);
01170         xfree(digits);
01171         rve = buf + (rve - digits);
01172         digits = buf;
01173         if (flags & ALT) {      /* Print trailing zeros */
01174                 bp = digits + ndigits;
01175                 if (ch == 'f') {
01176                         if (*digits == '0' && value)
01177                                 *decpt = -ndigits + 1;
01178                         bp += *decpt;
01179                 }
01180                 if (value == 0) /* kludge for __dtoa irregularity */
01181                         rve = bp;
01182                 while (rve < bp)
01183                         *rve++ = '0';
01184         }
01185         *length = (int)(rve - digits);
01186         return (digits);
01187 }
01188 
01189 static int
01190 exponent(p0, exp, fmtch)
01191         char *p0;
01192         int exp, fmtch;
01193 {
01194         register char *p, *t;
01195         char expbuf[MAXEXP];
01196 
01197         p = p0;
01198         *p++ = fmtch;
01199         if (exp < 0) {
01200                 exp = -exp;
01201                 *p++ = '-';
01202         }
01203         else
01204                 *p++ = '+';
01205         t = expbuf + MAXEXP;
01206         if (exp > 9) {
01207                 do {
01208                         *--t = to_char(exp % 10);
01209                 } while ((exp /= 10) > 9);
01210                 *--t = to_char(exp);
01211                 for (; t < expbuf + MAXEXP; *p++ = *t++);
01212         }
01213         else {
01214                 if (fmtch & 15) *p++ = '0'; /* other than p or P */
01215                 *p++ = to_char(exp);
01216         }
01217         return (int)(p - p0);
01218 }
01219 #endif /* FLOATING_POINT */
01220 
01221 int
01222 ruby_vsnprintf(char *str, size_t n, const char *fmt, va_list ap)
01223 {
01224         int ret;
01225         FILE f;
01226 
01227         if ((int)n < 1)
01228                 return (EOF);
01229         f._flags = __SWR | __SSTR;
01230         f._bf._base = f._p = (unsigned char *)str;
01231         f._bf._size = f._w = n - 1;
01232         f.vwrite = BSD__sfvwrite;
01233         ret = (int)BSD_vfprintf(&f, fmt, ap);
01234         *f._p = 0;
01235         return (ret);
01236 }
01237 
01238 int
01239 ruby_snprintf(char *str, size_t n, char const *fmt, ...)
01240 {
01241         int ret;
01242         va_list ap;
01243         FILE f;
01244 
01245         if ((int)n < 1)
01246                 return (EOF);
01247 
01248         va_start(ap, fmt);
01249         f._flags = __SWR | __SSTR;
01250         f._bf._base = f._p = (unsigned char *)str;
01251         f._bf._size = f._w = n - 1;
01252         f.vwrite = BSD__sfvwrite;
01253         ret = (int)BSD_vfprintf(&f, fmt, ap);
01254         *f._p = 0;
01255         va_end(ap);
01256         return (ret);
01257 }
01258 

Generated on Sat Jul 7 2012 15:29:25 for Ruby by  doxygen 1.7.1