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