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