Ruby 1.9.3p327(2012-11-10revision37606)
|
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