Contiki 2.6
|
00001 /* 00002 FUNCTION 00003 <<vprintf>>, <<vfprintf>>, <<vsprintf>>---format argument list 00004 00005 INDEX 00006 vprintf 00007 INDEX 00008 vfprintf 00009 INDEX 00010 vsprintf 00011 INDEX 00012 vsnprintf 00013 00014 ANSI_SYNOPSIS 00015 #include <stdio.h> 00016 #include <stdarg.h> 00017 int vprintf(const char *<[fmt]>, va_list <[list]>); 00018 int vfprintf(FILE *<[fp]>, const char *<[fmt]>, va_list <[list]>); 00019 int vsprintf(char *<[str]>, const char *<[fmt]>, va_list <[list]>); 00020 int vasprintf(char **<[strp]>, const char *<[fmt]>, va_list <[list]>); 00021 int vsnprintf(char *<[str]>, size_t <[size]>, const char *<[fmt]>, va_list <[list]>); 00022 00023 int _vprintf_r(void *<[reent]>, const char *<[fmt]>, 00024 va_list <[list]>); 00025 int _vfprintf_r(void *<[reent]>, FILE *<[fp]>, const char *<[fmt]>, 00026 va_list <[list]>); 00027 int _vasprintf_r(void *<[reent]>, char **<[str]>, const char *<[fmt]>, 00028 va_list <[list]>); 00029 int _vsprintf_r(void *<[reent]>, char *<[str]>, const char *<[fmt]>, 00030 va_list <[list]>); 00031 int _vsnprintf_r(void *<[reent]>, char *<[str]>, size_t <[size]>, const char *<[fmt]>, 00032 va_list <[list]>); 00033 00034 TRAD_SYNOPSIS 00035 #include <stdio.h> 00036 #include <varargs.h> 00037 int vprintf( <[fmt]>, <[list]>) 00038 char *<[fmt]>; 00039 va_list <[list]>; 00040 00041 int vfprintf(<[fp]>, <[fmt]>, <[list]>) 00042 FILE *<[fp]>; 00043 char *<[fmt]>; 00044 va_list <[list]>; 00045 00046 int vasprintf(<[strp]>, <[fmt]>, <[list]>) 00047 char **<[strp]>; 00048 char *<[fmt]>; 00049 va_list <[list]>; 00050 00051 int vsprintf(<[str]>, <[fmt]>, <[list]>) 00052 char *<[str]>; 00053 char *<[fmt]>; 00054 va_list <[list]>; 00055 00056 int vsnprintf(<[str]>, <[size]>, <[fmt]>, <[list]>) 00057 char *<[str]>; 00058 size_t <[size]>; 00059 char *<[fmt]>; 00060 va_list <[list]>; 00061 00062 int _vprintf_r(<[reent]>, <[fmt]>, <[list]>) 00063 char *<[reent]>; 00064 char *<[fmt]>; 00065 va_list <[list]>; 00066 00067 int _vfprintf_r(<[reent]>, <[fp]>, <[fmt]>, <[list]>) 00068 char *<[reent]>; 00069 FILE *<[fp]>; 00070 char *<[fmt]>; 00071 va_list <[list]>; 00072 00073 int _vasprintf_r(<[reent]>, <[strp]>, <[fmt]>, <[list]>) 00074 char *<[reent]>; 00075 char **<[strp]>; 00076 char *<[fmt]>; 00077 va_list <[list]>; 00078 00079 int _vsprintf_r(<[reent]>, <[str]>, <[fmt]>, <[list]>) 00080 char *<[reent]>; 00081 char *<[str]>; 00082 char *<[fmt]>; 00083 va_list <[list]>; 00084 00085 int _vsnprintf_r(<[reent]>, <[str]>, <[size]>, <[fmt]>, <[list]>) 00086 char *<[reent]>; 00087 char *<[str]>; 00088 size_t <[size]>; 00089 char *<[fmt]>; 00090 va_list <[list]>; 00091 00092 DESCRIPTION 00093 <<vprintf>>, <<vfprintf>>, <<vasprintf>>, <<vsprintf>> and <<vsnprintf>> are 00094 (respectively) variants of <<printf>>, <<fprintf>>, <<asprintf>>, <<sprintf>>, 00095 and <<snprintf>>. They differ only in allowing their caller to pass the 00096 variable argument list as a <<va_list>> object (initialized by <<va_start>>) 00097 rather than directly accepting a variable number of arguments. 00098 00099 RETURNS 00100 The return values are consistent with the corresponding functions: 00101 <<vasprintf>>/<<vsprintf>> returns the number of bytes in the output string, 00102 save that the concluding <<NULL>> is not counted. 00103 <<vprintf>> and <<vfprintf>> return the number of characters transmitted. 00104 If an error occurs, <<vprintf>> and <<vfprintf>> return <<EOF>> and 00105 <<vasprintf>> returns -1. No error returns occur for <<vsprintf>>. 00106 00107 PORTABILITY 00108 ANSI C requires all three functions. 00109 00110 Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>, 00111 <<lseek>>, <<read>>, <<sbrk>>, <<write>>. 00112 */ 00113 00114 /* 00115 * Copyright (c) 1990 The Regents of the University of California. 00116 * All rights reserved. 00117 * 00118 * This code is derived from software contributed to Berkeley by 00119 * Chris Torek. 00120 * 00121 * Redistribution and use in source and binary forms, with or without 00122 * modification, are permitted provided that the following conditions 00123 * are met: 00124 * 1. Redistributions of source code must retain the above copyright 00125 * notice, this list of conditions and the following disclaimer. 00126 * 2. Redistributions in binary form must reproduce the above copyright 00127 * notice, this list of conditions and the following disclaimer in the 00128 * documentation and/or other materials provided with the distribution. 00129 * 3. All advertising materials mentioning features or use of this software 00130 * must display the following acknowledgement: 00131 * This product includes software developed by the University of 00132 * California, Berkeley and its contributors. 00133 * 4. Neither the name of the University nor the names of its contributors 00134 * may be used to endorse or promote products derived from this software 00135 * without specific prior written permission. 00136 * 00137 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 00138 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00139 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00140 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 00141 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00142 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00143 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00144 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00145 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00146 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00147 * SUCH DAMAGE. 00148 */ 00149 00150 #if defined(LIBC_SCCS) && !defined(lint) 00151 static char *sccsid = "from: @(#)vfprintf.c 5.50 (Berkeley) 12/16/92"; 00152 #endif /* LIBC_SCCS and not lint */ 00153 00154 /* 00155 * Actual printf innards. 00156 * 00157 * This code is large and complicated... 00158 */ 00159 00160 00161 #ifdef _SMALL_PRINTF 00162 #define _NO_LONGDBL 00163 #endif 00164 00165 00166 #ifdef INTEGER_ONLY 00167 #define VFPRINTF vfiprintf 00168 #define _VFPRINTF_R _vfiprintf_r 00169 #else 00170 #define VFPRINTF vfprintf 00171 #define _VFPRINTF_R _vfprintf_r 00172 #ifndef NO_FLOATING_POINT 00173 #define FLOATING_POINT 00174 #endif 00175 #endif 00176 00177 #define _NO_LONGLONG 00178 #if defined WANT_PRINTF_LONG_LONG && defined __GNUC__ 00179 # undef _NO_LONGLONG 00180 #endif 00181 00182 #define _NO_POS_ARGS 00183 #if defined WANT_IO_POS_ARGS 00184 # undef _NO_POS_ARGS 00185 #endif 00186 00187 #include <_ansi.h> 00188 #include <stdio.h> 00189 #include <stdlib.h> 00190 #include <string.h> 00191 #include <limits.h> 00192 #include <reent.h> 00193 #include <wchar.h> 00194 #include <string.h> 00195 #include <sys/lock.h> 00196 00197 #ifdef _HAVE_STDC 00198 #include <stdarg.h> 00199 #else 00200 #include <varargs.h> 00201 #endif 00202 00203 #ifndef _SMALL_PRINTF 00204 #include "local.h" 00205 #include "fvwrite.h" 00206 #else 00207 #define MAXBUFLOC 80 00208 #endif 00209 00210 #include "vfieeefp.h" 00211 00212 /* Currently a test is made to see if long double processing is warranted. 00213 This could be changed in the future should the _ldtoa_r code be 00214 preferred over _dtoa_r. */ 00215 #define _NO_LONGDBL 00216 #if defined WANT_IO_LONG_DBL && (LDBL_MANT_DIG > DBL_MANT_DIG) 00217 # undef _NO_LONGDBL 00218 #endif 00219 00220 00221 #ifndef _SMALL_PRINTF 00222 /* 00223 * Flush out all the vectors defined by the given uio, 00224 * then reset it so that it can be reused. 00225 */ 00226 static int 00227 __sprint(fp, uio) 00228 FILE *fp; 00229 register struct __suio *uio; 00230 { 00231 register int err; 00232 00233 if (uio->uio_resid == 0) { 00234 uio->uio_iovcnt = 0; 00235 return (0); 00236 } 00237 err = __sfvwrite(fp, uio); 00238 uio->uio_resid = 0; 00239 uio->uio_iovcnt = 0; 00240 return (err); 00241 } 00242 00243 /* 00244 * Helper function for `fprintf to unbuffered unix file': creates a 00245 * temporary buffer. We only work on write-only files; this avoids 00246 * worries about ungetc buffers and so forth. 00247 */ 00248 static int 00249 __sbprintf(fp, fmt, ap) 00250 register FILE *fp; 00251 const char *fmt; 00252 va_list ap; 00253 { 00254 int ret; 00255 FILE fake; 00256 unsigned char buf[BUFSIZ]; 00257 00258 /* copy the important variables */ 00259 fake._flags = fp->_flags & ~__SNBF; 00260 fake._file = fp->_file; 00261 fake._cookie = fp->_cookie; 00262 fake._write = fp->_write; 00263 00264 /* set up the buffer */ 00265 fake._bf._base = fake._p = buf; 00266 fake._bf._size = fake._w = sizeof(buf); 00267 fake._lbfsize = 0; /* not actually used, but Just In Case */ 00268 #ifndef __SINGLE_THREAD__ 00269 __lock_init_recursive (*(_LOCK_RECURSIVE_T *)&fake._lock); 00270 #endif 00271 00272 /* do the work, then copy any error status */ 00273 ret = VFPRINTF(&fake, fmt, ap); 00274 if (ret >= 0 && fflush(&fake)) 00275 ret = EOF; 00276 if (fake._flags & __SERR) 00277 fp->_flags |= __SERR; 00278 00279 #ifndef __SINGLE_THREAD__ 00280 __lock_close_recursive (*(_LOCK_RECURSIVE_T *)&fake._lock); 00281 #endif 00282 return (ret); 00283 } 00284 #endif 00285 00286 00287 00288 #ifdef FLOATING_POINT 00289 #include <locale.h> 00290 #include <math.h> 00291 #include "floatio.h" 00292 00293 #if ((MAXEXP+MAXFRACT+1) > MB_LEN_MAX) 00294 # define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ 00295 #else 00296 # define BUF MB_LEN_MAX 00297 #endif 00298 00299 #define DEFPREC 6 00300 00301 #ifdef _NO_LONGDBL 00302 static char *cvt _PARAMS((struct _reent *, double, int, int, char *, int *, int, int *)); 00303 #else 00304 static char *cvt _PARAMS((struct _reent *, _LONG_DOUBLE, int, int, char *, int *, int, int *)); 00305 extern int _ldcheck _PARAMS((_LONG_DOUBLE *)); 00306 #endif 00307 00308 static int exponent _PARAMS((char *, int, int)); 00309 00310 #else /* no FLOATING_POINT */ 00311 00312 #define BUF 40 00313 00314 #endif /* FLOATING_POINT */ 00315 00316 #ifndef _NO_LONGLONG 00317 #define quad_t long long 00318 #define u_quad_t unsigned long long 00319 #else 00320 #define quad_t long 00321 #define u_quad_t unsigned long 00322 #endif 00323 00324 typedef quad_t * quad_ptr_t; 00325 typedef void * void_ptr_t; 00326 typedef char * char_ptr_t; 00327 typedef long * long_ptr_t; 00328 typedef int * int_ptr_t; 00329 typedef short * short_ptr_t; 00330 00331 #ifndef _NO_POS_ARGS 00332 #define MAX_POS_ARGS 32 00333 00334 union arg_val 00335 { 00336 int val_int; 00337 u_int val_u_int; 00338 long val_long; 00339 u_long val_u_long; 00340 float val_float; 00341 double val_double; 00342 _LONG_DOUBLE val__LONG_DOUBLE; 00343 int_ptr_t val_int_ptr_t; 00344 short_ptr_t val_short_ptr_t; 00345 long_ptr_t val_long_ptr_t; 00346 char_ptr_t val_char_ptr_t; 00347 quad_ptr_t val_quad_ptr_t; 00348 void_ptr_t val_void_ptr_t; 00349 quad_t val_quad_t; 00350 u_quad_t val_u_quad_t; 00351 wint_t val_wint_t; 00352 }; 00353 00354 static union arg_val *get_arg (struct _reent *data, int n, char *fmt, 00355 va_list *ap, int *numargs, union arg_val *args, 00356 int *arg_type, char **last_fmt); 00357 #endif /* !_NO_POS_ARGS */ 00358 00359 /* 00360 * Macros for converting digits to letters and vice versa 00361 */ 00362 #define to_digit(c) ((c) - '0') 00363 #define is_digit(c) ((unsigned)to_digit(c) <= 9) 00364 #define to_char(n) ((n) + '0') 00365 00366 /* 00367 * Flags used during conversion. 00368 */ 00369 #define ALT 0x001 /* alternate form */ 00370 #define HEXPREFIX 0x002 /* add 0x or 0X prefix */ 00371 #define LADJUST 0x004 /* left adjustment */ 00372 #define LONGDBL 0x008 /* long double */ 00373 #define LONGINT 0x010 /* long integer */ 00374 #ifndef _NO_LONGLONG 00375 #define QUADINT 0x020 /* quad integer */ 00376 #else /* ifdef _NO_LONGLONG, make QUADINT equivalent to LONGINT, so 00377 that %lld behaves the same as %ld, not as %d, as expected if: 00378 sizeof (long long) = sizeof long > sizeof int */ 00379 #define QUADINT LONGINT 00380 #endif 00381 #define SHORTINT 0x040 /* short integer */ 00382 #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ 00383 #define FPT 0x100 /* Floating point number */ 00384 00385 00386 int _EXFUN (_VFPRINTF_R, (struct _reent *, FILE *, _CONST char *, va_list)); 00387 00388 int 00389 _DEFUN (VFPRINTF, (fp, fmt0, ap), 00390 FILE * fp _AND 00391 _CONST char *fmt0 _AND 00392 va_list ap) 00393 { 00394 int result; 00395 _flockfile(fp); 00396 #ifndef _SMALL_PRINTF 00397 CHECK_INIT (fp); 00398 #endif 00399 result = _VFPRINTF_R (_REENT, fp, fmt0, ap); 00400 _funlockfile(fp); 00401 return result; 00402 } 00403 00404 00405 00406 int 00407 _DEFUN (_VFPRINTF_R, (data, fp, fmt0, ap), 00408 struct _reent *data _AND 00409 FILE * fp _AND 00410 _CONST char *fmt0 _AND 00411 va_list ap) 00412 { 00413 register char *fmt; /* format string */ 00414 register int ch; /* character from fmt */ 00415 register int n, m; /* handy integers (short term usage) */ 00416 register char *cp; /* handy char pointer (short term usage) */ 00417 register struct __siov *iovp;/* for PRINT macro */ 00418 register int flags; /* flags as above */ 00419 char *fmt_anchor; /* current format spec being processed */ 00420 int N; /* arg number */ 00421 int arg_index; /* index into args processed directly */ 00422 #ifndef _NO_POS_ARGS 00423 int numargs; /* number of varargs read */ 00424 char *saved_fmt; /* saved fmt pointer */ 00425 union arg_val args[MAX_POS_ARGS]; 00426 int arg_type[MAX_POS_ARGS]; 00427 int is_pos_arg; /* is current format positional? */ 00428 int old_is_pos_arg; /* is current format positional? */ 00429 #endif 00430 int ret; /* return value accumulator */ 00431 int width; /* width from format (%8d), or 0 */ 00432 int prec; /* precision from format (%.3d), or -1 */ 00433 char sign; /* sign prefix (' ', '+', '-', or \0) */ 00434 #ifdef FLOATING_POINT 00435 #ifdef _SMALL_PRINTF 00436 char *decimal_point = "."; 00437 #else 00438 char *decimal_point = localeconv()->decimal_point; 00439 #endif 00440 char softsign; /* temporary negative sign for floats */ 00441 #ifdef _NO_LONGDBL 00442 union { int i; double d; } _double_ = {0}; 00443 #define _fpvalue (_double_.d) 00444 #else 00445 union { int i; _LONG_DOUBLE ld; } _long_double_ = {0}; 00446 #define _fpvalue (_long_double_.ld) 00447 int tmp; 00448 #endif 00449 int expt; /* integer value of exponent */ 00450 int expsize = 0; /* character count for expstr */ 00451 int ndig; /* actual number of digits returned by cvt */ 00452 char expstr[7]; /* buffer for exponent string */ 00453 #endif 00454 u_quad_t _uquad; /* integer arguments %[diouxX] */ 00455 enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */ 00456 int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 00457 int realsz; /* field size expanded by dprec */ 00458 int size; /* size of converted field or string */ 00459 char *xdigs = NULL; /* digits for [xX] conversion */ 00460 #ifndef _SMALL_PRINTF 00461 #define NIOV 8 00462 struct __suio uio; /* output information: summary */ 00463 struct __siov iov[NIOV];/* ... and individual io vectors */ 00464 char *malloc_buf = NULL;/* handy pointer for malloced buffers */ 00465 #else 00466 char malloc_buf [MAXBUFLOC]; /* local buffers */ 00467 #endif 00468 00469 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ 00470 char ox[2]; /* space for 0x hex-prefix */ 00471 #ifdef MB_CAPABLE 00472 wchar_t wc; 00473 mbstate_t state; /* mbtowc calls from library must not change state */ 00474 #endif 00475 00476 00477 /* 00478 * Choose PADSIZE to trade efficiency vs. size. If larger printf 00479 * fields occur frequently, increase PADSIZE and make the initialisers 00480 * below longer. 00481 */ 00482 #define PADSIZE 16 /* pad chunk size */ 00483 static _CONST char blanks[PADSIZE] = 00484 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 00485 static _CONST char zeroes[PADSIZE] = 00486 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 00487 00488 #ifdef MB_CAPABLE 00489 memset (&state, '\0', sizeof (state)); 00490 #endif 00491 00492 #ifndef _SMALL_PRINTF 00493 /* 00494 * BEWARE, these `goto error' on error, and PAD uses `n'. 00495 */ 00496 #define PRINT(ptr, len,f) { \ 00497 iovp->iov_base = (ptr); \ 00498 iovp->iov_len = (len); \ 00499 uio.uio_resid += (len); \ 00500 iovp++; \ 00501 if (++uio.uio_iovcnt >= NIOV) { \ 00502 if (__sprint(fp, &uio)) \ 00503 goto error; \ 00504 iovp = iov; \ 00505 } \ 00506 } 00507 #define PAD(howmany, with,f) { \ 00508 if ((n = (howmany)) > 0) { \ 00509 while (n > PADSIZE) { \ 00510 PRINT(with, PADSIZE,f); \ 00511 n -= PADSIZE; \ 00512 } \ 00513 PRINT(with, n,f); \ 00514 } \ 00515 } 00516 #define FLUSH() { \ 00517 if (uio.uio_resid && __sprint(fp, &uio)) \ 00518 goto error; \ 00519 uio.uio_iovcnt = 0; \ 00520 iovp = iov; \ 00521 } 00522 #else 00523 //Macros for _SMALL_PRINTF 00524 void _SMALL_PRINTF_puts(const char *ptr, int len, FILE *f); 00525 #define PRINT(ptr, len, f) {_SMALL_PRINTF_puts(ptr,len,f);} 00526 #define PAD(howmany, with, f) { \ 00527 if ((n = (howmany)) > 0) { \ 00528 while (n > PADSIZE) { \ 00529 PRINT(with, PADSIZE,f); \ 00530 n -= PADSIZE; \ 00531 } \ 00532 PRINT(with, n, f); \ 00533 } \ 00534 } 00535 #define FLUSH() { ; } 00536 #endif 00537 00538 00539 /* Macros to support positional arguments */ 00540 #ifndef _NO_POS_ARGS 00541 #define GET_ARG(n, ap, type) \ 00542 ( is_pos_arg \ 00543 ? n < numargs \ 00544 ? args[n].val_##type \ 00545 : get_arg (data, n, fmt_anchor, &ap, &numargs, args, arg_type, &saved_fmt)->val_##type \ 00546 : arg_index++ < numargs \ 00547 ? args[n].val_##type \ 00548 : numargs < MAX_POS_ARGS \ 00549 ? args[numargs++].val_##type = va_arg(ap, type) \ 00550 : va_arg(ap, type) \ 00551 ) 00552 #else 00553 #define GET_ARG(n, ap, type) (va_arg(ap, type)) 00554 #endif 00555 00556 /* 00557 * To extend shorts properly, we need both signed and unsigned 00558 * argument extraction methods. 00559 */ 00560 #ifndef _NO_LONGLONG 00561 #define SARG() \ 00562 (flags&QUADINT ? GET_ARG(N, ap, quad_t) : \ 00563 flags&LONGINT ? GET_ARG(N, ap, long) : \ 00564 flags&SHORTINT ? (long)(short)GET_ARG(N, ap, int) : \ 00565 (long)GET_ARG(N, ap, int)) 00566 #define UARG() \ 00567 (flags&QUADINT ? GET_ARG(N, ap, u_quad_t) : \ 00568 flags&LONGINT ? GET_ARG(N, ap, u_long) : \ 00569 flags&SHORTINT ? (u_long)(u_short)GET_ARG(N, ap, int) : \ 00570 (u_long)GET_ARG(N, ap, u_int)) 00571 #else 00572 #define SARG() \ 00573 (flags&LONGINT ? GET_ARG(N, ap, long) : \ 00574 flags&SHORTINT ? (long)(short)GET_ARG(N, ap, int) : \ 00575 (long)GET_ARG(N, ap, int)) 00576 #define UARG() \ 00577 (flags&LONGINT ? GET_ARG(N, ap, u_long) : \ 00578 flags&SHORTINT ? (u_long)(u_short)GET_ARG(N, ap, int) : \ 00579 (u_long)GET_ARG(N, ap, u_int)) 00580 #endif 00581 00582 #ifndef _SMALL_PRINTF 00583 /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 00584 if (cantwrite(fp)) 00585 return (EOF); 00586 00587 /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 00588 if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 00589 fp->_file >= 0) 00590 return (__sbprintf(fp, fmt0, ap)); 00591 00592 uio.uio_iov = iovp = iov; 00593 uio.uio_resid = 0; 00594 uio.uio_iovcnt = 0; 00595 #endif 00596 fmt = (char *)fmt0; 00597 00598 ret = 0; 00599 arg_index = 0; 00600 00601 #ifndef _NO_POS_ARGS 00602 saved_fmt = NULL; 00603 arg_type[0] = -1; 00604 numargs = 0; 00605 is_pos_arg = 0; 00606 #endif 00607 00608 /* 00609 * Scan the format for conversions (`%' character). 00610 */ 00611 for (;;) { 00612 cp = fmt; 00613 #ifdef MB_CAPABLE 00614 while ((n = _mbtowc_r(data, &wc, fmt, MB_CUR_MAX, &state)) > 0) { 00615 if (wc == '%') 00616 break; 00617 fmt += n; 00618 } 00619 #else 00620 while (*fmt != '\0' && *fmt != '%') 00621 fmt += 1; 00622 #endif 00623 if ((m = fmt - cp) != 0) { 00624 PRINT(cp, m, fp); 00625 ret += m; 00626 } 00627 #ifdef MB_CAPABLE 00628 if (n <= 0) 00629 goto done; 00630 #else 00631 if (*fmt == '\0') 00632 goto done; 00633 #endif 00634 fmt_anchor = fmt; 00635 fmt++; /* skip over '%' */ 00636 00637 flags = 0; 00638 dprec = 0; 00639 width = 0; 00640 prec = -1; 00641 sign = '\0'; 00642 N = arg_index; 00643 #ifndef _NO_POS_ARGS 00644 is_pos_arg = 0; 00645 #endif 00646 00647 rflag: ch = *fmt++; 00648 reswitch: switch (ch) { 00649 case ' ': 00650 /* 00651 * ``If the space and + flags both appear, the space 00652 * flag will be ignored.'' 00653 * -- ANSI X3J11 00654 */ 00655 if (!sign) 00656 sign = ' '; 00657 goto rflag; 00658 case '#': 00659 flags |= ALT; 00660 goto rflag; 00661 case '*': 00662 n = N; 00663 #ifndef _NO_POS_ARGS 00664 /* we must check for positional arg used for dynamic width */ 00665 old_is_pos_arg = is_pos_arg; 00666 is_pos_arg = 0; 00667 if (is_digit(*fmt)) { 00668 char *old_fmt = fmt; 00669 00670 n = 0; 00671 ch = *fmt++; 00672 do { 00673 n = 10 * n + to_digit(ch); 00674 ch = *fmt++; 00675 } while (is_digit(ch)); 00676 00677 if (ch == '$') { 00678 if (n <= MAX_POS_ARGS) { 00679 n -= 1; 00680 is_pos_arg = 1; 00681 } 00682 else 00683 goto error; 00684 } 00685 else { 00686 fmt = old_fmt; 00687 goto rflag; 00688 } 00689 } 00690 #endif /* !_NO_POS_ARGS */ 00691 00692 /* 00693 * ``A negative field width argument is taken as a 00694 * - flag followed by a positive field width.'' 00695 * -- ANSI X3J11 00696 * They don't exclude field widths read from args. 00697 */ 00698 width = GET_ARG(n, ap, int); 00699 #ifndef _NO_POS_ARGS 00700 is_pos_arg = old_is_pos_arg; 00701 #endif 00702 if (width >= 0) 00703 goto rflag; 00704 width = -width; 00705 /* FALLTHROUGH */ 00706 case '-': 00707 flags |= LADJUST; 00708 goto rflag; 00709 case '+': 00710 sign = '+'; 00711 goto rflag; 00712 case '.': 00713 if ((ch = *fmt++) == '*') { 00714 n = N; 00715 #ifndef _NO_POS_ARGS 00716 /* we must check for positional arg used for dynamic width */ 00717 old_is_pos_arg = is_pos_arg; 00718 is_pos_arg = 0; 00719 if (is_digit(*fmt)) { 00720 char *old_fmt = fmt; 00721 00722 n = 0; 00723 ch = *fmt++; 00724 do { 00725 n = 10 * n + to_digit(ch); 00726 ch = *fmt++; 00727 } while (is_digit(ch)); 00728 00729 if (ch == '$') { 00730 if (n <= MAX_POS_ARGS) { 00731 n -= 1; 00732 is_pos_arg = 1; 00733 } 00734 else 00735 goto error; 00736 } 00737 else { 00738 fmt = old_fmt; 00739 goto rflag; 00740 } 00741 } 00742 #endif /* !_NO_POS_ARGS */ 00743 prec = GET_ARG(n, ap, int); 00744 #ifndef _NO_POS_ARGS 00745 is_pos_arg = old_is_pos_arg; 00746 #endif 00747 if (prec < 0) 00748 prec = -1; 00749 goto rflag; 00750 } 00751 n = 0; 00752 while (is_digit(ch)) { 00753 n = 10 * n + to_digit(ch); 00754 ch = *fmt++; 00755 } 00756 prec = n < 0 ? -1 : n; 00757 goto reswitch; 00758 case '0': 00759 /* 00760 * ``Note that 0 is taken as a flag, not as the 00761 * beginning of a field width.'' 00762 * -- ANSI X3J11 00763 */ 00764 flags |= ZEROPAD; 00765 goto rflag; 00766 case '1': case '2': case '3': case '4': 00767 case '5': case '6': case '7': case '8': case '9': 00768 n = 0; 00769 do { 00770 n = 10 * n + to_digit(ch); 00771 ch = *fmt++; 00772 } while (is_digit(ch)); 00773 #ifndef _NO_POS_ARGS 00774 if (ch == '$') { 00775 if (n <= MAX_POS_ARGS) { 00776 N = n - 1; 00777 is_pos_arg = 1; 00778 goto rflag; 00779 } 00780 else 00781 goto error; 00782 } 00783 #endif /* !_NO_POS_ARGS */ 00784 width = n; 00785 goto reswitch; 00786 #ifdef FLOATING_POINT 00787 case 'L': 00788 flags |= LONGDBL; 00789 goto rflag; 00790 #endif 00791 case 'h': 00792 flags |= SHORTINT; 00793 goto rflag; 00794 case 'l': 00795 if (*fmt == 'l') { 00796 fmt++; 00797 flags |= QUADINT; 00798 } else { 00799 flags |= LONGINT; 00800 } 00801 goto rflag; 00802 case 'q': 00803 flags |= QUADINT; 00804 goto rflag; 00805 case 'c': 00806 case 'C': 00807 cp = buf; 00808 if (ch == 'C' || (flags & LONGINT)) { 00809 mbstate_t ps; 00810 00811 memset((void *)&ps, '\0', sizeof(mbstate_t)); 00812 if ((size = (int)_wcrtomb_r(data, cp, 00813 (wchar_t)GET_ARG(N, ap, wint_t), 00814 &ps)) == -1) 00815 goto error; 00816 } 00817 else { 00818 *cp = GET_ARG(N, ap, int); 00819 size = 1; 00820 } 00821 sign = '\0'; 00822 break; 00823 case 'D': 00824 flags |= LONGINT; 00825 /*FALLTHROUGH*/ 00826 case 'd': 00827 case 'i': 00828 _uquad = SARG(); 00829 #ifndef _NO_LONGLONG 00830 if ((quad_t)_uquad < 0) 00831 #else 00832 if ((long) _uquad < 0) 00833 #endif 00834 { 00835 00836 _uquad = -_uquad; 00837 sign = '-'; 00838 } 00839 base = DEC; 00840 goto number; 00841 #ifdef FLOATING_POINT 00842 case 'e': 00843 case 'E': 00844 case 'f': 00845 case 'g': 00846 case 'G': 00847 if (prec == -1) { 00848 prec = DEFPREC; 00849 } else if ((ch == 'g' || ch == 'G') && prec == 0) { 00850 prec = 1; 00851 } 00852 00853 #ifdef _NO_LONGDBL 00854 if (flags & LONGDBL) { 00855 _fpvalue = (double) GET_ARG(N, ap, _LONG_DOUBLE); 00856 } else { 00857 _fpvalue = GET_ARG(N, ap, double); 00858 } 00859 00860 /* do this before tricky precision changes */ 00861 if (isinf(_fpvalue)) { 00862 if (_fpvalue < 0) 00863 sign = '-'; 00864 cp = "Inf"; 00865 size = 3; 00866 break; 00867 } 00868 if (isnan(_fpvalue)) { 00869 cp = "NaN"; 00870 size = 3; 00871 break; 00872 } 00873 00874 #else /* !_NO_LONGDBL */ 00875 00876 if (flags & LONGDBL) { 00877 _fpvalue = GET_ARG(N, ap, _LONG_DOUBLE); 00878 } else { 00879 _fpvalue = (_LONG_DOUBLE)GET_ARG(N, ap, double); 00880 } 00881 00882 /* do this before tricky precision changes */ 00883 tmp = _ldcheck (&_fpvalue); 00884 if (tmp == 2) { 00885 if (_fpvalue < 0) 00886 sign = '-'; 00887 cp = "Inf"; 00888 size = 3; 00889 break; 00890 } 00891 if (tmp == 1) { 00892 cp = "NaN"; 00893 size = 3; 00894 break; 00895 } 00896 #endif /* !_NO_LONGDBL */ 00897 00898 flags |= FPT; 00899 00900 cp = cvt(data, _fpvalue, prec, flags, &softsign, 00901 &expt, ch, &ndig); 00902 00903 if (ch == 'g' || ch == 'G') { 00904 if (expt <= -4 || expt > prec) 00905 ch = (ch == 'g') ? 'e' : 'E'; 00906 else 00907 ch = 'g'; 00908 } 00909 if (ch <= 'e') { /* 'e' or 'E' fmt */ 00910 --expt; 00911 expsize = exponent(expstr, expt, ch); 00912 size = expsize + ndig; 00913 if (ndig > 1 || flags & ALT) 00914 ++size; 00915 } else if (ch == 'f') { /* f fmt */ 00916 if (expt > 0) { 00917 size = expt; 00918 if (prec || flags & ALT) 00919 size += prec + 1; 00920 } else /* "0.X" */ 00921 size = (prec || flags & ALT) 00922 ? prec + 2 00923 : 1; 00924 } else if (expt >= ndig) { /* fixed g fmt */ 00925 size = expt; 00926 if (flags & ALT) 00927 ++size; 00928 } else 00929 size = ndig + (expt > 0 ? 00930 1 : 2 - expt); 00931 00932 if (softsign) 00933 sign = '-'; 00934 break; 00935 #endif /* FLOATING_POINT */ 00936 case 'n': 00937 #ifndef _NO_LONGLONG 00938 if (flags & QUADINT) 00939 *GET_ARG(N, ap, quad_ptr_t) = ret; 00940 else 00941 #endif 00942 if (flags & LONGINT) 00943 *GET_ARG(N, ap, long_ptr_t) = ret; 00944 else if (flags & SHORTINT) 00945 *GET_ARG(N, ap, short_ptr_t) = ret; 00946 else 00947 *GET_ARG(N, ap, int_ptr_t) = ret; 00948 continue; /* no output */ 00949 case 'O': 00950 flags |= LONGINT; 00951 /*FALLTHROUGH*/ 00952 case 'o': 00953 _uquad = UARG(); 00954 base = OCT; 00955 goto nosign; 00956 case 'p': 00957 /* 00958 * ``The argument shall be a pointer to void. The 00959 * value of the pointer is converted to a sequence 00960 * of printable characters, in an implementation- 00961 * defined manner.'' 00962 * -- ANSI X3J11 00963 */ 00964 /* NOSTRICT */ 00965 _uquad = (u_long)(unsigned _POINTER_INT)GET_ARG(N, ap, void_ptr_t); 00966 base = HEX; 00967 xdigs = "0123456789abcdef"; 00968 flags |= HEXPREFIX; 00969 ch = 'x'; 00970 goto nosign; 00971 case 's': 00972 case 'S': 00973 sign = '\0'; 00974 if ((cp = GET_ARG(N, ap, char_ptr_t)) == NULL) { 00975 cp = "(null)"; 00976 size = 6; 00977 } 00978 else if (ch == 'S' || (flags & LONGINT)) { 00979 mbstate_t ps; 00980 _CONST wchar_t *wcp; 00981 00982 wcp = (_CONST wchar_t *)cp; 00983 size = m = 0; 00984 memset((void *)&ps, '\0', sizeof(mbstate_t)); 00985 00986 /* Count number of bytes needed for multibyte 00987 string that will be produced from widechar 00988 string. */ 00989 if (prec >= 0) { 00990 while (1) { 00991 if (wcp[m] == L'\0') 00992 break; 00993 if ((n = (int)_wcrtomb_r(data, 00994 buf, wcp[m], &ps)) == -1) 00995 goto error; 00996 if (n + size > prec) 00997 break; 00998 m += 1; 00999 size += n; 01000 if (size == prec) 01001 break; 01002 } 01003 } 01004 else { 01005 if ((size = (int)_wcsrtombs_r(data, 01006 NULL, &wcp, 0, &ps)) == -1) 01007 goto error; 01008 wcp = (_CONST wchar_t *)cp; 01009 } 01010 01011 if (size == 0) 01012 break; 01013 01014 #ifndef _SMALL_PRINTF 01015 if ((malloc_buf = 01016 (char *)_malloc_r(data, size + 1)) == NULL) 01017 goto error; 01018 #endif 01019 01020 /* Convert widechar string to multibyte string. */ 01021 memset((void *)&ps, '\0', sizeof(mbstate_t)); 01022 if (_wcsrtombs_r(data, malloc_buf, &wcp, size, &ps) != size) 01023 goto error; 01024 cp = malloc_buf; 01025 cp[size] = '\0'; 01026 } 01027 else if (prec >= 0) { 01028 /* 01029 * can't use strlen; can only look for the 01030 * NUL in the first `prec' characters, and 01031 * strlen() will go further. 01032 */ 01033 char *p = memchr(cp, 0, prec); 01034 01035 if (p != NULL) { 01036 size = p - cp; 01037 if (size > prec) 01038 size = prec; 01039 } else 01040 size = prec; 01041 } else 01042 size = strlen(cp); 01043 01044 break; 01045 case 'U': 01046 flags |= LONGINT; 01047 /*FALLTHROUGH*/ 01048 case 'u': 01049 _uquad = UARG(); 01050 base = DEC; 01051 goto nosign; 01052 case 'X': 01053 xdigs = "0123456789ABCDEF"; 01054 goto hex; 01055 case 'x': 01056 xdigs = "0123456789abcdef"; 01057 hex: _uquad = UARG(); 01058 base = HEX; 01059 /* leading 0x/X only if non-zero */ 01060 if (flags & ALT && _uquad != 0) 01061 flags |= HEXPREFIX; 01062 01063 /* unsigned conversions */ 01064 nosign: sign = '\0'; 01065 /* 01066 * ``... diouXx conversions ... if a precision is 01067 * specified, the 0 flag will be ignored.'' 01068 * -- ANSI X3J11 01069 */ 01070 number: if ((dprec = prec) >= 0) 01071 flags &= ~ZEROPAD; 01072 01073 /* 01074 * ``The result of converting a zero value with an 01075 * explicit precision of zero is no characters.'' 01076 * -- ANSI X3J11 01077 */ 01078 cp = buf + BUF; 01079 if (_uquad != 0 || prec != 0) { 01080 /* 01081 * Unsigned mod is hard, and unsigned mod 01082 * by a constant is easier than that by 01083 * a variable; hence this switch. 01084 */ 01085 switch (base) { 01086 case OCT: 01087 do { 01088 *--cp = to_char(_uquad & 7); 01089 _uquad >>= 3; 01090 } while (_uquad); 01091 /* handle octal leading 0 */ 01092 if (flags & ALT && *cp != '0') 01093 *--cp = '0'; 01094 break; 01095 01096 case DEC: 01097 /* many numbers are 1 digit */ 01098 while (_uquad >= 10) { 01099 *--cp = to_char(_uquad % 10); 01100 _uquad /= 10; 01101 } 01102 *--cp = to_char(_uquad); 01103 break; 01104 01105 case HEX: 01106 do { 01107 *--cp = xdigs[_uquad & 15]; 01108 _uquad >>= 4; 01109 } while (_uquad); 01110 break; 01111 01112 default: 01113 cp = "bug in vfprintf: bad base"; 01114 size = strlen(cp); 01115 goto skipsize; 01116 } 01117 } 01118 /* 01119 * ...result is to be converted to an 'alternate form'. 01120 * For o conversion, it increases the precision to force 01121 * the first digit of the result to be a zero." 01122 * -- ANSI X3J11 01123 * 01124 * To demonstrate this case, compile and run: 01125 * printf ("%#.0o",0); 01126 */ 01127 else if (base == OCT && (flags & ALT)) 01128 *--cp = '0'; 01129 01130 size = buf + BUF - cp; 01131 skipsize: 01132 break; 01133 default: /* "%?" prints ?, unless ? is NUL */ 01134 if (ch == '\0') 01135 goto done; 01136 /* pretend it was %c with argument ch */ 01137 cp = buf; 01138 *cp = ch; 01139 size = 1; 01140 sign = '\0'; 01141 break; 01142 } 01143 01144 /* 01145 * All reasonable formats wind up here. At this point, `cp' 01146 * points to a string which (if not flags&LADJUST) should be 01147 * padded out to `width' places. If flags&ZEROPAD, it should 01148 * first be prefixed by any sign or other prefix; otherwise, 01149 * it should be blank padded before the prefix is emitted. 01150 * After any left-hand padding and prefixing, emit zeroes 01151 * required by a decimal [diouxX] precision, then print the 01152 * string proper, then emit zeroes required by any leftover 01153 * floating precision; finally, if LADJUST, pad with blanks. 01154 * 01155 * Compute actual size, so we know how much to pad. 01156 * size excludes decimal prec; realsz includes it. 01157 */ 01158 realsz = dprec > size ? dprec : size; 01159 if (sign) 01160 realsz++; 01161 else if (flags & HEXPREFIX) 01162 realsz+= 2; 01163 01164 /* right-adjusting blank padding */ 01165 if ((flags & (LADJUST|ZEROPAD)) == 0) 01166 PAD(width - realsz, blanks, fp); 01167 01168 /* prefix */ 01169 if (sign) { 01170 PRINT(&sign, 1, fp); 01171 } else if (flags & HEXPREFIX) { 01172 ox[0] = '0'; 01173 ox[1] = ch; 01174 PRINT(ox, 2 ,fp); 01175 } 01176 01177 /* right-adjusting zero padding */ 01178 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 01179 PAD(width - realsz, zeroes, fp); 01180 01181 /* leading zeroes from decimal precision */ 01182 PAD(dprec - size, zeroes, fp); 01183 01184 /* the string or number proper */ 01185 #ifdef FLOATING_POINT 01186 if ((flags & FPT) == 0) { 01187 PRINT(cp, size, fp); 01188 } else { /* glue together f_p fragments */ 01189 if (ch >= 'f') { /* 'f' or 'g' */ 01190 if (_fpvalue == 0) { 01191 /* kludge for __dtoa irregularity */ 01192 PRINT("0", 1, fp); 01193 if (expt < ndig || (flags & ALT) != 0) { 01194 PRINT(decimal_point, 1, fp); 01195 PAD(ndig - 1, zeroes, fp); 01196 } 01197 } else if (expt <= 0) { 01198 PRINT("0", 1, fp); 01199 if(expt || ndig) { 01200 PRINT(decimal_point, 1, fp); 01201 PAD(-expt, zeroes, fp); 01202 PRINT(cp, ndig, fp); 01203 } 01204 } else if (expt >= ndig) { 01205 PRINT(cp, ndig, fp); 01206 PAD(expt - ndig, zeroes, fp); 01207 if (flags & ALT) 01208 PRINT(".", 1, fp); 01209 } else { 01210 PRINT(cp, expt, fp); 01211 cp += expt; 01212 PRINT(".", 1, fp); 01213 PRINT(cp, ndig-expt, fp); 01214 } 01215 } else { /* 'e' or 'E' */ 01216 if (ndig > 1 || flags & ALT) { 01217 ox[0] = *cp++; 01218 ox[1] = '.'; 01219 PRINT(ox, 2, fp); 01220 if (_fpvalue) { 01221 PRINT(cp, ndig-1, fp); 01222 } else /* 0.[0..] */ 01223 /* __dtoa irregularity */ 01224 PAD(ndig - 1, zeroes, fp); 01225 } else /* XeYYY */ 01226 PRINT(cp, 1, fp); 01227 PRINT(expstr, expsize, fp); 01228 } 01229 } 01230 #else 01231 PRINT(cp, size, fp); 01232 #endif 01233 /* left-adjusting padding (always blank) */ 01234 if (flags & LADJUST) 01235 PAD(width - realsz, blanks, fp); 01236 01237 /* finally, adjust ret */ 01238 ret += width > realsz ? width : realsz; 01239 01240 FLUSH(); /* copy out the I/O vectors */ 01241 01242 #ifndef _SMALL_PRINTF 01243 if (malloc_buf != NULL) { 01244 free(malloc_buf); 01245 malloc_buf = NULL; 01246 } 01247 #endif 01248 } 01249 done: 01250 FLUSH(); 01251 error: 01252 01253 #ifndef _SMALL_PRINTF 01254 if (malloc_buf != NULL) 01255 free(malloc_buf); 01256 return (__sferror(fp) ? EOF : ret); 01257 #else 01258 return ret; 01259 #endif 01260 /* NOTREACHED */ 01261 } 01262 01263 #ifdef FLOATING_POINT 01264 01265 #ifdef _NO_LONGDBL 01266 extern char *_dtoa_r _PARAMS((struct _reent *, double, int, 01267 int, int *, int *, char **)); 01268 #else 01269 extern char *_ldtoa_r _PARAMS((struct _reent *, _LONG_DOUBLE, int, 01270 int, int *, int *, char **)); 01271 #undef word0 01272 #define word0(x) ldword0(x) 01273 #endif 01274 01275 static char * 01276 cvt(data, value, ndigits, flags, sign, decpt, ch, length) 01277 struct _reent *data; 01278 #ifdef _NO_LONGDBL 01279 double value; 01280 #else 01281 _LONG_DOUBLE value; 01282 #endif 01283 int ndigits, flags, *decpt, ch, *length; 01284 char *sign; 01285 { 01286 int mode, dsgn; 01287 char *digits, *bp, *rve; 01288 #ifdef _NO_LONGDBL 01289 union double_union tmp; 01290 #else 01291 struct ldieee *ldptr; 01292 #endif 01293 01294 if (ch == 'f') { 01295 mode = 3; /* ndigits after the decimal point */ 01296 } else { 01297 /* To obtain ndigits after the decimal point for the 'e' 01298 * and 'E' formats, round to ndigits + 1 significant 01299 * figures. 01300 */ 01301 if (ch == 'e' || ch == 'E') { 01302 ndigits++; 01303 } 01304 mode = 2; /* ndigits significant digits */ 01305 } 01306 01307 #ifdef _NO_LONGDBL 01308 tmp.d = value; 01309 01310 if (word0(tmp) & Sign_bit) { /* this will check for < 0 and -0.0 */ 01311 value = -value; 01312 *sign = '-'; 01313 } else 01314 *sign = '\000'; 01315 01316 digits = _dtoa_r(data, value, mode, ndigits, decpt, &dsgn, &rve); 01317 #else /* !_NO_LONGDBL */ 01318 ldptr = (struct ldieee *)&value; 01319 if (ldptr->sign) { /* this will check for < 0 and -0.0 */ 01320 value = -value; 01321 *sign = '-'; 01322 } else 01323 *sign = '\000'; 01324 01325 digits = _ldtoa_r(data, value, mode, ndigits, decpt, &dsgn, &rve); 01326 #endif /* !_NO_LONGDBL */ 01327 01328 if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */ 01329 bp = digits + ndigits; 01330 if (ch == 'f') { 01331 if (*digits == '0' && value) 01332 *decpt = -ndigits + 1; 01333 bp += *decpt; 01334 } 01335 if (value == 0) /* kludge for __dtoa irregularity */ 01336 rve = bp; 01337 while (rve < bp) 01338 *rve++ = '0'; 01339 } 01340 *length = rve - digits; 01341 return (digits); 01342 } 01343 01344 static int 01345 exponent(p0, exp, fmtch) 01346 char *p0; 01347 int exp, fmtch; 01348 { 01349 register char *p, *t; 01350 char expbuf[40]; 01351 01352 p = p0; 01353 *p++ = fmtch; 01354 if (exp < 0) { 01355 exp = -exp; 01356 *p++ = '-'; 01357 } 01358 else 01359 *p++ = '+'; 01360 t = expbuf + 40; 01361 if (exp > 9) { 01362 do { 01363 *--t = to_char(exp % 10); 01364 } while ((exp /= 10) > 9); 01365 *--t = to_char(exp); 01366 for (; t < expbuf + 40; *p++ = *t++); 01367 } 01368 else { 01369 *p++ = '0'; 01370 *p++ = to_char(exp); 01371 } 01372 return (p - p0); 01373 } 01374 #endif /* FLOATING_POINT */ 01375 01376 01377 #ifndef _NO_POS_ARGS 01378 01379 /* Positional argument support. 01380 Written by Jeff Johnston 01381 01382 Copyright (c) 2002 Red Hat Incorporated. 01383 All rights reserved. 01384 01385 Redistribution and use in source and binary forms, with or without 01386 modification, are permitted provided that the following conditions are met: 01387 01388 Redistributions of source code must retain the above copyright 01389 notice, this list of conditions and the following disclaimer. 01390 01391 Redistributions in binary form must reproduce the above copyright 01392 notice, this list of conditions and the following disclaimer in the 01393 documentation and/or other materials provided with the distribution. 01394 01395 The name of Red Hat Incorporated may not be used to endorse 01396 or promote products derived from this software without specific 01397 prior written permission. 01398 01399 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 01400 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 01401 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 01402 DISCLAIMED. IN NO EVENT SHALL RED HAT INCORPORATED BE LIABLE FOR ANY 01403 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 01404 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 01405 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 01406 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 01407 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 01408 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 01409 01410 typedef enum { 01411 ZERO, /* '0' */ 01412 DIGIT, /* '1-9' */ 01413 DOLLAR, /* '$' */ 01414 MODFR, /* spec modifier */ 01415 SPEC, /* format specifier */ 01416 DOT, /* '.' */ 01417 STAR, /* '*' */ 01418 FLAG, /* format flag */ 01419 OTHER, /* all other chars */ 01420 MAX_CH_CLASS /* place-holder */ 01421 } CH_CLASS; 01422 01423 typedef enum { 01424 START, /* start */ 01425 SFLAG, /* seen a flag */ 01426 WDIG, /* seen digits in width area */ 01427 WIDTH, /* processed width */ 01428 SMOD, /* seen spec modifier */ 01429 SDOT, /* seen dot */ 01430 VARW, /* have variable width specifier */ 01431 VARP, /* have variable precision specifier */ 01432 PREC, /* processed precision */ 01433 VWDIG, /* have digits in variable width specification */ 01434 VPDIG, /* have digits in variable precision specification */ 01435 DONE, /* done */ 01436 MAX_STATE, /* place-holder */ 01437 } STATE; 01438 01439 typedef enum { 01440 NOOP, /* do nothing */ 01441 NUMBER, /* build a number from digits */ 01442 SKIPNUM, /* skip over digits */ 01443 GETMOD, /* get and process format modifier */ 01444 GETARG, /* get and process argument */ 01445 GETPW, /* get variable precision or width */ 01446 GETPWB, /* get variable precision or width and pushback fmt char */ 01447 GETPOS, /* get positional parameter value */ 01448 PWPOS, /* get positional parameter value for variable width or precision */ 01449 } ACTION; 01450 01451 const static CH_CLASS chclass[256] = { 01452 /* 00-07 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01453 /* 08-0f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01454 /* 10-17 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01455 /* 18-1f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01456 /* 20-27 */ FLAG, OTHER, OTHER, FLAG, DOLLAR, OTHER, OTHER, OTHER, 01457 /* 28-2f */ OTHER, OTHER, STAR, FLAG, OTHER, FLAG, DOT, OTHER, 01458 /* 30-37 */ ZERO, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, 01459 /* 38-3f */ DIGIT, DIGIT, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01460 /* 40-47 */ OTHER, OTHER, OTHER, SPEC, SPEC, SPEC, OTHER, SPEC, 01461 /* 48-4f */ OTHER, OTHER, OTHER, OTHER, MODFR, OTHER, OTHER, SPEC, 01462 /* 50-57 */ OTHER, OTHER, OTHER, SPEC, OTHER, SPEC, OTHER, SPEC, 01463 /* 58-5f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01464 /* 60-67 */ OTHER, OTHER, OTHER, SPEC, SPEC, SPEC, SPEC, SPEC, 01465 /* 68-6f */ MODFR, SPEC, OTHER, OTHER, MODFR, OTHER, OTHER, SPEC, 01466 /* 70-77 */ SPEC, MODFR, OTHER, SPEC, OTHER, SPEC, OTHER, OTHER, 01467 /* 78-7f */ SPEC, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01468 /* 80-87 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01469 /* 88-8f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01470 /* 90-97 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01471 /* 98-9f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01472 /* a0-a7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01473 /* a8-af */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01474 /* b0-b7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01475 /* b8-bf */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01476 /* c0-c7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01477 /* c8-cf */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01478 /* d0-d7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01479 /* d8-df */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01480 /* e0-e7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01481 /* e8-ef */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01482 /* f0-f7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01483 /* f8-ff */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, 01484 }; 01485 01486 const static STATE state_table[MAX_STATE][MAX_CH_CLASS] = { 01487 /* '0' '1-9' '$' MODFR SPEC '.' '*' FLAG OTHER */ 01488 /* START */ { SFLAG, WDIG, DONE, SMOD, DONE, SDOT, VARW, SFLAG, DONE }, 01489 /* SFLAG */ { SFLAG, WDIG, DONE, SMOD, DONE, SDOT, VARW, SFLAG, DONE }, 01490 /* WDIG */ { DONE, DONE, WIDTH, SMOD, DONE, SDOT, DONE, DONE, DONE }, 01491 /* WIDTH */ { DONE, DONE, DONE, SMOD, DONE, SDOT, DONE, DONE, DONE }, 01492 /* SMOD */ { DONE, DONE, DONE, DONE, DONE, DONE, DONE, DONE, DONE }, 01493 /* SDOT */ { SDOT, PREC, DONE, SMOD, DONE, DONE, VARP, DONE, DONE }, 01494 /* VARW */ { DONE, VWDIG, DONE, SMOD, DONE, SDOT, DONE, DONE, DONE }, 01495 /* VARP */ { DONE, VPDIG, DONE, SMOD, DONE, DONE, DONE, DONE, DONE }, 01496 /* PREC */ { DONE, DONE, DONE, SMOD, DONE, DONE, DONE, DONE, DONE }, 01497 /* VWDIG */ { DONE, DONE, WIDTH, DONE, DONE, DONE, DONE, DONE, DONE }, 01498 /* VPDIG */ { DONE, DONE, PREC, DONE, DONE, DONE, DONE, DONE, DONE }, 01499 }; 01500 01501 const static ACTION action_table[MAX_STATE][MAX_CH_CLASS] = { 01502 /* '0' '1-9' '$' MODFR SPEC '.' '*' FLAG OTHER */ 01503 /* START */ { NOOP, NUMBER, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP }, 01504 /* SFLAG */ { NOOP, NUMBER, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP }, 01505 /* WDIG */ { NOOP, NOOP, GETPOS, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP }, 01506 /* WIDTH */ { NOOP, NOOP, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP }, 01507 /* SMOD */ { NOOP, NOOP, NOOP, NOOP, GETARG, NOOP, NOOP, NOOP, NOOP }, 01508 /* SDOT */ { NOOP, SKIPNUM, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP }, 01509 /* VARW */ { NOOP, NUMBER, NOOP, GETPW, GETPWB, GETPW, NOOP, NOOP, NOOP }, 01510 /* VARP */ { NOOP, NUMBER, NOOP, GETPW, GETPWB, NOOP, NOOP, NOOP, NOOP }, 01511 /* PREC */ { NOOP, NOOP, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP }, 01512 /* VWDIG */ { NOOP, NOOP, PWPOS, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP }, 01513 /* VPDIG */ { NOOP, NOOP, PWPOS, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP }, 01514 }; 01515 01516 /* function to get positional parameter N where n = N - 1 */ 01517 static union arg_val * 01518 get_arg (struct _reent *data, int n, char *fmt, va_list *ap, 01519 int *numargs_p, union arg_val *args, 01520 int *arg_type, char **last_fmt) 01521 { 01522 int ch; 01523 int number, flags; 01524 int spec_type; 01525 int numargs = *numargs_p; 01526 CH_CLASS chtype; 01527 STATE state, next_state; 01528 ACTION action; 01529 int pos, last_arg; 01530 int max_pos_arg = n; 01531 enum types { INT, LONG_INT, SHORT_INT, QUAD_INT, CHAR, CHAR_PTR, DOUBLE, LONG_DOUBLE, WIDE_CHAR }; 01532 #ifdef MB_CAPABLE 01533 wchar_t wc; 01534 mbstate_t wc_state; 01535 int nbytes; 01536 #endif 01537 01538 /* if this isn't the first call, pick up where we left off last time */ 01539 if (*last_fmt != NULL) 01540 fmt = *last_fmt; 01541 01542 #ifdef MB_CAPABLE 01543 memset (&wc_state, '\0', sizeof (wc_state)); 01544 #endif 01545 01546 /* we need to process either to end of fmt string or until we have actually 01547 read the desired parameter from the vararg list. */ 01548 while (*fmt && n >= numargs) 01549 { 01550 #ifdef MB_CAPABLE 01551 while ((nbytes = _mbtowc_r(data, &wc, fmt, MB_CUR_MAX, &wc_state)) > 0) 01552 { 01553 fmt += nbytes; 01554 if (wc == '%') 01555 break; 01556 } 01557 01558 if (nbytes <= 0) 01559 break; 01560 #else 01561 while (*fmt != '\0' && *fmt != '%') 01562 fmt += 1; 01563 01564 if (*fmt == '\0') 01565 break; 01566 #endif 01567 state = START; 01568 flags = 0; 01569 pos = -1; 01570 number = 0; 01571 spec_type = INT; 01572 01573 /* Use state/action table to process format specifiers. We ignore invalid 01574 formats and we are only interested in information that tells us how to 01575 read the vararg list. */ 01576 while (state != DONE) 01577 { 01578 ch = *fmt++; 01579 chtype = chclass[ch]; 01580 next_state = state_table[state][chtype]; 01581 action = action_table[state][chtype]; 01582 state = next_state; 01583 01584 switch (action) 01585 { 01586 case GETMOD: /* we have format modifier */ 01587 switch (ch) 01588 { 01589 case 'h': 01590 flags |= SHORTINT; 01591 break; 01592 case 'L': 01593 flags |= LONGDBL; 01594 break; 01595 case 'q': 01596 flags |= QUADINT; 01597 break; 01598 case 'l': 01599 default: 01600 if (*fmt == 'l') 01601 { 01602 flags |= QUADINT; 01603 ++fmt; 01604 } 01605 else 01606 flags |= LONGINT; 01607 break; 01608 } 01609 break; 01610 case GETARG: /* we have format specifier */ 01611 { 01612 numargs &= (MAX_POS_ARGS - 1); 01613 /* process the specifier and translate it to a type to fetch from varargs */ 01614 switch (ch) 01615 { 01616 case 'd': 01617 case 'i': 01618 case 'o': 01619 case 'x': 01620 case 'X': 01621 case 'u': 01622 if (flags & LONGINT) 01623 spec_type = LONG_INT; 01624 else if (flags & SHORTINT) 01625 spec_type = SHORT_INT; 01626 #ifndef _NO_LONGLONG 01627 else if (flags & QUADINT) 01628 spec_type = QUAD_INT; 01629 #endif 01630 else 01631 spec_type = INT; 01632 break; 01633 case 'D': 01634 case 'U': 01635 case 'O': 01636 spec_type = LONG_INT; 01637 break; 01638 case 'f': 01639 case 'g': 01640 case 'G': 01641 case 'E': 01642 case 'e': 01643 #ifndef _NO_LONGDBL 01644 if (flags & LONGDBL) 01645 spec_type = LONG_DOUBLE; 01646 else 01647 #endif 01648 spec_type = DOUBLE; 01649 break; 01650 case 's': 01651 case 'S': 01652 case 'p': 01653 spec_type = CHAR_PTR; 01654 break; 01655 case 'c': 01656 spec_type = CHAR; 01657 break; 01658 case 'C': 01659 spec_type = WIDE_CHAR; 01660 break; 01661 } 01662 01663 /* if we have a positional parameter, just store the type, otherwise 01664 fetch the parameter from the vararg list */ 01665 if (pos != -1) 01666 arg_type[pos] = spec_type; 01667 else 01668 { 01669 switch (spec_type) 01670 { 01671 case LONG_INT: 01672 args[numargs++].val_long = va_arg(*ap, long); 01673 break; 01674 case QUAD_INT: 01675 args[numargs++].val_quad_t = va_arg(*ap, quad_t); 01676 break; 01677 case WIDE_CHAR: 01678 args[numargs++].val_wint_t = va_arg(*ap, wint_t); 01679 break; 01680 case CHAR: 01681 case SHORT_INT: 01682 case INT: 01683 args[numargs++].val_int = va_arg(*ap, int); 01684 break; 01685 case CHAR_PTR: 01686 args[numargs++].val_char_ptr_t = va_arg(*ap, char *); 01687 break; 01688 case DOUBLE: 01689 args[numargs++].val_double = va_arg(*ap, double); 01690 break; 01691 case LONG_DOUBLE: 01692 args[numargs++].val__LONG_DOUBLE = va_arg(*ap, _LONG_DOUBLE); 01693 break; 01694 } 01695 } 01696 } 01697 break; 01698 case GETPOS: /* we have positional specifier */ 01699 if (arg_type[0] == -1) 01700 memset (arg_type, 0, sizeof(int) * MAX_POS_ARGS); 01701 pos = number - 1; 01702 max_pos_arg = (max_pos_arg > pos ? max_pos_arg : pos); 01703 break; 01704 case PWPOS: /* we have positional specifier for width or precision */ 01705 if (arg_type[0] == -1) 01706 memset (arg_type, 0, sizeof(int) * MAX_POS_ARGS); 01707 number -= 1; 01708 arg_type[number] = INT; 01709 max_pos_arg = (max_pos_arg > number ? max_pos_arg : number); 01710 break; 01711 case GETPWB: /* we require format pushback */ 01712 --fmt; 01713 /* fallthrough */ 01714 case GETPW: /* we have a variable precision or width to acquire */ 01715 args[numargs++].val_int = va_arg(*ap, int); 01716 break; 01717 case NUMBER: /* we have a number to process */ 01718 number = (ch - '0'); 01719 while ((ch = *fmt) != '\0' && is_digit(ch)) 01720 { 01721 number = number * 10 + (ch - '0'); 01722 ++fmt; 01723 } 01724 break; 01725 case SKIPNUM: /* we have a number to skip */ 01726 while ((ch = *fmt) != '\0' && is_digit(ch)) 01727 ++fmt; 01728 break; 01729 case NOOP: 01730 default: 01731 break; /* do nothing */ 01732 } 01733 } 01734 } 01735 01736 /* process all arguments up to at least the one we are looking for and if we 01737 have seen the end of the string, then process up to the max argument needed */ 01738 if (*fmt == '\0') 01739 last_arg = max_pos_arg; 01740 else 01741 last_arg = n; 01742 01743 while (numargs <= last_arg) 01744 { 01745 switch (arg_type[numargs]) 01746 { 01747 case LONG_INT: 01748 args[numargs++].val_long = va_arg(*ap, long); 01749 break; 01750 case QUAD_INT: 01751 args[numargs++].val_quad_t = va_arg(*ap, quad_t); 01752 break; 01753 case CHAR_PTR: 01754 args[numargs++].val_char_ptr_t = va_arg(*ap, char *); 01755 break; 01756 case DOUBLE: 01757 args[numargs++].val_double = va_arg(*ap, double); 01758 break; 01759 case LONG_DOUBLE: 01760 args[numargs++].val__LONG_DOUBLE = va_arg(*ap, _LONG_DOUBLE); 01761 break; 01762 case WIDE_CHAR: 01763 args[numargs++].val_wint_t = va_arg(*ap, wint_t); 01764 break; 01765 case INT: 01766 case SHORT_INT: 01767 case CHAR: 01768 default: 01769 args[numargs++].val_int = va_arg(*ap, int); 01770 break; 01771 } 01772 } 01773 01774 /* alter the global numargs value and keep a reference to the last bit of the fmt 01775 string we processed here because the caller will continue processing where we started */ 01776 *numargs_p = numargs; 01777 *last_fmt = fmt; 01778 return &args[n]; 01779 } 01780 #endif /* !_NO_POS_ARGS */