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