Contiki 2.5
_SP_vfprintf.c
1 /*
2 FUNCTION
3 <<vprintf>>, <<vfprintf>>, <<vsprintf>>---format argument list
4 
5 INDEX
6  vprintf
7 INDEX
8  vfprintf
9 INDEX
10  vsprintf
11 INDEX
12  vsnprintf
13 
14 ANSI_SYNOPSIS
15  #include <stdio.h>
16  #include <stdarg.h>
17  int vprintf(const char *<[fmt]>, va_list <[list]>);
18  int vfprintf(FILE *<[fp]>, const char *<[fmt]>, va_list <[list]>);
19  int vsprintf(char *<[str]>, const char *<[fmt]>, va_list <[list]>);
20  int vasprintf(char **<[strp]>, const char *<[fmt]>, va_list <[list]>);
21  int vsnprintf(char *<[str]>, size_t <[size]>, const char *<[fmt]>, va_list <[list]>);
22 
23  int _vprintf_r(void *<[reent]>, const char *<[fmt]>,
24  va_list <[list]>);
25  int _vfprintf_r(void *<[reent]>, FILE *<[fp]>, const char *<[fmt]>,
26  va_list <[list]>);
27  int _vasprintf_r(void *<[reent]>, char **<[str]>, const char *<[fmt]>,
28  va_list <[list]>);
29  int _vsprintf_r(void *<[reent]>, char *<[str]>, const char *<[fmt]>,
30  va_list <[list]>);
31  int _vsnprintf_r(void *<[reent]>, char *<[str]>, size_t <[size]>, const char *<[fmt]>,
32  va_list <[list]>);
33 
34 TRAD_SYNOPSIS
35  #include <stdio.h>
36  #include <varargs.h>
37  int vprintf( <[fmt]>, <[list]>)
38  char *<[fmt]>;
39  va_list <[list]>;
40 
41  int vfprintf(<[fp]>, <[fmt]>, <[list]>)
42  FILE *<[fp]>;
43  char *<[fmt]>;
44  va_list <[list]>;
45 
46  int vasprintf(<[strp]>, <[fmt]>, <[list]>)
47  char **<[strp]>;
48  char *<[fmt]>;
49  va_list <[list]>;
50 
51  int vsprintf(<[str]>, <[fmt]>, <[list]>)
52  char *<[str]>;
53  char *<[fmt]>;
54  va_list <[list]>;
55 
56  int vsnprintf(<[str]>, <[size]>, <[fmt]>, <[list]>)
57  char *<[str]>;
58  size_t <[size]>;
59  char *<[fmt]>;
60  va_list <[list]>;
61 
62  int _vprintf_r(<[reent]>, <[fmt]>, <[list]>)
63  char *<[reent]>;
64  char *<[fmt]>;
65  va_list <[list]>;
66 
67  int _vfprintf_r(<[reent]>, <[fp]>, <[fmt]>, <[list]>)
68  char *<[reent]>;
69  FILE *<[fp]>;
70  char *<[fmt]>;
71  va_list <[list]>;
72 
73  int _vasprintf_r(<[reent]>, <[strp]>, <[fmt]>, <[list]>)
74  char *<[reent]>;
75  char **<[strp]>;
76  char *<[fmt]>;
77  va_list <[list]>;
78 
79  int _vsprintf_r(<[reent]>, <[str]>, <[fmt]>, <[list]>)
80  char *<[reent]>;
81  char *<[str]>;
82  char *<[fmt]>;
83  va_list <[list]>;
84 
85  int _vsnprintf_r(<[reent]>, <[str]>, <[size]>, <[fmt]>, <[list]>)
86  char *<[reent]>;
87  char *<[str]>;
88  size_t <[size]>;
89  char *<[fmt]>;
90  va_list <[list]>;
91 
92 DESCRIPTION
93 <<vprintf>>, <<vfprintf>>, <<vasprintf>>, <<vsprintf>> and <<vsnprintf>> are
94 (respectively) variants of <<printf>>, <<fprintf>>, <<asprintf>>, <<sprintf>>,
95 and <<snprintf>>. They differ only in allowing their caller to pass the
96 variable argument list as a <<va_list>> object (initialized by <<va_start>>)
97 rather than directly accepting a variable number of arguments.
98 
99 RETURNS
100 The return values are consistent with the corresponding functions:
101 <<vasprintf>>/<<vsprintf>> returns the number of bytes in the output string,
102 save that the concluding <<NULL>> is not counted.
103 <<vprintf>> and <<vfprintf>> return the number of characters transmitted.
104 If an error occurs, <<vprintf>> and <<vfprintf>> return <<EOF>> and
105 <<vasprintf>> returns -1. No error returns occur for <<vsprintf>>.
106 
107 PORTABILITY
108 ANSI C requires all three functions.
109 
110 Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
111 <<lseek>>, <<read>>, <<sbrk>>, <<write>>.
112 */
113 
114 /*
115  * Copyright (c) 1990 The Regents of the University of California.
116  * All rights reserved.
117  *
118  * This code is derived from software contributed to Berkeley by
119  * Chris Torek.
120  *
121  * Redistribution and use in source and binary forms, with or without
122  * modification, are permitted provided that the following conditions
123  * are met:
124  * 1. Redistributions of source code must retain the above copyright
125  * notice, this list of conditions and the following disclaimer.
126  * 2. Redistributions in binary form must reproduce the above copyright
127  * notice, this list of conditions and the following disclaimer in the
128  * documentation and/or other materials provided with the distribution.
129  * 3. All advertising materials mentioning features or use of this software
130  * must display the following acknowledgement:
131  * This product includes software developed by the University of
132  * California, Berkeley and its contributors.
133  * 4. Neither the name of the University nor the names of its contributors
134  * may be used to endorse or promote products derived from this software
135  * without specific prior written permission.
136  *
137  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
138  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
139  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
140  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
141  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
142  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
143  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
144  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
145  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
146  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
147  * SUCH DAMAGE.
148  */
149 
150 #if defined(LIBC_SCCS) && !defined(lint)
151 static char *sccsid = "from: @(#)vfprintf.c 5.50 (Berkeley) 12/16/92";
152 #endif /* LIBC_SCCS and not lint */
153 
154 /*
155  * Actual printf innards.
156  *
157  * This code is large and complicated...
158  */
159 
160 
161 #ifdef _SMALL_PRINTF
162 #define _NO_LONGDBL
163 #endif
164 
165 
166 #ifdef INTEGER_ONLY
167  #define VFPRINTF vfiprintf
168  #define _VFPRINTF_R _vfiprintf_r
169 #else
170  #define VFPRINTF vfprintf
171  #define _VFPRINTF_R _vfprintf_r
172  #ifndef NO_FLOATING_POINT
173  #define FLOATING_POINT
174  #endif
175 #endif
176 
177 #define _NO_LONGLONG
178 #if defined WANT_PRINTF_LONG_LONG && defined __GNUC__
179 # undef _NO_LONGLONG
180 #endif
181 
182 #define _NO_POS_ARGS
183 #if defined WANT_IO_POS_ARGS
184 # undef _NO_POS_ARGS
185 #endif
186 
187 #include <_ansi.h>
188 #include <stdio.h>
189 #include <stdlib.h>
190 #include <string.h>
191 #include <limits.h>
192 #include <reent.h>
193 #include <wchar.h>
194 #include <string.h>
195 #include <sys/lock.h>
196 
197 #ifdef _HAVE_STDC
198 #include <stdarg.h>
199 #else
200 #include <varargs.h>
201 #endif
202 
203 #ifndef _SMALL_PRINTF
204  #include "local.h"
205  #include "fvwrite.h"
206 #else
207  #define MAXBUFLOC 80
208 #endif
209 
210  #include "vfieeefp.h"
211 
212 /* Currently a test is made to see if long double processing is warranted.
213  This could be changed in the future should the _ldtoa_r code be
214  preferred over _dtoa_r. */
215 #define _NO_LONGDBL
216 #if defined WANT_IO_LONG_DBL && (LDBL_MANT_DIG > DBL_MANT_DIG)
217 # undef _NO_LONGDBL
218 #endif
219 
220 
221 #ifndef _SMALL_PRINTF
222 /*
223  * Flush out all the vectors defined by the given uio,
224  * then reset it so that it can be reused.
225  */
226 static int
227 __sprint(fp, uio)
228  FILE *fp;
229  register struct __suio *uio;
230 {
231  register int err;
232 
233  if (uio->uio_resid == 0) {
234  uio->uio_iovcnt = 0;
235  return (0);
236  }
237  err = __sfvwrite(fp, uio);
238  uio->uio_resid = 0;
239  uio->uio_iovcnt = 0;
240  return (err);
241 }
242 
243 /*
244  * Helper function for `fprintf to unbuffered unix file': creates a
245  * temporary buffer. We only work on write-only files; this avoids
246  * worries about ungetc buffers and so forth.
247  */
248 static int
249 __sbprintf(fp, fmt, ap)
250  register FILE *fp;
251  const char *fmt;
252  va_list ap;
253 {
254  int ret;
255  FILE fake;
256  unsigned char buf[BUFSIZ];
257 
258  /* copy the important variables */
259  fake._flags = fp->_flags & ~__SNBF;
260  fake._file = fp->_file;
261  fake._cookie = fp->_cookie;
262  fake._write = fp->_write;
263 
264  /* set up the buffer */
265  fake._bf._base = fake._p = buf;
266  fake._bf._size = fake._w = sizeof(buf);
267  fake._lbfsize = 0; /* not actually used, but Just In Case */
268 #ifndef __SINGLE_THREAD__
269  __lock_init_recursive (*(_LOCK_RECURSIVE_T *)&fake._lock);
270 #endif
271 
272  /* do the work, then copy any error status */
273  ret = VFPRINTF(&fake, fmt, ap);
274  if (ret >= 0 && fflush(&fake))
275  ret = EOF;
276  if (fake._flags & __SERR)
277  fp->_flags |= __SERR;
278 
279 #ifndef __SINGLE_THREAD__
280  __lock_close_recursive (*(_LOCK_RECURSIVE_T *)&fake._lock);
281 #endif
282  return (ret);
283 }
284 #endif
285 
286 
287 
288 #ifdef FLOATING_POINT
289 #include <locale.h>
290 #include <math.h>
291 #include "floatio.h"
292 
293 #if ((MAXEXP+MAXFRACT+1) > MB_LEN_MAX)
294 # define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
295 #else
296 # define BUF MB_LEN_MAX
297 #endif
298 
299 #define DEFPREC 6
300 
301 #ifdef _NO_LONGDBL
302 static char *cvt _PARAMS((struct _reent *, double, int, int, char *, int *, int, int *));
303 #else
304 static char *cvt _PARAMS((struct _reent *, _LONG_DOUBLE, int, int, char *, int *, int, int *));
305 extern int _ldcheck _PARAMS((_LONG_DOUBLE *));
306 #endif
307 
308 static int exponent _PARAMS((char *, int, int));
309 
310 #else /* no FLOATING_POINT */
311 
312 #define BUF 40
313 
314 #endif /* FLOATING_POINT */
315 
316 #ifndef _NO_LONGLONG
317 #define quad_t long long
318 #define u_quad_t unsigned long long
319 #else
320 #define quad_t long
321 #define u_quad_t unsigned long
322 #endif
323 
324 typedef quad_t * quad_ptr_t;
325 typedef void * void_ptr_t;
326 typedef char * char_ptr_t;
327 typedef long * long_ptr_t;
328 typedef int * int_ptr_t;
329 typedef short * short_ptr_t;
330 
331 #ifndef _NO_POS_ARGS
332 #define MAX_POS_ARGS 32
333 
334 union arg_val
335 {
336  int val_int;
337  u_int val_u_int;
338  long val_long;
339  u_long val_u_long;
340  float val_float;
341  double val_double;
342  _LONG_DOUBLE val__LONG_DOUBLE;
343  int_ptr_t val_int_ptr_t;
344  short_ptr_t val_short_ptr_t;
345  long_ptr_t val_long_ptr_t;
346  char_ptr_t val_char_ptr_t;
347  quad_ptr_t val_quad_ptr_t;
348  void_ptr_t val_void_ptr_t;
349  quad_t val_quad_t;
350  u_quad_t val_u_quad_t;
351  wint_t val_wint_t;
352 };
353 
354 static union arg_val *get_arg (struct _reent *data, int n, char *fmt,
355  va_list *ap, int *numargs, union arg_val *args,
356  int *arg_type, char **last_fmt);
357 #endif /* !_NO_POS_ARGS */
358 
359 /*
360  * Macros for converting digits to letters and vice versa
361  */
362 #define to_digit(c) ((c) - '0')
363 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
364 #define to_char(n) ((n) + '0')
365 
366 /*
367  * Flags used during conversion.
368  */
369 #define ALT 0x001 /* alternate form */
370 #define HEXPREFIX 0x002 /* add 0x or 0X prefix */
371 #define LADJUST 0x004 /* left adjustment */
372 #define LONGDBL 0x008 /* long double */
373 #define LONGINT 0x010 /* long integer */
374 #ifndef _NO_LONGLONG
375 #define QUADINT 0x020 /* quad integer */
376 #else /* ifdef _NO_LONGLONG, make QUADINT equivalent to LONGINT, so
377  that %lld behaves the same as %ld, not as %d, as expected if:
378  sizeof (long long) = sizeof long > sizeof int */
379 #define QUADINT LONGINT
380 #endif
381 #define SHORTINT 0x040 /* short integer */
382 #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
383 #define FPT 0x100 /* Floating point number */
384 
385 
386  int _EXFUN (_VFPRINTF_R, (struct _reent *, FILE *, _CONST char *, va_list));
387 
388  int
389  _DEFUN (VFPRINTF, (fp, fmt0, ap),
390  FILE * fp _AND
391  _CONST char *fmt0 _AND
392  va_list ap)
393  {
394  int result;
395  _flockfile(fp);
396 #ifndef _SMALL_PRINTF
397  CHECK_INIT (fp);
398 #endif
399  result = _VFPRINTF_R (_REENT, fp, fmt0, ap);
400  _funlockfile(fp);
401  return result;
402  }
403 
404 
405 
406 int
407 _DEFUN (_VFPRINTF_R, (data, fp, fmt0, ap),
408  struct _reent *data _AND
409  FILE * fp _AND
410  _CONST char *fmt0 _AND
411  va_list ap)
412 {
413  register char *fmt; /* format string */
414  register int ch; /* character from fmt */
415  register int n, m; /* handy integers (short term usage) */
416  register char *cp; /* handy char pointer (short term usage) */
417  register struct __siov *iovp;/* for PRINT macro */
418  register int flags; /* flags as above */
419  char *fmt_anchor; /* current format spec being processed */
420  int N; /* arg number */
421  int arg_index; /* index into args processed directly */
422 #ifndef _NO_POS_ARGS
423  int numargs; /* number of varargs read */
424  char *saved_fmt; /* saved fmt pointer */
425  union arg_val args[MAX_POS_ARGS];
426  int arg_type[MAX_POS_ARGS];
427  int is_pos_arg; /* is current format positional? */
428  int old_is_pos_arg; /* is current format positional? */
429 #endif
430  int ret; /* return value accumulator */
431  int width; /* width from format (%8d), or 0 */
432  int prec; /* precision from format (%.3d), or -1 */
433  char sign; /* sign prefix (' ', '+', '-', or \0) */
434 #ifdef FLOATING_POINT
435 #ifdef _SMALL_PRINTF
436  char *decimal_point = ".";
437 #else
438  char *decimal_point = localeconv()->decimal_point;
439 #endif
440  char softsign; /* temporary negative sign for floats */
441 #ifdef _NO_LONGDBL
442  union { int i; double d; } _double_ = {0};
443  #define _fpvalue (_double_.d)
444 #else
445  union { int i; _LONG_DOUBLE ld; } _long_double_ = {0};
446  #define _fpvalue (_long_double_.ld)
447  int tmp;
448 #endif
449  int expt; /* integer value of exponent */
450  int expsize = 0; /* character count for expstr */
451  int ndig; /* actual number of digits returned by cvt */
452  char expstr[7]; /* buffer for exponent string */
453 #endif
454  u_quad_t _uquad; /* integer arguments %[diouxX] */
455  enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
456  int dprec; /* a copy of prec if [diouxX], 0 otherwise */
457  int realsz; /* field size expanded by dprec */
458  int size; /* size of converted field or string */
459  char *xdigs = NULL; /* digits for [xX] conversion */
460 #ifndef _SMALL_PRINTF
461  #define NIOV 8
462  struct __suio uio; /* output information: summary */
463  struct __siov iov[NIOV];/* ... and individual io vectors */
464  char *malloc_buf = NULL;/* handy pointer for malloced buffers */
465 #else
466  char malloc_buf [MAXBUFLOC]; /* local buffers */
467 #endif
468 
469  char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
470  char ox[2]; /* space for 0x hex-prefix */
471 #ifdef MB_CAPABLE
472  wchar_t wc;
473  mbstate_t state; /* mbtowc calls from library must not change state */
474 #endif
475 
476 
477  /*
478  * Choose PADSIZE to trade efficiency vs. size. If larger printf
479  * fields occur frequently, increase PADSIZE and make the initialisers
480  * below longer.
481  */
482 #define PADSIZE 16 /* pad chunk size */
483  static _CONST char blanks[PADSIZE] =
484  {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
485  static _CONST char zeroes[PADSIZE] =
486  {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
487 
488 #ifdef MB_CAPABLE
489  memset (&state, '\0', sizeof (state));
490 #endif
491 
492 #ifndef _SMALL_PRINTF
493  /*
494  * BEWARE, these `goto error' on error, and PAD uses `n'.
495  */
496  #define PRINT(ptr, len,f) { \
497  iovp->iov_base = (ptr); \
498  iovp->iov_len = (len); \
499  uio.uio_resid += (len); \
500  iovp++; \
501  if (++uio.uio_iovcnt >= NIOV) { \
502  if (__sprint(fp, &uio)) \
503  goto error; \
504  iovp = iov; \
505  } \
506  }
507  #define PAD(howmany, with,f) { \
508  if ((n = (howmany)) > 0) { \
509  while (n > PADSIZE) { \
510  PRINT(with, PADSIZE,f); \
511  n -= PADSIZE; \
512  } \
513  PRINT(with, n,f); \
514  } \
515  }
516  #define FLUSH() { \
517  if (uio.uio_resid && __sprint(fp, &uio)) \
518  goto error; \
519  uio.uio_iovcnt = 0; \
520  iovp = iov; \
521  }
522 #else
523  //Macros for _SMALL_PRINTF
524  void _SMALL_PRINTF_puts(const char *ptr, int len, FILE *f);
525  #define PRINT(ptr, len, f) {_SMALL_PRINTF_puts(ptr,len,f);}
526  #define PAD(howmany, with, f) { \
527  if ((n = (howmany)) > 0) { \
528  while (n > PADSIZE) { \
529  PRINT(with, PADSIZE,f); \
530  n -= PADSIZE; \
531  } \
532  PRINT(with, n, f); \
533  } \
534  }
535  #define FLUSH() { ; }
536 #endif
537 
538 
539  /* Macros to support positional arguments */
540 #ifndef _NO_POS_ARGS
541 #define GET_ARG(n, ap, type) \
542  ( is_pos_arg \
543  ? n < numargs \
544  ? args[n].val_##type \
545  : get_arg (data, n, fmt_anchor, &ap, &numargs, args, arg_type, &saved_fmt)->val_##type \
546  : arg_index++ < numargs \
547  ? args[n].val_##type \
548  : numargs < MAX_POS_ARGS \
549  ? args[numargs++].val_##type = va_arg(ap, type) \
550  : va_arg(ap, type) \
551  )
552 #else
553 #define GET_ARG(n, ap, type) (va_arg(ap, type))
554 #endif
555 
556  /*
557  * To extend shorts properly, we need both signed and unsigned
558  * argument extraction methods.
559  */
560 #ifndef _NO_LONGLONG
561 #define SARG() \
562  (flags&QUADINT ? GET_ARG(N, ap, quad_t) : \
563  flags&LONGINT ? GET_ARG(N, ap, long) : \
564  flags&SHORTINT ? (long)(short)GET_ARG(N, ap, int) : \
565  (long)GET_ARG(N, ap, int))
566 #define UARG() \
567  (flags&QUADINT ? GET_ARG(N, ap, u_quad_t) : \
568  flags&LONGINT ? GET_ARG(N, ap, u_long) : \
569  flags&SHORTINT ? (u_long)(u_short)GET_ARG(N, ap, int) : \
570  (u_long)GET_ARG(N, ap, u_int))
571 #else
572 #define SARG() \
573  (flags&LONGINT ? GET_ARG(N, ap, long) : \
574  flags&SHORTINT ? (long)(short)GET_ARG(N, ap, int) : \
575  (long)GET_ARG(N, ap, int))
576 #define UARG() \
577  (flags&LONGINT ? GET_ARG(N, ap, u_long) : \
578  flags&SHORTINT ? (u_long)(u_short)GET_ARG(N, ap, int) : \
579  (u_long)GET_ARG(N, ap, u_int))
580 #endif
581 
582 #ifndef _SMALL_PRINTF
583  /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
584  if (cantwrite(fp))
585  return (EOF);
586 
587  /* optimise fprintf(stderr) (and other unbuffered Unix files) */
588  if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
589  fp->_file >= 0)
590  return (__sbprintf(fp, fmt0, ap));
591 
592  uio.uio_iov = iovp = iov;
593  uio.uio_resid = 0;
594  uio.uio_iovcnt = 0;
595 #endif
596  fmt = (char *)fmt0;
597 
598  ret = 0;
599  arg_index = 0;
600 
601 #ifndef _NO_POS_ARGS
602  saved_fmt = NULL;
603  arg_type[0] = -1;
604  numargs = 0;
605  is_pos_arg = 0;
606 #endif
607 
608  /*
609  * Scan the format for conversions (`%' character).
610  */
611  for (;;) {
612  cp = fmt;
613 #ifdef MB_CAPABLE
614  while ((n = _mbtowc_r(data, &wc, fmt, MB_CUR_MAX, &state)) > 0) {
615  if (wc == '%')
616  break;
617  fmt += n;
618  }
619 #else
620  while (*fmt != '\0' && *fmt != '%')
621  fmt += 1;
622 #endif
623  if ((m = fmt - cp) != 0) {
624  PRINT(cp, m, fp);
625  ret += m;
626  }
627 #ifdef MB_CAPABLE
628  if (n <= 0)
629  goto done;
630 #else
631  if (*fmt == '\0')
632  goto done;
633 #endif
634  fmt_anchor = fmt;
635  fmt++; /* skip over '%' */
636 
637  flags = 0;
638  dprec = 0;
639  width = 0;
640  prec = -1;
641  sign = '\0';
642  N = arg_index;
643 #ifndef _NO_POS_ARGS
644  is_pos_arg = 0;
645 #endif
646 
647 rflag: ch = *fmt++;
648 reswitch: switch (ch) {
649  case ' ':
650  /*
651  * ``If the space and + flags both appear, the space
652  * flag will be ignored.''
653  * -- ANSI X3J11
654  */
655  if (!sign)
656  sign = ' ';
657  goto rflag;
658  case '#':
659  flags |= ALT;
660  goto rflag;
661  case '*':
662  n = N;
663 #ifndef _NO_POS_ARGS
664  /* we must check for positional arg used for dynamic width */
665  old_is_pos_arg = is_pos_arg;
666  is_pos_arg = 0;
667  if (is_digit(*fmt)) {
668  char *old_fmt = fmt;
669 
670  n = 0;
671  ch = *fmt++;
672  do {
673  n = 10 * n + to_digit(ch);
674  ch = *fmt++;
675  } while (is_digit(ch));
676 
677  if (ch == '$') {
678  if (n <= MAX_POS_ARGS) {
679  n -= 1;
680  is_pos_arg = 1;
681  }
682  else
683  goto error;
684  }
685  else {
686  fmt = old_fmt;
687  goto rflag;
688  }
689  }
690 #endif /* !_NO_POS_ARGS */
691 
692  /*
693  * ``A negative field width argument is taken as a
694  * - flag followed by a positive field width.''
695  * -- ANSI X3J11
696  * They don't exclude field widths read from args.
697  */
698  width = GET_ARG(n, ap, int);
699 #ifndef _NO_POS_ARGS
700  is_pos_arg = old_is_pos_arg;
701 #endif
702  if (width >= 0)
703  goto rflag;
704  width = -width;
705  /* FALLTHROUGH */
706  case '-':
707  flags |= LADJUST;
708  goto rflag;
709  case '+':
710  sign = '+';
711  goto rflag;
712  case '.':
713  if ((ch = *fmt++) == '*') {
714  n = N;
715 #ifndef _NO_POS_ARGS
716  /* we must check for positional arg used for dynamic width */
717  old_is_pos_arg = is_pos_arg;
718  is_pos_arg = 0;
719  if (is_digit(*fmt)) {
720  char *old_fmt = fmt;
721 
722  n = 0;
723  ch = *fmt++;
724  do {
725  n = 10 * n + to_digit(ch);
726  ch = *fmt++;
727  } while (is_digit(ch));
728 
729  if (ch == '$') {
730  if (n <= MAX_POS_ARGS) {
731  n -= 1;
732  is_pos_arg = 1;
733  }
734  else
735  goto error;
736  }
737  else {
738  fmt = old_fmt;
739  goto rflag;
740  }
741  }
742 #endif /* !_NO_POS_ARGS */
743  prec = GET_ARG(n, ap, int);
744 #ifndef _NO_POS_ARGS
745  is_pos_arg = old_is_pos_arg;
746 #endif
747  if (prec < 0)
748  prec = -1;
749  goto rflag;
750  }
751  n = 0;
752  while (is_digit(ch)) {
753  n = 10 * n + to_digit(ch);
754  ch = *fmt++;
755  }
756  prec = n < 0 ? -1 : n;
757  goto reswitch;
758  case '0':
759  /*
760  * ``Note that 0 is taken as a flag, not as the
761  * beginning of a field width.''
762  * -- ANSI X3J11
763  */
764  flags |= ZEROPAD;
765  goto rflag;
766  case '1': case '2': case '3': case '4':
767  case '5': case '6': case '7': case '8': case '9':
768  n = 0;
769  do {
770  n = 10 * n + to_digit(ch);
771  ch = *fmt++;
772  } while (is_digit(ch));
773 #ifndef _NO_POS_ARGS
774  if (ch == '$') {
775  if (n <= MAX_POS_ARGS) {
776  N = n - 1;
777  is_pos_arg = 1;
778  goto rflag;
779  }
780  else
781  goto error;
782  }
783 #endif /* !_NO_POS_ARGS */
784  width = n;
785  goto reswitch;
786 #ifdef FLOATING_POINT
787  case 'L':
788  flags |= LONGDBL;
789  goto rflag;
790 #endif
791  case 'h':
792  flags |= SHORTINT;
793  goto rflag;
794  case 'l':
795  if (*fmt == 'l') {
796  fmt++;
797  flags |= QUADINT;
798  } else {
799  flags |= LONGINT;
800  }
801  goto rflag;
802  case 'q':
803  flags |= QUADINT;
804  goto rflag;
805  case 'c':
806  case 'C':
807  cp = buf;
808  if (ch == 'C' || (flags & LONGINT)) {
809  mbstate_t ps;
810 
811  memset((void *)&ps, '\0', sizeof(mbstate_t));
812  if ((size = (int)_wcrtomb_r(data, cp,
813  (wchar_t)GET_ARG(N, ap, wint_t),
814  &ps)) == -1)
815  goto error;
816  }
817  else {
818  *cp = GET_ARG(N, ap, int);
819  size = 1;
820  }
821  sign = '\0';
822  break;
823  case 'D':
824  flags |= LONGINT;
825  /*FALLTHROUGH*/
826  case 'd':
827  case 'i':
828  _uquad = SARG();
829 #ifndef _NO_LONGLONG
830  if ((quad_t)_uquad < 0)
831 #else
832  if ((long) _uquad < 0)
833 #endif
834  {
835 
836  _uquad = -_uquad;
837  sign = '-';
838  }
839  base = DEC;
840  goto number;
841 #ifdef FLOATING_POINT
842  case 'e':
843  case 'E':
844  case 'f':
845  case 'g':
846  case 'G':
847  if (prec == -1) {
848  prec = DEFPREC;
849  } else if ((ch == 'g' || ch == 'G') && prec == 0) {
850  prec = 1;
851  }
852 
853 #ifdef _NO_LONGDBL
854  if (flags & LONGDBL) {
855  _fpvalue = (double) GET_ARG(N, ap, _LONG_DOUBLE);
856  } else {
857  _fpvalue = GET_ARG(N, ap, double);
858  }
859 
860  /* do this before tricky precision changes */
861  if (isinf(_fpvalue)) {
862  if (_fpvalue < 0)
863  sign = '-';
864  cp = "Inf";
865  size = 3;
866  break;
867  }
868  if (isnan(_fpvalue)) {
869  cp = "NaN";
870  size = 3;
871  break;
872  }
873 
874 #else /* !_NO_LONGDBL */
875 
876  if (flags & LONGDBL) {
877  _fpvalue = GET_ARG(N, ap, _LONG_DOUBLE);
878  } else {
879  _fpvalue = (_LONG_DOUBLE)GET_ARG(N, ap, double);
880  }
881 
882  /* do this before tricky precision changes */
883  tmp = _ldcheck (&_fpvalue);
884  if (tmp == 2) {
885  if (_fpvalue < 0)
886  sign = '-';
887  cp = "Inf";
888  size = 3;
889  break;
890  }
891  if (tmp == 1) {
892  cp = "NaN";
893  size = 3;
894  break;
895  }
896 #endif /* !_NO_LONGDBL */
897 
898  flags |= FPT;
899 
900  cp = cvt(data, _fpvalue, prec, flags, &softsign,
901  &expt, ch, &ndig);
902 
903  if (ch == 'g' || ch == 'G') {
904  if (expt <= -4 || expt > prec)
905  ch = (ch == 'g') ? 'e' : 'E';
906  else
907  ch = 'g';
908  }
909  if (ch <= 'e') { /* 'e' or 'E' fmt */
910  --expt;
911  expsize = exponent(expstr, expt, ch);
912  size = expsize + ndig;
913  if (ndig > 1 || flags & ALT)
914  ++size;
915  } else if (ch == 'f') { /* f fmt */
916  if (expt > 0) {
917  size = expt;
918  if (prec || flags & ALT)
919  size += prec + 1;
920  } else /* "0.X" */
921  size = (prec || flags & ALT)
922  ? prec + 2
923  : 1;
924  } else if (expt >= ndig) { /* fixed g fmt */
925  size = expt;
926  if (flags & ALT)
927  ++size;
928  } else
929  size = ndig + (expt > 0 ?
930  1 : 2 - expt);
931 
932  if (softsign)
933  sign = '-';
934  break;
935 #endif /* FLOATING_POINT */
936  case 'n':
937 #ifndef _NO_LONGLONG
938  if (flags & QUADINT)
939  *GET_ARG(N, ap, quad_ptr_t) = ret;
940  else
941 #endif
942  if (flags & LONGINT)
943  *GET_ARG(N, ap, long_ptr_t) = ret;
944  else if (flags & SHORTINT)
945  *GET_ARG(N, ap, short_ptr_t) = ret;
946  else
947  *GET_ARG(N, ap, int_ptr_t) = ret;
948  continue; /* no output */
949  case 'O':
950  flags |= LONGINT;
951  /*FALLTHROUGH*/
952  case 'o':
953  _uquad = UARG();
954  base = OCT;
955  goto nosign;
956  case 'p':
957  /*
958  * ``The argument shall be a pointer to void. The
959  * value of the pointer is converted to a sequence
960  * of printable characters, in an implementation-
961  * defined manner.''
962  * -- ANSI X3J11
963  */
964  /* NOSTRICT */
965  _uquad = (u_long)(unsigned _POINTER_INT)GET_ARG(N, ap, void_ptr_t);
966  base = HEX;
967  xdigs = "0123456789abcdef";
968  flags |= HEXPREFIX;
969  ch = 'x';
970  goto nosign;
971  case 's':
972  case 'S':
973  sign = '\0';
974  if ((cp = GET_ARG(N, ap, char_ptr_t)) == NULL) {
975  cp = "(null)";
976  size = 6;
977  }
978  else if (ch == 'S' || (flags & LONGINT)) {
979  mbstate_t ps;
980  _CONST wchar_t *wcp;
981 
982  wcp = (_CONST wchar_t *)cp;
983  size = m = 0;
984  memset((void *)&ps, '\0', sizeof(mbstate_t));
985 
986  /* Count number of bytes needed for multibyte
987  string that will be produced from widechar
988  string. */
989  if (prec >= 0) {
990  while (1) {
991  if (wcp[m] == L'\0')
992  break;
993  if ((n = (int)_wcrtomb_r(data,
994  buf, wcp[m], &ps)) == -1)
995  goto error;
996  if (n + size > prec)
997  break;
998  m += 1;
999  size += n;
1000  if (size == prec)
1001  break;
1002  }
1003  }
1004  else {
1005  if ((size = (int)_wcsrtombs_r(data,
1006  NULL, &wcp, 0, &ps)) == -1)
1007  goto error;
1008  wcp = (_CONST wchar_t *)cp;
1009  }
1010 
1011  if (size == 0)
1012  break;
1013 
1014  #ifndef _SMALL_PRINTF
1015  if ((malloc_buf =
1016  (char *)_malloc_r(data, size + 1)) == NULL)
1017  goto error;
1018  #endif
1019 
1020  /* Convert widechar string to multibyte string. */
1021  memset((void *)&ps, '\0', sizeof(mbstate_t));
1022  if (_wcsrtombs_r(data, malloc_buf, &wcp, size, &ps) != size)
1023  goto error;
1024  cp = malloc_buf;
1025  cp[size] = '\0';
1026  }
1027  else if (prec >= 0) {
1028  /*
1029  * can't use strlen; can only look for the
1030  * NUL in the first `prec' characters, and
1031  * strlen() will go further.
1032  */
1033  char *p = memchr(cp, 0, prec);
1034 
1035  if (p != NULL) {
1036  size = p - cp;
1037  if (size > prec)
1038  size = prec;
1039  } else
1040  size = prec;
1041  } else
1042  size = strlen(cp);
1043 
1044  break;
1045  case 'U':
1046  flags |= LONGINT;
1047  /*FALLTHROUGH*/
1048  case 'u':
1049  _uquad = UARG();
1050  base = DEC;
1051  goto nosign;
1052  case 'X':
1053  xdigs = "0123456789ABCDEF";
1054  goto hex;
1055  case 'x':
1056  xdigs = "0123456789abcdef";
1057 hex: _uquad = UARG();
1058  base = HEX;
1059  /* leading 0x/X only if non-zero */
1060  if (flags & ALT && _uquad != 0)
1061  flags |= HEXPREFIX;
1062 
1063  /* unsigned conversions */
1064 nosign: sign = '\0';
1065  /*
1066  * ``... diouXx conversions ... if a precision is
1067  * specified, the 0 flag will be ignored.''
1068  * -- ANSI X3J11
1069  */
1070 number: if ((dprec = prec) >= 0)
1071  flags &= ~ZEROPAD;
1072 
1073  /*
1074  * ``The result of converting a zero value with an
1075  * explicit precision of zero is no characters.''
1076  * -- ANSI X3J11
1077  */
1078  cp = buf + BUF;
1079  if (_uquad != 0 || prec != 0) {
1080  /*
1081  * Unsigned mod is hard, and unsigned mod
1082  * by a constant is easier than that by
1083  * a variable; hence this switch.
1084  */
1085  switch (base) {
1086  case OCT:
1087  do {
1088  *--cp = to_char(_uquad & 7);
1089  _uquad >>= 3;
1090  } while (_uquad);
1091  /* handle octal leading 0 */
1092  if (flags & ALT && *cp != '0')
1093  *--cp = '0';
1094  break;
1095 
1096  case DEC:
1097  /* many numbers are 1 digit */
1098  while (_uquad >= 10) {
1099  *--cp = to_char(_uquad % 10);
1100  _uquad /= 10;
1101  }
1102  *--cp = to_char(_uquad);
1103  break;
1104 
1105  case HEX:
1106  do {
1107  *--cp = xdigs[_uquad & 15];
1108  _uquad >>= 4;
1109  } while (_uquad);
1110  break;
1111 
1112  default:
1113  cp = "bug in vfprintf: bad base";
1114  size = strlen(cp);
1115  goto skipsize;
1116  }
1117  }
1118  /*
1119  * ...result is to be converted to an 'alternate form'.
1120  * For o conversion, it increases the precision to force
1121  * the first digit of the result to be a zero."
1122  * -- ANSI X3J11
1123  *
1124  * To demonstrate this case, compile and run:
1125  * printf ("%#.0o",0);
1126  */
1127  else if (base == OCT && (flags & ALT))
1128  *--cp = '0';
1129 
1130  size = buf + BUF - cp;
1131  skipsize:
1132  break;
1133  default: /* "%?" prints ?, unless ? is NUL */
1134  if (ch == '\0')
1135  goto done;
1136  /* pretend it was %c with argument ch */
1137  cp = buf;
1138  *cp = ch;
1139  size = 1;
1140  sign = '\0';
1141  break;
1142  }
1143 
1144  /*
1145  * All reasonable formats wind up here. At this point, `cp'
1146  * points to a string which (if not flags&LADJUST) should be
1147  * padded out to `width' places. If flags&ZEROPAD, it should
1148  * first be prefixed by any sign or other prefix; otherwise,
1149  * it should be blank padded before the prefix is emitted.
1150  * After any left-hand padding and prefixing, emit zeroes
1151  * required by a decimal [diouxX] precision, then print the
1152  * string proper, then emit zeroes required by any leftover
1153  * floating precision; finally, if LADJUST, pad with blanks.
1154  *
1155  * Compute actual size, so we know how much to pad.
1156  * size excludes decimal prec; realsz includes it.
1157  */
1158  realsz = dprec > size ? dprec : size;
1159  if (sign)
1160  realsz++;
1161  else if (flags & HEXPREFIX)
1162  realsz+= 2;
1163 
1164  /* right-adjusting blank padding */
1165  if ((flags & (LADJUST|ZEROPAD)) == 0)
1166  PAD(width - realsz, blanks, fp);
1167 
1168  /* prefix */
1169  if (sign) {
1170  PRINT(&sign, 1, fp);
1171  } else if (flags & HEXPREFIX) {
1172  ox[0] = '0';
1173  ox[1] = ch;
1174  PRINT(ox, 2 ,fp);
1175  }
1176 
1177  /* right-adjusting zero padding */
1178  if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
1179  PAD(width - realsz, zeroes, fp);
1180 
1181  /* leading zeroes from decimal precision */
1182  PAD(dprec - size, zeroes, fp);
1183 
1184  /* the string or number proper */
1185 #ifdef FLOATING_POINT
1186  if ((flags & FPT) == 0) {
1187  PRINT(cp, size, fp);
1188  } else { /* glue together f_p fragments */
1189  if (ch >= 'f') { /* 'f' or 'g' */
1190  if (_fpvalue == 0) {
1191  /* kludge for __dtoa irregularity */
1192  PRINT("0", 1, fp);
1193  if (expt < ndig || (flags & ALT) != 0) {
1194  PRINT(decimal_point, 1, fp);
1195  PAD(ndig - 1, zeroes, fp);
1196  }
1197  } else if (expt <= 0) {
1198  PRINT("0", 1, fp);
1199  if(expt || ndig) {
1200  PRINT(decimal_point, 1, fp);
1201  PAD(-expt, zeroes, fp);
1202  PRINT(cp, ndig, fp);
1203  }
1204  } else if (expt >= ndig) {
1205  PRINT(cp, ndig, fp);
1206  PAD(expt - ndig, zeroes, fp);
1207  if (flags & ALT)
1208  PRINT(".", 1, fp);
1209  } else {
1210  PRINT(cp, expt, fp);
1211  cp += expt;
1212  PRINT(".", 1, fp);
1213  PRINT(cp, ndig-expt, fp);
1214  }
1215  } else { /* 'e' or 'E' */
1216  if (ndig > 1 || flags & ALT) {
1217  ox[0] = *cp++;
1218  ox[1] = '.';
1219  PRINT(ox, 2, fp);
1220  if (_fpvalue) {
1221  PRINT(cp, ndig-1, fp);
1222  } else /* 0.[0..] */
1223  /* __dtoa irregularity */
1224  PAD(ndig - 1, zeroes, fp);
1225  } else /* XeYYY */
1226  PRINT(cp, 1, fp);
1227  PRINT(expstr, expsize, fp);
1228  }
1229  }
1230 #else
1231  PRINT(cp, size, fp);
1232 #endif
1233  /* left-adjusting padding (always blank) */
1234  if (flags & LADJUST)
1235  PAD(width - realsz, blanks, fp);
1236 
1237  /* finally, adjust ret */
1238  ret += width > realsz ? width : realsz;
1239 
1240  FLUSH(); /* copy out the I/O vectors */
1241 
1242 #ifndef _SMALL_PRINTF
1243  if (malloc_buf != NULL) {
1244  free(malloc_buf);
1245  malloc_buf = NULL;
1246  }
1247 #endif
1248  }
1249 done:
1250  FLUSH();
1251 error:
1252 
1253 #ifndef _SMALL_PRINTF
1254  if (malloc_buf != NULL)
1255  free(malloc_buf);
1256  return (__sferror(fp) ? EOF : ret);
1257 #else
1258  return ret;
1259 #endif
1260  /* NOTREACHED */
1261 }
1262 
1263 #ifdef FLOATING_POINT
1264 
1265 #ifdef _NO_LONGDBL
1266 extern char *_dtoa_r _PARAMS((struct _reent *, double, int,
1267  int, int *, int *, char **));
1268 #else
1269 extern char *_ldtoa_r _PARAMS((struct _reent *, _LONG_DOUBLE, int,
1270  int, int *, int *, char **));
1271 #undef word0
1272 #define word0(x) ldword0(x)
1273 #endif
1274 
1275 static char *
1276 cvt(data, value, ndigits, flags, sign, decpt, ch, length)
1277  struct _reent *data;
1278 #ifdef _NO_LONGDBL
1279  double value;
1280 #else
1281  _LONG_DOUBLE value;
1282 #endif
1283  int ndigits, flags, *decpt, ch, *length;
1284  char *sign;
1285 {
1286  int mode, dsgn;
1287  char *digits, *bp, *rve;
1288 #ifdef _NO_LONGDBL
1289  union double_union tmp;
1290 #else
1291  struct ldieee *ldptr;
1292 #endif
1293 
1294  if (ch == 'f') {
1295  mode = 3; /* ndigits after the decimal point */
1296  } else {
1297  /* To obtain ndigits after the decimal point for the 'e'
1298  * and 'E' formats, round to ndigits + 1 significant
1299  * figures.
1300  */
1301  if (ch == 'e' || ch == 'E') {
1302  ndigits++;
1303  }
1304  mode = 2; /* ndigits significant digits */
1305  }
1306 
1307 #ifdef _NO_LONGDBL
1308  tmp.d = value;
1309 
1310  if (word0(tmp) & Sign_bit) { /* this will check for < 0 and -0.0 */
1311  value = -value;
1312  *sign = '-';
1313  } else
1314  *sign = '\000';
1315 
1316  digits = _dtoa_r(data, value, mode, ndigits, decpt, &dsgn, &rve);
1317 #else /* !_NO_LONGDBL */
1318  ldptr = (struct ldieee *)&value;
1319  if (ldptr->sign) { /* this will check for < 0 and -0.0 */
1320  value = -value;
1321  *sign = '-';
1322  } else
1323  *sign = '\000';
1324 
1325  digits = _ldtoa_r(data, value, mode, ndigits, decpt, &dsgn, &rve);
1326 #endif /* !_NO_LONGDBL */
1327 
1328  if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */
1329  bp = digits + ndigits;
1330  if (ch == 'f') {
1331  if (*digits == '0' && value)
1332  *decpt = -ndigits + 1;
1333  bp += *decpt;
1334  }
1335  if (value == 0) /* kludge for __dtoa irregularity */
1336  rve = bp;
1337  while (rve < bp)
1338  *rve++ = '0';
1339  }
1340  *length = rve - digits;
1341  return (digits);
1342 }
1343 
1344 static int
1345 exponent(p0, exp, fmtch)
1346  char *p0;
1347  int exp, fmtch;
1348 {
1349  register char *p, *t;
1350  char expbuf[40];
1351 
1352  p = p0;
1353  *p++ = fmtch;
1354  if (exp < 0) {
1355  exp = -exp;
1356  *p++ = '-';
1357  }
1358  else
1359  *p++ = '+';
1360  t = expbuf + 40;
1361  if (exp > 9) {
1362  do {
1363  *--t = to_char(exp % 10);
1364  } while ((exp /= 10) > 9);
1365  *--t = to_char(exp);
1366  for (; t < expbuf + 40; *p++ = *t++);
1367  }
1368  else {
1369  *p++ = '0';
1370  *p++ = to_char(exp);
1371  }
1372  return (p - p0);
1373 }
1374 #endif /* FLOATING_POINT */
1375 
1376 
1377 #ifndef _NO_POS_ARGS
1378 
1379 /* Positional argument support.
1380  Written by Jeff Johnston
1381 
1382  Copyright (c) 2002 Red Hat Incorporated.
1383  All rights reserved.
1384 
1385  Redistribution and use in source and binary forms, with or without
1386  modification, are permitted provided that the following conditions are met:
1387 
1388  Redistributions of source code must retain the above copyright
1389  notice, this list of conditions and the following disclaimer.
1390 
1391  Redistributions in binary form must reproduce the above copyright
1392  notice, this list of conditions and the following disclaimer in the
1393  documentation and/or other materials provided with the distribution.
1394 
1395  The name of Red Hat Incorporated may not be used to endorse
1396  or promote products derived from this software without specific
1397  prior written permission.
1398 
1399  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1400  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1401  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1402  DISCLAIMED. IN NO EVENT SHALL RED HAT INCORPORATED BE LIABLE FOR ANY
1403  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1404  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1405  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1406  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1407  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1408  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
1409 
1410 typedef enum {
1411  ZERO, /* '0' */
1412  DIGIT, /* '1-9' */
1413  DOLLAR, /* '$' */
1414  MODFR, /* spec modifier */
1415  SPEC, /* format specifier */
1416  DOT, /* '.' */
1417  STAR, /* '*' */
1418  FLAG, /* format flag */
1419  OTHER, /* all other chars */
1420  MAX_CH_CLASS /* place-holder */
1421 } CH_CLASS;
1422 
1423 typedef enum {
1424  START, /* start */
1425  SFLAG, /* seen a flag */
1426  WDIG, /* seen digits in width area */
1427  WIDTH, /* processed width */
1428  SMOD, /* seen spec modifier */
1429  SDOT, /* seen dot */
1430  VARW, /* have variable width specifier */
1431  VARP, /* have variable precision specifier */
1432  PREC, /* processed precision */
1433  VWDIG, /* have digits in variable width specification */
1434  VPDIG, /* have digits in variable precision specification */
1435  DONE, /* done */
1436  MAX_STATE, /* place-holder */
1437 } STATE;
1438 
1439 typedef enum {
1440  NOOP, /* do nothing */
1441  NUMBER, /* build a number from digits */
1442  SKIPNUM, /* skip over digits */
1443  GETMOD, /* get and process format modifier */
1444  GETARG, /* get and process argument */
1445  GETPW, /* get variable precision or width */
1446  GETPWB, /* get variable precision or width and pushback fmt char */
1447  GETPOS, /* get positional parameter value */
1448  PWPOS, /* get positional parameter value for variable width or precision */
1449 } ACTION;
1450 
1451 const static CH_CLASS chclass[256] = {
1452  /* 00-07 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1453  /* 08-0f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1454  /* 10-17 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1455  /* 18-1f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1456  /* 20-27 */ FLAG, OTHER, OTHER, FLAG, DOLLAR, OTHER, OTHER, OTHER,
1457  /* 28-2f */ OTHER, OTHER, STAR, FLAG, OTHER, FLAG, DOT, OTHER,
1458  /* 30-37 */ ZERO, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT,
1459  /* 38-3f */ DIGIT, DIGIT, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1460  /* 40-47 */ OTHER, OTHER, OTHER, SPEC, SPEC, SPEC, OTHER, SPEC,
1461  /* 48-4f */ OTHER, OTHER, OTHER, OTHER, MODFR, OTHER, OTHER, SPEC,
1462  /* 50-57 */ OTHER, OTHER, OTHER, SPEC, OTHER, SPEC, OTHER, SPEC,
1463  /* 58-5f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1464  /* 60-67 */ OTHER, OTHER, OTHER, SPEC, SPEC, SPEC, SPEC, SPEC,
1465  /* 68-6f */ MODFR, SPEC, OTHER, OTHER, MODFR, OTHER, OTHER, SPEC,
1466  /* 70-77 */ SPEC, MODFR, OTHER, SPEC, OTHER, SPEC, OTHER, OTHER,
1467  /* 78-7f */ SPEC, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1468  /* 80-87 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1469  /* 88-8f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1470  /* 90-97 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1471  /* 98-9f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1472  /* a0-a7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1473  /* a8-af */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1474  /* b0-b7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1475  /* b8-bf */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1476  /* c0-c7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1477  /* c8-cf */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1478  /* d0-d7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1479  /* d8-df */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1480  /* e0-e7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1481  /* e8-ef */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1482  /* f0-f7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1483  /* f8-ff */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1484 };
1485 
1486 const static STATE state_table[MAX_STATE][MAX_CH_CLASS] = {
1487  /* '0' '1-9' '$' MODFR SPEC '.' '*' FLAG OTHER */
1488  /* START */ { SFLAG, WDIG, DONE, SMOD, DONE, SDOT, VARW, SFLAG, DONE },
1489  /* SFLAG */ { SFLAG, WDIG, DONE, SMOD, DONE, SDOT, VARW, SFLAG, DONE },
1490  /* WDIG */ { DONE, DONE, WIDTH, SMOD, DONE, SDOT, DONE, DONE, DONE },
1491  /* WIDTH */ { DONE, DONE, DONE, SMOD, DONE, SDOT, DONE, DONE, DONE },
1492  /* SMOD */ { DONE, DONE, DONE, DONE, DONE, DONE, DONE, DONE, DONE },
1493  /* SDOT */ { SDOT, PREC, DONE, SMOD, DONE, DONE, VARP, DONE, DONE },
1494  /* VARW */ { DONE, VWDIG, DONE, SMOD, DONE, SDOT, DONE, DONE, DONE },
1495  /* VARP */ { DONE, VPDIG, DONE, SMOD, DONE, DONE, DONE, DONE, DONE },
1496  /* PREC */ { DONE, DONE, DONE, SMOD, DONE, DONE, DONE, DONE, DONE },
1497  /* VWDIG */ { DONE, DONE, WIDTH, DONE, DONE, DONE, DONE, DONE, DONE },
1498  /* VPDIG */ { DONE, DONE, PREC, DONE, DONE, DONE, DONE, DONE, DONE },
1499 };
1500 
1501 const static ACTION action_table[MAX_STATE][MAX_CH_CLASS] = {
1502  /* '0' '1-9' '$' MODFR SPEC '.' '*' FLAG OTHER */
1503  /* START */ { NOOP, NUMBER, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP },
1504  /* SFLAG */ { NOOP, NUMBER, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP },
1505  /* WDIG */ { NOOP, NOOP, GETPOS, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP },
1506  /* WIDTH */ { NOOP, NOOP, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP },
1507  /* SMOD */ { NOOP, NOOP, NOOP, NOOP, GETARG, NOOP, NOOP, NOOP, NOOP },
1508  /* SDOT */ { NOOP, SKIPNUM, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP },
1509  /* VARW */ { NOOP, NUMBER, NOOP, GETPW, GETPWB, GETPW, NOOP, NOOP, NOOP },
1510  /* VARP */ { NOOP, NUMBER, NOOP, GETPW, GETPWB, NOOP, NOOP, NOOP, NOOP },
1511  /* PREC */ { NOOP, NOOP, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP },
1512  /* VWDIG */ { NOOP, NOOP, PWPOS, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP },
1513  /* VPDIG */ { NOOP, NOOP, PWPOS, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP },
1514 };
1515 
1516 /* function to get positional parameter N where n = N - 1 */
1517 static union arg_val *
1518 get_arg (struct _reent *data, int n, char *fmt, va_list *ap,
1519  int *numargs_p, union arg_val *args,
1520  int *arg_type, char **last_fmt)
1521 {
1522  int ch;
1523  int number, flags;
1524  int spec_type;
1525  int numargs = *numargs_p;
1526  CH_CLASS chtype;
1527  STATE state, next_state;
1528  ACTION action;
1529  int pos, last_arg;
1530  int max_pos_arg = n;
1531  enum types { INT, LONG_INT, SHORT_INT, QUAD_INT, CHAR, CHAR_PTR, DOUBLE, LONG_DOUBLE, WIDE_CHAR };
1532 #ifdef MB_CAPABLE
1533  wchar_t wc;
1534  mbstate_t wc_state;
1535  int nbytes;
1536 #endif
1537 
1538  /* if this isn't the first call, pick up where we left off last time */
1539  if (*last_fmt != NULL)
1540  fmt = *last_fmt;
1541 
1542 #ifdef MB_CAPABLE
1543  memset (&wc_state, '\0', sizeof (wc_state));
1544 #endif
1545 
1546  /* we need to process either to end of fmt string or until we have actually
1547  read the desired parameter from the vararg list. */
1548  while (*fmt && n >= numargs)
1549  {
1550 #ifdef MB_CAPABLE
1551  while ((nbytes = _mbtowc_r(data, &wc, fmt, MB_CUR_MAX, &wc_state)) > 0)
1552  {
1553  fmt += nbytes;
1554  if (wc == '%')
1555  break;
1556  }
1557 
1558  if (nbytes <= 0)
1559  break;
1560 #else
1561  while (*fmt != '\0' && *fmt != '%')
1562  fmt += 1;
1563 
1564  if (*fmt == '\0')
1565  break;
1566 #endif
1567  state = START;
1568  flags = 0;
1569  pos = -1;
1570  number = 0;
1571  spec_type = INT;
1572 
1573  /* Use state/action table to process format specifiers. We ignore invalid
1574  formats and we are only interested in information that tells us how to
1575  read the vararg list. */
1576  while (state != DONE)
1577  {
1578  ch = *fmt++;
1579  chtype = chclass[ch];
1580  next_state = state_table[state][chtype];
1581  action = action_table[state][chtype];
1582  state = next_state;
1583 
1584  switch (action)
1585  {
1586  case GETMOD: /* we have format modifier */
1587  switch (ch)
1588  {
1589  case 'h':
1590  flags |= SHORTINT;
1591  break;
1592  case 'L':
1593  flags |= LONGDBL;
1594  break;
1595  case 'q':
1596  flags |= QUADINT;
1597  break;
1598  case 'l':
1599  default:
1600  if (*fmt == 'l')
1601  {
1602  flags |= QUADINT;
1603  ++fmt;
1604  }
1605  else
1606  flags |= LONGINT;
1607  break;
1608  }
1609  break;
1610  case GETARG: /* we have format specifier */
1611  {
1612  numargs &= (MAX_POS_ARGS - 1);
1613  /* process the specifier and translate it to a type to fetch from varargs */
1614  switch (ch)
1615  {
1616  case 'd':
1617  case 'i':
1618  case 'o':
1619  case 'x':
1620  case 'X':
1621  case 'u':
1622  if (flags & LONGINT)
1623  spec_type = LONG_INT;
1624  else if (flags & SHORTINT)
1625  spec_type = SHORT_INT;
1626 #ifndef _NO_LONGLONG
1627  else if (flags & QUADINT)
1628  spec_type = QUAD_INT;
1629 #endif
1630  else
1631  spec_type = INT;
1632  break;
1633  case 'D':
1634  case 'U':
1635  case 'O':
1636  spec_type = LONG_INT;
1637  break;
1638  case 'f':
1639  case 'g':
1640  case 'G':
1641  case 'E':
1642  case 'e':
1643 #ifndef _NO_LONGDBL
1644  if (flags & LONGDBL)
1645  spec_type = LONG_DOUBLE;
1646  else
1647 #endif
1648  spec_type = DOUBLE;
1649  break;
1650  case 's':
1651  case 'S':
1652  case 'p':
1653  spec_type = CHAR_PTR;
1654  break;
1655  case 'c':
1656  spec_type = CHAR;
1657  break;
1658  case 'C':
1659  spec_type = WIDE_CHAR;
1660  break;
1661  }
1662 
1663  /* if we have a positional parameter, just store the type, otherwise
1664  fetch the parameter from the vararg list */
1665  if (pos != -1)
1666  arg_type[pos] = spec_type;
1667  else
1668  {
1669  switch (spec_type)
1670  {
1671  case LONG_INT:
1672  args[numargs++].val_long = va_arg(*ap, long);
1673  break;
1674  case QUAD_INT:
1675  args[numargs++].val_quad_t = va_arg(*ap, quad_t);
1676  break;
1677  case WIDE_CHAR:
1678  args[numargs++].val_wint_t = va_arg(*ap, wint_t);
1679  break;
1680  case CHAR:
1681  case SHORT_INT:
1682  case INT:
1683  args[numargs++].val_int = va_arg(*ap, int);
1684  break;
1685  case CHAR_PTR:
1686  args[numargs++].val_char_ptr_t = va_arg(*ap, char *);
1687  break;
1688  case DOUBLE:
1689  args[numargs++].val_double = va_arg(*ap, double);
1690  break;
1691  case LONG_DOUBLE:
1692  args[numargs++].val__LONG_DOUBLE = va_arg(*ap, _LONG_DOUBLE);
1693  break;
1694  }
1695  }
1696  }
1697  break;
1698  case GETPOS: /* we have positional specifier */
1699  if (arg_type[0] == -1)
1700  memset (arg_type, 0, sizeof(int) * MAX_POS_ARGS);
1701  pos = number - 1;
1702  max_pos_arg = (max_pos_arg > pos ? max_pos_arg : pos);
1703  break;
1704  case PWPOS: /* we have positional specifier for width or precision */
1705  if (arg_type[0] == -1)
1706  memset (arg_type, 0, sizeof(int) * MAX_POS_ARGS);
1707  number -= 1;
1708  arg_type[number] = INT;
1709  max_pos_arg = (max_pos_arg > number ? max_pos_arg : number);
1710  break;
1711  case GETPWB: /* we require format pushback */
1712  --fmt;
1713  /* fallthrough */
1714  case GETPW: /* we have a variable precision or width to acquire */
1715  args[numargs++].val_int = va_arg(*ap, int);
1716  break;
1717  case NUMBER: /* we have a number to process */
1718  number = (ch - '0');
1719  while ((ch = *fmt) != '\0' && is_digit(ch))
1720  {
1721  number = number * 10 + (ch - '0');
1722  ++fmt;
1723  }
1724  break;
1725  case SKIPNUM: /* we have a number to skip */
1726  while ((ch = *fmt) != '\0' && is_digit(ch))
1727  ++fmt;
1728  break;
1729  case NOOP:
1730  default:
1731  break; /* do nothing */
1732  }
1733  }
1734  }
1735 
1736  /* process all arguments up to at least the one we are looking for and if we
1737  have seen the end of the string, then process up to the max argument needed */
1738  if (*fmt == '\0')
1739  last_arg = max_pos_arg;
1740  else
1741  last_arg = n;
1742 
1743  while (numargs <= last_arg)
1744  {
1745  switch (arg_type[numargs])
1746  {
1747  case LONG_INT:
1748  args[numargs++].val_long = va_arg(*ap, long);
1749  break;
1750  case QUAD_INT:
1751  args[numargs++].val_quad_t = va_arg(*ap, quad_t);
1752  break;
1753  case CHAR_PTR:
1754  args[numargs++].val_char_ptr_t = va_arg(*ap, char *);
1755  break;
1756  case DOUBLE:
1757  args[numargs++].val_double = va_arg(*ap, double);
1758  break;
1759  case LONG_DOUBLE:
1760  args[numargs++].val__LONG_DOUBLE = va_arg(*ap, _LONG_DOUBLE);
1761  break;
1762  case WIDE_CHAR:
1763  args[numargs++].val_wint_t = va_arg(*ap, wint_t);
1764  break;
1765  case INT:
1766  case SHORT_INT:
1767  case CHAR:
1768  default:
1769  args[numargs++].val_int = va_arg(*ap, int);
1770  break;
1771  }
1772  }
1773 
1774  /* alter the global numargs value and keep a reference to the last bit of the fmt
1775  string we processed here because the caller will continue processing where we started */
1776  *numargs_p = numargs;
1777  *last_fmt = fmt;
1778  return &args[n];
1779 }
1780 #endif /* !_NO_POS_ARGS */