|
Ruby 1.9.2p290(2011-07-09revision32553)
|
00001 /*- 00002 * Copyright (c) 1990, 1993 00003 * The Regents of the University of California. All rights reserved. 00004 * 00005 * This code is derived from software contributed to Berkeley by 00006 * Chris Torek. 00007 * 00008 * Redistribution and use in source and binary forms, with or without 00009 * modification, are permitted provided that the following conditions 00010 * are met: 00011 * 1. Redistributions of source code must retain the above copyright 00012 * notice, this list of conditions and the following disclaimer. 00013 * 2. Redistributions in binary form must reproduce the above copyright 00014 * notice, this list of conditions and the following disclaimer in the 00015 * documentation and/or other materials provided with the distribution. 00016 * 3. Neither the name of the University nor the names of its contributors 00017 * may be used to endorse or promote products derived from this software 00018 * without specific prior written permission. 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 00021 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00022 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00023 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 00024 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00025 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00026 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00027 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00028 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00029 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00030 * SUCH DAMAGE. 00031 */ 00032 00033 /* 00034 * IMPORTANT NOTE: 00035 * -------------- 00036 * From ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change 00037 * paragraph 3 above is now null and void. 00038 */ 00039 00040 /* SNPRINTF.C 00041 * fjc 7-31-97 Modified by Mib Software to be a standalone snprintf.c module. 00042 * http://www.mibsoftware.com 00043 * Mib Software does not warrant this software any differently than the 00044 * University of California, Berkeley as described above. All warranties 00045 * are disclaimed. Use this software at your own risk. 00046 * 00047 * All code referencing FILE * functions was eliminated, since it could 00048 * never be called. All header files and necessary files are collapsed 00049 * into one file, internal functions are declared static. This should 00050 * allow inclusion into libraries with less chance of namespace collisions. 00051 * 00052 * snprintf should be the only externally visible item. 00053 * 00054 * As of 7-31-97 FLOATING_POINT is NOT provided. The code is somewhat 00055 * non-portable, so it is disabled. 00056 */ 00057 00058 /* Define FLOATING_POINT to get floating point. */ 00059 /* 00060 #define FLOATING_POINT 00061 */ 00062 00063 #include <sys/types.h> 00064 #define u_long unsigned long 00065 #define u_short unsigned short 00066 #define u_int unsigned int 00067 00068 #if !defined(HAVE_STDARG_PROTOTYPES) 00069 #if defined(__STDC__) 00070 #define HAVE_STDARG_PROTOTYPES 1 00071 #endif 00072 #endif 00073 00074 #undef __P 00075 #if defined(HAVE_STDARG_PROTOTYPES) 00076 # include <stdarg.h> 00077 # if !defined(__P) 00078 # define __P(x) x 00079 # endif 00080 #else 00081 # define __P(x) () 00082 # if !defined(const) 00083 # define const 00084 # endif 00085 # include <varargs.h> 00086 #endif 00087 #ifndef _BSD_VA_LIST_ 00088 #define _BSD_VA_LIST_ va_list 00089 #endif 00090 00091 #ifdef __STDC__ 00092 # include <limits.h> 00093 #else 00094 # ifndef LONG_MAX 00095 # ifdef HAVE_LIMITS_H 00096 # include <limits.h> 00097 # else 00098 /* assuming 32bit(2's compliment) long */ 00099 # define LONG_MAX 2147483647 00100 # endif 00101 # endif 00102 #endif 00103 00104 #if defined(__hpux) && !defined(__GNUC__) && !defined(__STDC__) 00105 #define const 00106 #endif 00107 00108 #if defined(sgi) 00109 #undef __const 00110 #define __const 00111 #endif /* People who don't like const sys_error */ 00112 00113 #include <stddef.h> 00114 #if defined(__hpux) && !defined(__GNUC__) || defined(__DECC) 00115 #include <string.h> 00116 #endif 00117 00118 #if !defined(__CYGWIN32__) && defined(__hpux) && !defined(__GNUC__) 00119 #include <stdlib.h> 00120 #endif 00121 00122 #ifndef NULL 00123 #define NULL 0 00124 #endif 00125 00126 #if SIZEOF_LONG > SIZEOF_INT 00127 # include <errno.h> 00128 #endif 00129 00130 /* 00131 * NB: to fit things in six character monocase externals, the stdio 00132 * code uses the prefix `__s' for stdio objects, typically followed 00133 * by a three-character attempt at a mnemonic. 00134 */ 00135 00136 /* stdio buffers */ 00137 struct __sbuf { 00138 unsigned char *_base; 00139 size_t _size; 00140 }; 00141 00142 00143 /* 00144 * stdio state variables. 00145 * 00146 * The following always hold: 00147 * 00148 * if (_flags&(__SLBF|__SWR)) == (__SLBF|__SWR), 00149 * _lbfsize is -_bf._size, else _lbfsize is 0 00150 * if _flags&__SRD, _w is 0 00151 * if _flags&__SWR, _r is 0 00152 * 00153 * This ensures that the getc and putc macros (or inline functions) never 00154 * try to write or read from a file that is in `read' or `write' mode. 00155 * (Moreover, they can, and do, automatically switch from read mode to 00156 * write mode, and back, on "r+" and "w+" files.) 00157 * 00158 * _lbfsize is used only to make the inline line-buffered output stream 00159 * code as compact as possible. 00160 * 00161 * _ub, _up, and _ur are used when ungetc() pushes back more characters 00162 * than fit in the current _bf, or when ungetc() pushes back a character 00163 * that does not match the previous one in _bf. When this happens, 00164 * _ub._base becomes non-nil (i.e., a stream has ungetc() data iff 00165 * _ub._base!=NULL) and _up and _ur save the current values of _p and _r. 00166 * 00167 * NB: see WARNING above before changing the layout of this structure! 00168 */ 00169 typedef struct __sFILE { 00170 unsigned char *_p; /* current position in (some) buffer */ 00171 #if 0 00172 size_t _r; /* read space left for getc() */ 00173 #endif 00174 size_t _w; /* write space left for putc() */ 00175 short _flags; /* flags, below; this FILE is free if 0 */ 00176 short _file; /* fileno, if Unix descriptor, else -1 */ 00177 struct __sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */ 00178 size_t _lbfsize; /* 0 or -_bf._size, for inline putc */ 00179 int (*vwrite)(/* struct __sFILE*, struct __suio * */); 00180 } FILE; 00181 00182 00183 #define __SLBF 0x0001 /* line buffered */ 00184 #define __SNBF 0x0002 /* unbuffered */ 00185 #define __SRD 0x0004 /* OK to read */ 00186 #define __SWR 0x0008 /* OK to write */ 00187 /* RD and WR are never simultaneously asserted */ 00188 #define __SRW 0x0010 /* open for reading & writing */ 00189 #define __SEOF 0x0020 /* found EOF */ 00190 #define __SERR 0x0040 /* found error */ 00191 #define __SMBF 0x0080 /* _buf is from malloc */ 00192 #define __SAPP 0x0100 /* fdopen()ed in append mode */ 00193 #define __SSTR 0x0200 /* this is an sprintf/snprintf string */ 00194 #define __SOPT 0x0400 /* do fseek() optimisation */ 00195 #define __SNPT 0x0800 /* do not do fseek() optimisation */ 00196 #define __SOFF 0x1000 /* set iff _offset is in fact correct */ 00197 #define __SMOD 0x2000 /* true => fgetln modified _p text */ 00198 00199 00200 #define EOF (-1) 00201 00202 00203 #define __sfeof(p) (((p)->_flags & __SEOF) != 0) 00204 #define __sferror(p) (((p)->_flags & __SERR) != 0) 00205 #define __sclearerr(p) ((void)((p)->_flags &= ~(__SERR|__SEOF))) 00206 #define __sfileno(p) ((p)->_file) 00207 00208 #undef feof 00209 #undef ferror 00210 #undef clearerr 00211 #define feof(p) __sfeof(p) 00212 #define ferror(p) __sferror(p) 00213 #define clearerr(p) __sclearerr(p) 00214 00215 #ifndef _ANSI_SOURCE 00216 #define fileno(p) __sfileno(p) 00217 #endif 00218 00219 00220 /* 00221 * I/O descriptors for __sfvwrite(). 00222 */ 00223 struct __siov { 00224 const void *iov_base; 00225 size_t iov_len; 00226 }; 00227 struct __suio { 00228 struct __siov *uio_iov; 00229 int uio_iovcnt; 00230 size_t uio_resid; 00231 }; 00232 00233 /* 00234 * Write some memory regions. Return zero on success, EOF on error. 00235 * 00236 * This routine is large and unsightly, but most of the ugliness due 00237 * to the three different kinds of output buffering is handled here. 00238 */ 00239 static int BSD__sfvwrite(fp, uio) 00240 register FILE *fp; 00241 register struct __suio *uio; 00242 { 00243 register size_t len; 00244 register const char *p; 00245 register struct __siov *iov; 00246 register size_t w; 00247 00248 if ((len = uio->uio_resid) == 0) 00249 return (0); 00250 #ifndef __hpux 00251 #define MIN(a, b) ((a) < (b) ? (a) : (b)) 00252 #endif 00253 #define COPY(n) (void)memcpy((void *)fp->_p, (void *)p, (size_t)(n)) 00254 00255 iov = uio->uio_iov; 00256 p = iov->iov_base; 00257 len = iov->iov_len; 00258 iov++; 00259 #define GETIOV(extra_work) \ 00260 while (len == 0) { \ 00261 extra_work; \ 00262 p = iov->iov_base; \ 00263 len = iov->iov_len; \ 00264 iov++; \ 00265 } 00266 if (fp->_flags & __SNBF) { 00267 /* fjc 7-31-97 Will never happen. We are working with 00268 strings only 00269 */ 00270 } else if ((fp->_flags & __SLBF) == 0) { 00271 /* 00272 * Fully buffered: fill partially full buffer, if any, 00273 * and then flush. If there is no partial buffer, write 00274 * one _bf._size byte chunk directly (without copying). 00275 * 00276 * String output is a special case: write as many bytes 00277 * as fit, but pretend we wrote everything. This makes 00278 * snprintf() return the number of bytes needed, rather 00279 * than the number used, and avoids its write function 00280 * (so that the write function can be invalid). 00281 */ 00282 do { 00283 GETIOV(;); 00284 w = fp->_w; 00285 if (fp->_flags & __SSTR) { 00286 if (len < w) 00287 w = len; 00288 COPY(w); /* copy MIN(fp->_w,len), */ 00289 fp->_w -= w; 00290 fp->_p += w; 00291 w = len; /* but pretend copied all */ 00292 } else { 00293 /* fjc 7-31-97 Will never happen. We are working with 00294 strings only 00295 */ 00296 } 00297 p += w; 00298 len -= w; 00299 } while ((uio->uio_resid -= w) != 0); 00300 } else { 00301 /* fjc 7-31-97 Will never happen. We are working with 00302 strings only 00303 */ 00304 } 00305 return (0); 00306 } 00307 00308 /* 00309 * Actual printf innards. 00310 * 00311 * This code is large and complicated... 00312 */ 00313 00314 /* 00315 * Flush out all the vectors defined by the given uio, 00316 * then reset it so that it can be reused. 00317 */ 00318 static int 00319 BSD__sprint(FILE *fp, register struct __suio *uio) 00320 { 00321 register int err; 00322 00323 if (uio->uio_resid == 0) { 00324 uio->uio_iovcnt = 0; 00325 return (0); 00326 } 00327 err = (*fp->vwrite)(fp, uio); 00328 uio->uio_resid = 0; 00329 uio->uio_iovcnt = 0; 00330 return (err); 00331 } 00332 00333 00334 /* 00335 * Helper function for `fprintf to unbuffered unix file': creates a 00336 * temporary buffer. We only work on write-only files; this avoids 00337 * worries about ungetc buffers and so forth. 00338 */ 00339 static int 00340 BSD__sbprintf(register FILE *fp, const char *fmt, va_list ap) 00341 { 00342 /* We don't support files. */ 00343 return 0; 00344 } 00345 00346 00347 /* 00348 * Macros for converting digits to letters and vice versa 00349 */ 00350 #define to_digit(c) ((c) - '0') 00351 #define is_digit(c) ((unsigned)to_digit(c) <= 9) 00352 #define to_char(n) (char)((n) + '0') 00353 00354 #ifdef _HAVE_SANE_QUAD_ 00355 /* 00356 * Convert an unsigned long long to ASCII for printf purposes, returning 00357 * a pointer to the first character of the string representation. 00358 * Octal numbers can be forced to have a leading zero; hex numbers 00359 * use the given digits. 00360 */ 00361 static char * 00362 BSD__uqtoa(register u_quad_t val, char *endp, int base, int octzero, const char *xdigs) 00363 { 00364 register char *cp = endp; 00365 register quad_t sval; 00366 00367 /* 00368 * Handle the three cases separately, in the hope of getting 00369 * better/faster code. 00370 */ 00371 switch (base) { 00372 case 10: 00373 if (val < 10) { /* many numbers are 1 digit */ 00374 *--cp = to_char(val); 00375 return (cp); 00376 } 00377 /* 00378 * On many machines, unsigned arithmetic is harder than 00379 * signed arithmetic, so we do at most one unsigned mod and 00380 * divide; this is sufficient to reduce the range of 00381 * the incoming value to where signed arithmetic works. 00382 */ 00383 if (val > LLONG_MAX) { 00384 *--cp = to_char(val % 10); 00385 sval = val / 10; 00386 } else 00387 sval = val; 00388 do { 00389 *--cp = to_char(sval % 10); 00390 sval /= 10; 00391 } while (sval != 0); 00392 break; 00393 00394 case 8: 00395 do { 00396 *--cp = to_char(val & 7); 00397 val >>= 3; 00398 } while (val); 00399 if (octzero && *cp != '0') 00400 *--cp = '0'; 00401 break; 00402 00403 case 16: 00404 do { 00405 *--cp = xdigs[val & 15]; 00406 val >>= 4; 00407 } while (val); 00408 break; 00409 00410 default: /* oops */ 00411 /* 00412 abort(); 00413 */ 00414 break; /* fjc 7-31-97. Don't reference abort() here */ 00415 } 00416 return (cp); 00417 } 00418 #endif /* _HAVE_SANE_QUAD_ */ 00419 00420 /* 00421 * Convert an unsigned long to ASCII for printf purposes, returning 00422 * a pointer to the first character of the string representation. 00423 * Octal numbers can be forced to have a leading zero; hex numbers 00424 * use the given digits. 00425 */ 00426 static char * 00427 BSD__ultoa(register u_long val, char *endp, int base, int octzero, const char *xdigs) 00428 { 00429 register char *cp = endp; 00430 register long sval; 00431 00432 /* 00433 * Handle the three cases separately, in the hope of getting 00434 * better/faster code. 00435 */ 00436 switch (base) { 00437 case 10: 00438 if (val < 10) { /* many numbers are 1 digit */ 00439 *--cp = to_char(val); 00440 return (cp); 00441 } 00442 /* 00443 * On many machines, unsigned arithmetic is harder than 00444 * signed arithmetic, so we do at most one unsigned mod and 00445 * divide; this is sufficient to reduce the range of 00446 * the incoming value to where signed arithmetic works. 00447 */ 00448 if (val > LONG_MAX) { 00449 *--cp = to_char(val % 10); 00450 sval = val / 10; 00451 } else 00452 sval = val; 00453 do { 00454 *--cp = to_char(sval % 10); 00455 sval /= 10; 00456 } while (sval != 0); 00457 break; 00458 00459 case 8: 00460 do { 00461 *--cp = to_char(val & 7); 00462 val >>= 3; 00463 } while (val); 00464 if (octzero && *cp != '0') 00465 *--cp = '0'; 00466 break; 00467 00468 case 16: 00469 do { 00470 *--cp = xdigs[val & 15]; 00471 val >>= 4; 00472 } while (val); 00473 break; 00474 00475 default: /* oops */ 00476 /* 00477 abort(); 00478 */ 00479 break; /* fjc 7-31-97. Don't reference abort() here */ 00480 } 00481 return (cp); 00482 } 00483 00484 #ifdef FLOATING_POINT 00485 #include <math.h> 00486 /* #include "floatio.h" */ 00487 00488 #ifndef MAXEXP 00489 # define MAXEXP 1024 00490 #endif 00491 00492 #ifndef MAXFRACT 00493 # define MAXFRACT 64 00494 #endif 00495 00496 #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ 00497 #define DEFPREC 6 00498 00499 static char *cvt __P((double, int, int, char *, int *, int, int *, char *)); 00500 static int exponent __P((char *, int, int)); 00501 00502 #else /* no FLOATING_POINT */ 00503 00504 #define BUF 68 00505 00506 #endif /* FLOATING_POINT */ 00507 00508 00509 /* 00510 * Flags used during conversion. 00511 */ 00512 #define ALT 0x001 /* alternate form */ 00513 #define HEXPREFIX 0x002 /* add 0x or 0X prefix */ 00514 #define LADJUST 0x004 /* left adjustment */ 00515 #define LONGDBL 0x008 /* long double; unimplemented */ 00516 #define LONGINT 0x010 /* long integer */ 00517 00518 #ifdef _HAVE_SANE_QUAD_ 00519 #define QUADINT 0x020 /* quad integer */ 00520 #endif /* _HAVE_SANE_QUAD_ */ 00521 00522 #define SHORTINT 0x040 /* short integer */ 00523 #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ 00524 #define FPT 0x100 /* Floating point number */ 00525 static ssize_t 00526 BSD_vfprintf(FILE *fp, const char *fmt0, va_list ap) 00527 { 00528 register const char *fmt; /* format string */ 00529 register int ch; /* character from fmt */ 00530 register int n; /* handy integer (short term usage) */ 00531 register const char *cp;/* handy char pointer (short term usage) */ 00532 register struct __siov *iovp;/* for PRINT macro */ 00533 register int flags; /* flags as above */ 00534 ssize_t ret; /* return value accumulator */ 00535 int width; /* width from format (%8d), or 0 */ 00536 int prec; /* precision from format (%.3d), or -1 */ 00537 char sign; /* sign prefix (' ', '+', '-', or \0) */ 00538 #ifdef FLOATING_POINT 00539 char softsign; /* temporary negative sign for floats */ 00540 double _double = 0; /* double precision arguments %[eEfgG] */ 00541 int expt; /* integer value of exponent */ 00542 int expsize = 0; /* character count for expstr */ 00543 int ndig = 0; /* actual number of digits returned by cvt */ 00544 char expstr[7]; /* buffer for exponent string */ 00545 #endif 00546 u_long ulval; /* integer arguments %[diouxX] */ 00547 #ifdef _HAVE_SANE_QUAD_ 00548 u_quad_t uqval; /* %q integers */ 00549 #endif /* _HAVE_SANE_QUAD_ */ 00550 int base; /* base for [diouxX] conversion */ 00551 int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 00552 long fieldsz; /* field size expanded by sign, etc */ 00553 long realsz; /* field size expanded by dprec */ 00554 int size; /* size of converted field or string */ 00555 const char *xdigs = 0; /* digits for [xX] conversion */ 00556 #define NIOV 8 00557 struct __suio uio; /* output information: summary */ 00558 struct __siov iov[NIOV];/* ... and individual io vectors */ 00559 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ 00560 char ox[4]; /* space for 0x hex-prefix, hexadecimal's 1. */ 00561 char *const ebuf = buf + sizeof(buf); 00562 #if SIZEOF_LONG > SIZEOF_INT 00563 long ln; 00564 #endif 00565 00566 /* 00567 * Choose PADSIZE to trade efficiency vs. size. If larger printf 00568 * fields occur frequently, increase PADSIZE and make the initializers 00569 * below longer. 00570 */ 00571 #define PADSIZE 16 /* pad chunk size */ 00572 static const char blanks[PADSIZE] = 00573 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 00574 static const char zeroes[PADSIZE] = 00575 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 00576 00577 /* 00578 * BEWARE, these `goto error' on error, and PAD uses `n'. 00579 */ 00580 #define PRINT(ptr, len) { \ 00581 iovp->iov_base = (ptr); \ 00582 iovp->iov_len = (len); \ 00583 uio.uio_resid += (len); \ 00584 iovp++; \ 00585 if (++uio.uio_iovcnt >= NIOV) { \ 00586 if (BSD__sprint(fp, &uio)) \ 00587 goto error; \ 00588 iovp = iov; \ 00589 } \ 00590 } 00591 #define PAD(howmany, with) { \ 00592 if ((n = (howmany)) > 0) { \ 00593 while (n > PADSIZE) { \ 00594 PRINT(with, PADSIZE); \ 00595 n -= PADSIZE; \ 00596 } \ 00597 PRINT(with, n); \ 00598 } \ 00599 } 00600 #if SIZEOF_LONG > SIZEOF_INT 00601 /* abandon if too larger padding */ 00602 #define PAD_L(howmany, with) { \ 00603 ln = (howmany); \ 00604 if ((long)((int)ln) != ln) { \ 00605 errno = ENOMEM; \ 00606 goto error; \ 00607 } \ 00608 if (ln > 0) PAD((int)ln, with); \ 00609 } 00610 #else 00611 #define PAD_L(howmany, with) PAD(howmany, with) 00612 #endif 00613 #define FLUSH() { \ 00614 if (uio.uio_resid && BSD__sprint(fp, &uio)) \ 00615 goto error; \ 00616 uio.uio_iovcnt = 0; \ 00617 iovp = iov; \ 00618 } 00619 00620 /* 00621 * To extend shorts properly, we need both signed and unsigned 00622 * argument extraction methods. 00623 */ 00624 #define SARG() \ 00625 (flags&LONGINT ? va_arg(ap, long) : \ 00626 flags&SHORTINT ? (long)(short)va_arg(ap, int) : \ 00627 (long)va_arg(ap, int)) 00628 #define UARG() \ 00629 (flags&LONGINT ? va_arg(ap, u_long) : \ 00630 flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \ 00631 (u_long)va_arg(ap, u_int)) 00632 00633 /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 00634 if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 00635 fp->_file >= 0) 00636 return (BSD__sbprintf(fp, fmt0, ap)); 00637 00638 fmt = fmt0; 00639 uio.uio_iov = iovp = iov; 00640 uio.uio_resid = 0; 00641 uio.uio_iovcnt = 0; 00642 ret = 0; 00643 xdigs = 0; 00644 00645 /* 00646 * Scan the format for conversions (`%' character). 00647 */ 00648 for (;;) { 00649 size_t nc; 00650 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 00651 /* void */; 00652 if ((nc = fmt - cp) != 0) { 00653 PRINT(cp, nc); 00654 ret += nc; 00655 } 00656 if (ch == '\0') 00657 goto done; 00658 fmt++; /* skip over '%' */ 00659 00660 flags = 0; 00661 dprec = 0; 00662 width = 0; 00663 prec = -1; 00664 sign = '\0'; 00665 00666 rflag: ch = *fmt++; 00667 reswitch: switch (ch) { 00668 case ' ': 00669 /* 00670 * ``If the space and + flags both appear, the space 00671 * flag will be ignored.'' 00672 * -- ANSI X3J11 00673 */ 00674 if (!sign) 00675 sign = ' '; 00676 goto rflag; 00677 case '#': 00678 flags |= ALT; 00679 goto rflag; 00680 case '*': 00681 /* 00682 * ``A negative field width argument is taken as a 00683 * - flag followed by a positive field width.'' 00684 * -- ANSI X3J11 00685 * They don't exclude field widths read from args. 00686 */ 00687 if ((width = va_arg(ap, int)) >= 0) 00688 goto rflag; 00689 width = -width; 00690 /* FALLTHROUGH */ 00691 case '-': 00692 flags |= LADJUST; 00693 goto rflag; 00694 case '+': 00695 sign = '+'; 00696 goto rflag; 00697 case '.': 00698 if ((ch = *fmt++) == '*') { 00699 n = va_arg(ap, int); 00700 prec = n < 0 ? -1 : n; 00701 goto rflag; 00702 } 00703 n = 0; 00704 while (is_digit(ch)) { 00705 n = 10 * n + to_digit(ch); 00706 ch = *fmt++; 00707 } 00708 prec = n < 0 ? -1 : n; 00709 goto reswitch; 00710 case '0': 00711 /* 00712 * ``Note that 0 is taken as a flag, not as the 00713 * beginning of a field width.'' 00714 * -- ANSI X3J11 00715 */ 00716 flags |= ZEROPAD; 00717 goto rflag; 00718 case '1': case '2': case '3': case '4': 00719 case '5': case '6': case '7': case '8': case '9': 00720 n = 0; 00721 do { 00722 n = 10 * n + to_digit(ch); 00723 ch = *fmt++; 00724 } while (is_digit(ch)); 00725 width = n; 00726 goto reswitch; 00727 #ifdef FLOATING_POINT 00728 case 'L': 00729 flags |= LONGDBL; 00730 goto rflag; 00731 #endif 00732 case 'h': 00733 flags |= SHORTINT; 00734 goto rflag; 00735 #if SIZEOF_PTRDIFF_T == SIZEOF_LONG 00736 case 't': 00737 #endif 00738 #if SIZEOF_SIZE_T == SIZEOF_LONG 00739 case 'z': 00740 #endif 00741 case 'l': 00742 flags |= LONGINT; 00743 goto rflag; 00744 #ifdef _HAVE_SANE_QUAD_ 00745 #if SIZEOF_PTRDIFF_T == SIZEOF_LONG_LONG 00746 case 't': 00747 #endif 00748 #if SIZEOF_SIZE_T == SIZEOF_LONG_LONG 00749 case 'z': 00750 #endif 00751 case 'q': 00752 flags |= QUADINT; 00753 goto rflag; 00754 #endif /* _HAVE_SANE_QUAD_ */ 00755 case 'c': 00756 cp = buf; 00757 *buf = (char)va_arg(ap, int); 00758 size = 1; 00759 sign = '\0'; 00760 break; 00761 case 'D': 00762 flags |= LONGINT; 00763 /*FALLTHROUGH*/ 00764 case 'd': 00765 case 'i': 00766 #ifdef _HAVE_SANE_QUAD_ 00767 if (flags & QUADINT) { 00768 uqval = va_arg(ap, quad_t); 00769 if ((quad_t)uqval < 0) { 00770 uqval = -(quad_t)uqval; 00771 sign = '-'; 00772 } 00773 } else 00774 #endif /* _HAVE_SANE_QUAD_ */ 00775 { 00776 ulval = SARG(); 00777 if ((long)ulval < 0) { 00778 ulval = (u_long)(-(long)ulval); 00779 sign = '-'; 00780 } 00781 } 00782 base = 10; 00783 goto number; 00784 #ifdef FLOATING_POINT 00785 case 'a': 00786 case 'A': 00787 if (prec >= 0) 00788 prec++; 00789 goto fp_begin; 00790 case 'e': /* anomalous precision */ 00791 case 'E': 00792 if (prec != 0) 00793 flags |= ALT; 00794 prec = (prec == -1) ? 00795 DEFPREC + 1 : prec + 1; 00796 /* FALLTHROUGH */ 00797 goto fp_begin; 00798 case 'f': /* always print trailing zeroes */ 00799 if (prec != 0) 00800 flags |= ALT; 00801 case 'g': 00802 case 'G': 00803 if (prec == -1) 00804 prec = DEFPREC; 00805 fp_begin: _double = va_arg(ap, double); 00806 /* do this before tricky precision changes */ 00807 if (isinf(_double)) { 00808 if (_double < 0) 00809 sign = '-'; 00810 cp = "Inf"; 00811 size = 3; 00812 break; 00813 } 00814 if (isnan(_double)) { 00815 cp = "NaN"; 00816 size = 3; 00817 break; 00818 } 00819 flags |= FPT; 00820 cp = cvt(_double, prec, flags, &softsign, 00821 &expt, ch, &ndig, buf); 00822 if (ch == 'g' || ch == 'G') { 00823 if (expt <= -4 || (expt > prec && expt > 1)) 00824 ch = (ch == 'g') ? 'e' : 'E'; 00825 else 00826 ch = 'g'; 00827 } 00828 if (ch == 'a' || ch == 'A') { 00829 --expt; 00830 expsize = exponent(expstr, expt, ch + 'p' - 'a'); 00831 size = expsize + ndig; 00832 } 00833 else if (ch <= 'e') { /* 'e' or 'E' fmt */ 00834 --expt; 00835 expsize = exponent(expstr, expt, ch); 00836 size = expsize + ndig; 00837 if (ndig > 1 || flags & ALT) 00838 ++size; 00839 } else if (ch == 'f') { /* f fmt */ 00840 if (expt > 0) { 00841 size = expt; 00842 if (prec || flags & ALT) 00843 size += prec + 1; 00844 } else if (!prec) { /* "0" */ 00845 size = 1; 00846 } else /* "0.X" */ 00847 size = prec + 2; 00848 } else if (expt >= ndig) { /* fixed g fmt */ 00849 size = expt; 00850 if (flags & ALT) 00851 ++size; 00852 } else 00853 size = ndig + (expt > 0 ? 00854 1 : 2 - expt); 00855 00856 if (softsign) 00857 sign = '-'; 00858 break; 00859 #endif /* FLOATING_POINT */ 00860 case 'n': 00861 #ifdef _HAVE_SANE_QUAD_ 00862 if (flags & QUADINT) 00863 *va_arg(ap, quad_t *) = ret; 00864 else if (flags & LONGINT) 00865 #else /* _HAVE_SANE_QUAD_ */ 00866 if (flags & LONGINT) 00867 #endif /* _HAVE_SANE_QUAD_ */ 00868 *va_arg(ap, long *) = ret; 00869 else if (flags & SHORTINT) 00870 *va_arg(ap, short *) = (short)ret; 00871 else 00872 *va_arg(ap, int *) = (int)ret; 00873 continue; /* no output */ 00874 case 'O': 00875 flags |= LONGINT; 00876 /*FALLTHROUGH*/ 00877 case 'o': 00878 #ifdef _HAVE_SANE_QUAD_ 00879 if (flags & QUADINT) 00880 uqval = va_arg(ap, u_quad_t); 00881 else 00882 #endif /* _HAVE_SANE_QUAD_ */ 00883 ulval = UARG(); 00884 base = 8; 00885 goto nosign; 00886 case 'p': 00887 /* 00888 * ``The argument shall be a pointer to void. The 00889 * value of the pointer is converted to a sequence 00890 * of printable characters, in an implementation- 00891 * defined manner.'' 00892 * -- ANSI X3J11 00893 */ 00894 prec = (int)(sizeof(void*)*CHAR_BIT/4); 00895 #ifdef _HAVE_LLP64_ 00896 uqval = (u_quad_t)va_arg(ap, void *); 00897 flags = (flags) | QUADINT | HEXPREFIX; 00898 #else 00899 ulval = (u_long)va_arg(ap, void *); 00900 #ifdef _HAVE_SANE_QUAD_ 00901 flags = (flags & ~QUADINT) | HEXPREFIX; 00902 #else /* _HAVE_SANE_QUAD_ */ 00903 flags = (flags) | HEXPREFIX; 00904 #endif /* _HAVE_SANE_QUAD_ */ 00905 #endif 00906 base = 16; 00907 xdigs = "0123456789abcdef"; 00908 ch = 'x'; 00909 goto nosign; 00910 case 's': 00911 if ((cp = va_arg(ap, char *)) == NULL) 00912 cp = "(null)"; 00913 if (prec >= 0) { 00914 /* 00915 * can't use strlen; can only look for the 00916 * NUL in the first `prec' characters, and 00917 * strlen() will go further. 00918 */ 00919 const char *p = (char *)memchr(cp, 0, prec); 00920 00921 if (p != NULL && (p - cp) > prec) 00922 size = (int)(p - cp); 00923 else 00924 size = prec; 00925 } 00926 else { 00927 fieldsz = strlen(cp); 00928 goto long_len; 00929 } 00930 sign = '\0'; 00931 break; 00932 case 'U': 00933 flags |= LONGINT; 00934 /*FALLTHROUGH*/ 00935 case 'u': 00936 #ifdef _HAVE_SANE_QUAD_ 00937 if (flags & QUADINT) 00938 uqval = va_arg(ap, u_quad_t); 00939 else 00940 #endif /* _HAVE_SANE_QUAD_ */ 00941 ulval = UARG(); 00942 base = 10; 00943 goto nosign; 00944 case 'X': 00945 xdigs = "0123456789ABCDEF"; 00946 goto hex; 00947 case 'x': 00948 xdigs = "0123456789abcdef"; 00949 hex: 00950 #ifdef _HAVE_SANE_QUAD_ 00951 if (flags & QUADINT) 00952 uqval = va_arg(ap, u_quad_t); 00953 else 00954 #endif /* _HAVE_SANE_QUAD_ */ 00955 ulval = UARG(); 00956 base = 16; 00957 /* leading 0x/X only if non-zero */ 00958 if (flags & ALT && 00959 #ifdef _HAVE_SANE_QUAD_ 00960 (flags & QUADINT ? uqval != 0 : ulval != 0) 00961 #else /* _HAVE_SANE_QUAD_ */ 00962 ulval != 0 00963 #endif /* _HAVE_SANE_QUAD_ */ 00964 ) 00965 flags |= HEXPREFIX; 00966 00967 /* unsigned conversions */ 00968 nosign: sign = '\0'; 00969 /* 00970 * ``... diouXx conversions ... if a precision is 00971 * specified, the 0 flag will be ignored.'' 00972 * -- ANSI X3J11 00973 */ 00974 number: if ((dprec = prec) >= 0) 00975 flags &= ~ZEROPAD; 00976 00977 /* 00978 * ``The result of converting a zero value with an 00979 * explicit precision of zero is no characters.'' 00980 * -- ANSI X3J11 00981 */ 00982 #ifdef _HAVE_SANE_QUAD_ 00983 if (flags & QUADINT) { 00984 if (uqval != 0 || prec != 0) 00985 cp = BSD__uqtoa(uqval, ebuf, base, 00986 flags & ALT, xdigs); 00987 } else 00988 #else /* _HAVE_SANE_QUAD_ */ 00989 #endif /* _HAVE_SANE_QUAD_ */ 00990 { 00991 if (ulval != 0 || prec != 0) 00992 cp = BSD__ultoa(ulval, ebuf, base, 00993 flags & ALT, xdigs); 00994 } 00995 size = (int)(ebuf - cp); 00996 break; 00997 default: /* "%?" prints ?, unless ? is NUL */ 00998 if (ch == '\0') 00999 goto done; 01000 /* pretend it was %c with argument ch */ 01001 cp = buf; 01002 *buf = ch; 01003 size = 1; 01004 sign = '\0'; 01005 break; 01006 } 01007 01008 /* 01009 * All reasonable formats wind up here. At this point, `cp' 01010 * points to a string which (if not flags&LADJUST) should be 01011 * padded out to `width' places. If flags&ZEROPAD, it should 01012 * first be prefixed by any sign or other prefix; otherwise, 01013 * it should be blank padded before the prefix is emitted. 01014 * After any left-hand padding and prefixing, emit zeroes 01015 * required by a decimal [diouxX] precision, then print the 01016 * string proper, then emit zeroes required by any leftover 01017 * floating precision; finally, if LADJUST, pad with blanks. 01018 * 01019 * Compute actual size, so we know how much to pad. 01020 * fieldsz excludes decimal prec; realsz includes it. 01021 */ 01022 fieldsz = size; 01023 long_len: 01024 if (sign) 01025 fieldsz++; 01026 else if (flags & HEXPREFIX) 01027 fieldsz += 2; 01028 realsz = dprec > fieldsz ? dprec : fieldsz; 01029 01030 /* right-adjusting blank padding */ 01031 if ((flags & (LADJUST|ZEROPAD)) == 0) 01032 PAD_L(width - realsz, blanks); 01033 01034 /* prefix */ 01035 if (sign) { 01036 PRINT(&sign, 1); 01037 } else if (flags & HEXPREFIX) { 01038 ox[0] = '0'; 01039 ox[1] = ch; 01040 PRINT(ox, 2); 01041 } 01042 01043 /* right-adjusting zero padding */ 01044 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 01045 PAD_L(width - realsz, zeroes); 01046 01047 /* leading zeroes from decimal precision */ 01048 PAD_L(dprec - fieldsz, zeroes); 01049 if (sign) 01050 fieldsz--; 01051 else if (flags & HEXPREFIX) 01052 fieldsz -= 2; 01053 01054 /* the string or number proper */ 01055 #ifdef FLOATING_POINT 01056 if ((flags & FPT) == 0) { 01057 PRINT(cp, fieldsz); 01058 } else { /* glue together f_p fragments */ 01059 if (ch == 'a' || ch == 'A') { 01060 ox[0] = '0'; 01061 ox[1] = ch + ('x' - 'a'); 01062 PRINT(ox, 2); 01063 if (ndig > 1 || flags & ALT) { 01064 ox[2] = *cp++; 01065 ox[3] = '.'; 01066 PRINT(ox+2, 2); 01067 PRINT(cp, ndig-1); 01068 } else /* XpYYY */ 01069 PRINT(cp, 1); 01070 PRINT(expstr, expsize); 01071 } 01072 else if (ch >= 'f') { /* 'f' or 'g' */ 01073 if (_double == 0) { 01074 /* kludge for __dtoa irregularity */ 01075 if (ndig <= 1 && 01076 (flags & ALT) == 0) { 01077 PRINT("0", 1); 01078 } else { 01079 PRINT("0.", 2); 01080 PAD(ndig - 1, zeroes); 01081 } 01082 } else if (expt == 0 && ndig == 0 && (flags & ALT) == 0) { 01083 PRINT("0", 1); 01084 } else if (expt <= 0) { 01085 PRINT("0.", 2); 01086 PAD(-expt, zeroes); 01087 PRINT(cp, ndig); 01088 } else if (expt >= ndig) { 01089 PRINT(cp, ndig); 01090 PAD(expt - ndig, zeroes); 01091 if (flags & ALT) 01092 PRINT(".", 1); 01093 } else { 01094 PRINT(cp, expt); 01095 cp += expt; 01096 PRINT(".", 1); 01097 PRINT(cp, ndig-expt); 01098 } 01099 } else { /* 'e' or 'E' */ 01100 if (ndig > 1 || flags & ALT) { 01101 ox[0] = *cp++; 01102 ox[1] = '.'; 01103 PRINT(ox, 2); 01104 if (_double /*|| flags & ALT == 0*/) { 01105 PRINT(cp, ndig-1); 01106 } else /* 0.[0..] */ 01107 /* __dtoa irregularity */ 01108 PAD(ndig - 1, zeroes); 01109 } else /* XeYYY */ 01110 PRINT(cp, 1); 01111 PRINT(expstr, expsize); 01112 } 01113 } 01114 #else 01115 PRINT(cp, fieldsz); 01116 #endif 01117 /* left-adjusting padding (always blank) */ 01118 if (flags & LADJUST) 01119 PAD_L(width - realsz, blanks); 01120 01121 /* finally, adjust ret */ 01122 ret += width > realsz ? width : realsz; 01123 01124 FLUSH(); /* copy out the I/O vectors */ 01125 } 01126 done: 01127 FLUSH(); 01128 error: 01129 return (__sferror(fp) ? EOF : ret); 01130 /* NOTREACHED */ 01131 } 01132 01133 #ifdef FLOATING_POINT 01134 01135 extern char *BSD__dtoa __P((double, int, int, int *, int *, char **)); 01136 extern char *BSD__hdtoa(double, const char *, int, int *, int *, char **); 01137 01138 static char * 01139 cvt(value, ndigits, flags, sign, decpt, ch, length, buf) 01140 double value; 01141 int ndigits, flags, *decpt, ch, *length; 01142 char *sign, *buf; 01143 { 01144 int mode, dsgn; 01145 char *digits, *bp, *rve; 01146 01147 if (ch == 'f') 01148 mode = 3; 01149 else { 01150 mode = 2; 01151 } 01152 if (value < 0) { 01153 value = -value; 01154 *sign = '-'; 01155 } else if (value == 0.0 && 1.0/value < 0) { 01156 *sign = '-'; 01157 } else { 01158 *sign = '\000'; 01159 } 01160 if (ch == 'a' || ch =='A') { 01161 digits = BSD__hdtoa(value, 01162 ch == 'a' ? "0123456789abcdef" : "0123456789ABCDEF", 01163 ndigits, decpt, &dsgn, &rve); 01164 } 01165 else { 01166 digits = BSD__dtoa(value, mode, ndigits, decpt, &dsgn, &rve); 01167 } 01168 buf[0] = 0; /* rve - digits may be 0 */ 01169 memcpy(buf, digits, rve - digits); 01170 xfree(digits); 01171 rve = buf + (rve - digits); 01172 digits = buf; 01173 if (flags & ALT) { /* Print trailing zeros */ 01174 bp = digits + ndigits; 01175 if (ch == 'f') { 01176 if (*digits == '0' && value) 01177 *decpt = -ndigits + 1; 01178 bp += *decpt; 01179 } 01180 if (value == 0) /* kludge for __dtoa irregularity */ 01181 rve = bp; 01182 while (rve < bp) 01183 *rve++ = '0'; 01184 } 01185 *length = (int)(rve - digits); 01186 return (digits); 01187 } 01188 01189 static int 01190 exponent(p0, exp, fmtch) 01191 char *p0; 01192 int exp, fmtch; 01193 { 01194 register char *p, *t; 01195 char expbuf[MAXEXP]; 01196 01197 p = p0; 01198 *p++ = fmtch; 01199 if (exp < 0) { 01200 exp = -exp; 01201 *p++ = '-'; 01202 } 01203 else 01204 *p++ = '+'; 01205 t = expbuf + MAXEXP; 01206 if (exp > 9) { 01207 do { 01208 *--t = to_char(exp % 10); 01209 } while ((exp /= 10) > 9); 01210 *--t = to_char(exp); 01211 for (; t < expbuf + MAXEXP; *p++ = *t++); 01212 } 01213 else { 01214 if (fmtch & 15) *p++ = '0'; /* other than p or P */ 01215 *p++ = to_char(exp); 01216 } 01217 return (int)(p - p0); 01218 } 01219 #endif /* FLOATING_POINT */ 01220 01221 int 01222 ruby_vsnprintf(char *str, size_t n, const char *fmt, va_list ap) 01223 { 01224 int ret; 01225 FILE f; 01226 01227 if ((int)n < 1) 01228 return (EOF); 01229 f._flags = __SWR | __SSTR; 01230 f._bf._base = f._p = (unsigned char *)str; 01231 f._bf._size = f._w = n - 1; 01232 f.vwrite = BSD__sfvwrite; 01233 ret = (int)BSD_vfprintf(&f, fmt, ap); 01234 *f._p = 0; 01235 return (ret); 01236 } 01237 01238 int 01239 ruby_snprintf(char *str, size_t n, char const *fmt, ...) 01240 { 01241 int ret; 01242 va_list ap; 01243 FILE f; 01244 01245 if ((int)n < 1) 01246 return (EOF); 01247 01248 va_start(ap, fmt); 01249 f._flags = __SWR | __SSTR; 01250 f._bf._base = f._p = (unsigned char *)str; 01251 f._bf._size = f._w = n - 1; 01252 f.vwrite = BSD__sfvwrite; 01253 ret = (int)BSD_vfprintf(&f, fmt, ap); 01254 *f._p = 0; 01255 va_end(ap); 01256 return (ret); 01257 } 01258
1.7.3