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