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