Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6607 serge 1
/*
2
 * Copyright (c) 1990 The Regents of the University of California.
3
 * All rights reserved.
4
 *
5
 * This code is derived from software contributed to Berkeley by
6
 * Chris Torek.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 4. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
 
33
/*
34
FUNCTION
35
<>, <>, <>---wide character format argument list
36
 
37
INDEX
38
	vfwprintf
39
INDEX
40
	_vfwprintf_r
41
INDEX
42
	vwprintf
43
INDEX
44
	_vwprintf_r
45
INDEX
46
	vswprintf
47
INDEX
48
	_vswprintf_r
49
 
50
ANSI_SYNOPSIS
51
	#include 
52
	#include 
53
	#include 
54
	int vwprintf(const wchar_t *__restrict <[fmt]>, va_list <[list]>);
55
	int vfwprintf(FILE *__restrict <[fp]>,
56
		const wchar_t *__restrict <[fmt]>, va_list <[list]>);
57
	int vswprintf(wchar_t * __restrict <[str]>, size_t <[size]>,
58
		const wchar_t *__ restrict <[fmt]>, va_list <[list]>);
59
 
60
	int _vwprintf_r(struct _reent *<[reent]>, const wchar_t *<[fmt]>,
61
		va_list <[list]>);
62
	int _vfwprintf_r(struct _reent *<[reent]>, FILE *<[fp]>,
63
		const wchar_t *<[fmt]>, va_list <[list]>);
64
	int _vswprintf_r(struct _reent *<[reent]>, wchar_t *<[str]>,
65
		size_t <[size]>, const wchar_t *<[fmt]>, va_list <[list]>);
66
 
67
DESCRIPTION
68
<>, <> and <> are (respectively) variants
69
of <>, <> and <>.  They differ only in allowing
70
their caller to pass the variable argument list as a <> object
71
(initialized by <>) rather than directly accepting a variable
72
number of arguments.  The caller is responsible for calling <>.
73
 
74
<<_vwprintf_r>>, <<_vfwprintf_r>> and <<_vswprintf_r>> are reentrant
75
versions of the above.
76
 
77
RETURNS
78
The return values are consistent with the corresponding functions.
79
 
80
PORTABILITY
81
POSIX-1.2008 with extensions; C99 (compliant except for POSIX extensions).
82
 
83
Supporting OS subroutines required: <>, <>, <>,
84
<>, <>, <>, <>.
85
 
86
SEEALSO
87
<>, <> and <>.
88
*/
89
 
90
/*
91
 * Actual wprintf innards.
92
 *
93
 * This code is large and complicated...
94
 */
95
#include 
96
 
97
#ifdef INTEGER_ONLY
98
# define VFWPRINTF vfiwprintf
99
# ifdef STRING_ONLY
100
#   define _VFWPRINTF_R _svfiwprintf_r
101
# else
102
#   define _VFWPRINTF_R _vfiwprintf_r
103
# endif
104
#else
105
# define VFWPRINTF vfwprintf
106
# ifdef STRING_ONLY
107
#   define _VFWPRINTF_R _svfwprintf_r
108
# else
109
#   define _VFWPRINTF_R _vfwprintf_r
110
# endif
111
# ifndef NO_FLOATING_POINT
112
#  define FLOATING_POINT
113
# endif
114
#endif
115
 
116
#define _NO_POS_ARGS
117
#ifdef _WANT_IO_POS_ARGS
118
# undef _NO_POS_ARGS
119
#endif
120
 
121
#include <_ansi.h>
122
#include 
123
#include 
124
#include 
125
#include 
126
#include 
127
#include 
128
#include 
129
#include 
130
#include 
131
#include "local.h"
132
#include "fvwrite.h"
133
#include "vfieeefp.h"
134
#ifdef __HAVE_LOCALE_INFO_EXTENDED__
135
#include "../locale/lnumeric.h"
136
#endif
137
 
138
/* Currently a test is made to see if long double processing is warranted.
139
   This could be changed in the future should the _ldtoa_r code be
140
   preferred over _dtoa_r.  */
141
#define _NO_LONGDBL
142
#if defined _WANT_IO_LONG_DOUBLE && (LDBL_MANT_DIG > DBL_MANT_DIG)
143
#undef _NO_LONGDBL
144
#endif
145
 
146
#define _NO_LONGLONG
147
#if defined _WANT_IO_LONG_LONG \
148
	&& (defined __GNUC__ || __STDC_VERSION__ >= 199901L)
149
# undef _NO_LONGLONG
150
#endif
151
 
152
int _EXFUN(_VFWPRINTF_R, (struct _reent *, FILE *, _CONST wchar_t *, va_list));
153
/* Defined in vfprintf.c. */
154
#ifdef _FVWRITE_IN_STREAMIO
155
# ifdef STRING_ONLY
156
#  define __SPRINT __ssprint_r
157
# else
158
#  define __SPRINT __sprint_r
159
# endif
160
int _EXFUN(__SPRINT, (struct _reent *, FILE *, register struct __suio *));
161
#else
162
# ifdef STRING_ONLY
163
#  define __SPRINT __ssputs_r
164
# else
165
#  define __SPRINT __sfputs_r
166
# endif
167
int _EXFUN(__SPRINT, (struct _reent *, FILE *, _CONST char *, size_t));
168
#endif
169
#ifndef STRING_ONLY
170
#ifdef _UNBUF_STREAM_OPT
171
/*
172
 * Helper function for `fprintf to unbuffered unix file': creates a
173
 * temporary buffer.  We only work on write-only files; this avoids
174
 * worries about ungetc buffers and so forth.
175
 */
176
static int
177
_DEFUN(__sbwprintf, (rptr, fp, fmt, ap),
178
       struct _reent *rptr _AND
179
       register FILE *fp   _AND
180
       _CONST wchar_t *fmt  _AND
181
       va_list ap)
182
{
183
	int ret;
184
	FILE fake;
185
	unsigned char buf[BUFSIZ];
186
 
187
	/* copy the important variables */
188
	fake._flags = fp->_flags & ~__SNBF;
189
	fake._flags2 = fp->_flags2;
190
	fake._file = fp->_file;
191
	fake._cookie = fp->_cookie;
192
	fake._write = fp->_write;
193
 
194
	/* set up the buffer */
195
	fake._bf._base = fake._p = buf;
196
	fake._bf._size = fake._w = sizeof (buf);
197
	fake._lbfsize = 0;	/* not actually used, but Just In Case */
198
#ifndef __SINGLE_THREAD__
199
	__lock_init_recursive (fake._lock);
200
#endif
201
 
202
	/* do the work, then copy any error status */
203
	ret = _VFWPRINTF_R (rptr, &fake, fmt, ap);
204
	if (ret >= 0 && _fflush_r (rptr, &fake))
205
		ret = EOF;
206
	if (fake._flags & __SERR)
207
		fp->_flags |= __SERR;
208
 
209
#ifndef __SINGLE_THREAD__
210
	__lock_close_recursive (fake._lock);
211
#endif
212
	return (ret);
213
}
214
#endif /* _UNBUF_STREAM_OPT */
215
#endif /* !STRING_ONLY */
216
 
217
 
218
#if defined (FLOATING_POINT) || defined (_WANT_IO_C99_FORMATS)
219
# include 
220
#endif
221
#ifdef FLOATING_POINT
222
# include 
223
 
224
/* For %La, an exponent of 15 bits occupies the exponent character, a
225
   sign, and up to 5 digits.  */
226
# define MAXEXPLEN		7
227
# define DEFPREC		6
228
 
229
# ifdef _NO_LONGDBL
230
 
231
extern char *_dtoa_r _PARAMS((struct _reent *, double, int,
232
			      int, int *, int *, char **));
233
 
234
#  define _PRINTF_FLOAT_TYPE double
235
#  define _DTOA_R _dtoa_r
236
#  define FREXP frexp
237
 
238
# else /* !_NO_LONGDBL */
239
 
240
extern char *_ldtoa_r _PARAMS((struct _reent *, _LONG_DOUBLE, int,
241
			      int, int *, int *, char **));
242
 
243
extern int _EXFUN(_ldcheck,(_LONG_DOUBLE *));
244
 
245
#  define _PRINTF_FLOAT_TYPE _LONG_DOUBLE
246
#  define _DTOA_R _ldtoa_r
247
/* FIXME - frexpl is not yet supported; and cvt infloops if (double)f
248
   converts a finite value into infinity.  */
249
/* #  define FREXP frexpl */
250
#  define FREXP(f,e) ((_LONG_DOUBLE) frexp ((double)f, e))
251
# endif /* !_NO_LONGDBL */
252
 
253
static wchar_t *wcvt(struct _reent *, _PRINTF_FLOAT_TYPE, int, int, wchar_t *,
254
		    int *, int, int *, wchar_t *, int);
255
 
256
static int wexponent(wchar_t *, int, int);
257
 
258
#endif /* FLOATING_POINT */
259
 
260
/* BUF must be big enough for the maximum %#llo (assuming long long is
261
   at most 64 bits, this would be 23 characters), the maximum
262
   multibyte character %C, and the maximum default precision of %La
263
   (assuming long double is at most 128 bits with 113 bits of
264
   mantissa, this would be 29 characters).  %e, %f, and %g use
265
   reentrant storage shared with mprec.  All other formats that use
266
   buf get by with fewer characters.  Making BUF slightly bigger
267
   reduces the need for malloc in %.*a and %ls/%S, when large precision or
268
   long strings are processed.
269
   The bigger size of 100 bytes is used on systems which allow number
270
   strings using the locale's grouping character.  Since that's a multibyte
271
   value, we should use a conservative value.
272
   */
273
#ifdef _WANT_IO_C99_FORMATS
274
#define BUF             100
275
#else
276
#define	BUF		40
277
#endif
278
#if defined _MB_CAPABLE && MB_LEN_MAX > BUF
279
# undef BUF
280
# define BUF MB_LEN_MAX
281
#endif
282
 
283
#ifndef _NO_LONGLONG
284
# define quad_t long long
285
# define u_quad_t unsigned long long
286
#else
287
# define quad_t long
288
# define u_quad_t unsigned long
289
#endif
290
 
291
typedef quad_t * quad_ptr_t;
292
typedef _PTR     void_ptr_t;
293
typedef char *   char_ptr_t;
294
typedef wchar_t* wchar_ptr_t;
295
typedef long *   long_ptr_t;
296
typedef int  *   int_ptr_t;
297
typedef short *  short_ptr_t;
298
 
299
#ifndef _NO_POS_ARGS
300
# ifdef NL_ARGMAX
301
#  define MAX_POS_ARGS NL_ARGMAX
302
# else
303
#  define MAX_POS_ARGS 32
304
# endif
305
 
306
union arg_val
307
{
308
  int val_int;
309
  u_int val_u_int;
310
  long val_long;
311
  u_long val_u_long;
312
  float val_float;
313
  double val_double;
314
  _LONG_DOUBLE val__LONG_DOUBLE;
315
  int_ptr_t val_int_ptr_t;
316
  short_ptr_t val_short_ptr_t;
317
  long_ptr_t val_long_ptr_t;
318
  char_ptr_t val_char_ptr_t;
319
  wchar_ptr_t val_wchar_ptr_t;
320
  quad_ptr_t val_quad_ptr_t;
321
  void_ptr_t val_void_ptr_t;
322
  quad_t val_quad_t;
323
  u_quad_t val_u_quad_t;
324
  wint_t val_wint_t;
325
};
326
 
327
static union arg_val *
328
_EXFUN(get_arg, (struct _reent *data, int n, wchar_t *fmt,
329
                 va_list *ap, int *numargs, union arg_val *args,
330
                 int *arg_type, wchar_t **last_fmt));
331
#endif /* !_NO_POS_ARGS */
332
 
333
/*
334
 * Macros for converting digits to letters and vice versa
335
 */
336
#define	to_digit(c)	((c) - L'0')
337
#define is_digit(c)	((unsigned)to_digit (c) <= 9)
338
#define	to_char(n)	((n) + L'0')
339
 
340
/*
341
 * Flags used during conversion.
342
 */
343
#define	ALT		0x001		/* alternate form */
344
#define	HEXPREFIX	0x002		/* add 0x or 0X prefix */
345
#define	LADJUST		0x004		/* left adjustment */
346
#define	LONGDBL		0x008		/* long double */
347
#define	LONGINT		0x010		/* long integer */
348
#ifndef _NO_LONGLONG
349
# define QUADINT	0x020		/* quad integer */
350
#else /* ifdef _NO_LONGLONG, make QUADINT equivalent to LONGINT, so
351
	 that %lld behaves the same as %ld, not as %d, as expected if:
352
	 sizeof (long long) = sizeof long > sizeof int  */
353
# define QUADINT	LONGINT
354
#endif
355
#define	SHORTINT	0x040		/* short integer */
356
#define	ZEROPAD		0x080		/* zero (as opposed to blank) pad */
357
#define FPT		0x100		/* Floating point number */
358
#ifdef _WANT_IO_C99_FORMATS
359
# define CHARINT	0x200		/* char as integer */
360
#else /* define as 0, to make SARG and UARG occupy fewer instructions  */
361
# define CHARINT	0
362
#endif
363
#ifdef _WANT_IO_C99_FORMATS
364
# define GROUPING	0x400		/* use grouping ("'" flag) */
365
#endif
366
 
367
#ifndef STRING_ONLY
368
int
369
_DEFUN(VFWPRINTF, (fp, fmt0, ap),
370
       FILE *__restrict fp         _AND
371
       _CONST wchar_t *__restrict fmt0 _AND
372
       va_list ap)
373
{
374
  int result;
375
  result = _VFWPRINTF_R (_REENT, fp, fmt0, ap);
376
  return result;
377
}
378
#endif /* STRING_ONLY */
379
 
380
int
381
_DEFUN(_VFWPRINTF_R, (data, fp, fmt0, ap),
382
       struct _reent *data _AND
383
       FILE * fp           _AND
384
       _CONST wchar_t *fmt0   _AND
385
       va_list ap)
386
{
387
	register wchar_t *fmt;	/* format string */
388
	register wint_t ch;	/* character from fmt */
389
	register int n, m;	/* handy integers (short term usage) */
390
	register wchar_t *cp;	/* handy char pointer (short term usage) */
391
	register int flags;	/* flags as above */
392
	wchar_t *fmt_anchor;    /* current format spec being processed */
393
#ifndef _NO_POS_ARGS
394
	int N;                  /* arg number */
395
	int arg_index;          /* index into args processed directly */
396
	int numargs;            /* number of varargs read */
397
	wchar_t *saved_fmt;     /* saved fmt pointer */
398
	union arg_val args[MAX_POS_ARGS];
399
	int arg_type[MAX_POS_ARGS];
400
	int is_pos_arg;         /* is current format positional? */
401
	int old_is_pos_arg;     /* is current format positional? */
402
#endif
403
	int ret;		/* return value accumulator */
404
	int width;		/* width from format (%8d), or 0 */
405
	int prec;		/* precision from format (%.3d), or -1 */
406
	wchar_t sign;		/* sign prefix (' ', '+', '-', or \0) */
407
#ifdef _WANT_IO_C99_FORMATS
408
				/* locale specific numeric grouping */
409
	wchar_t thousands_sep = L'\0';
410
	const char *grouping = NULL;
411
#endif
412
#if defined (_MB_CAPABLE) && !defined (__HAVE_LOCALE_INFO_EXTENDED__) \
413
    && (defined (FLOATING_POINT) || defined (_WANT_IO_C99_FORMATS))
414
	mbstate_t state;        /* mbtowc calls from library must not change state */
415
#endif
416
#ifdef FLOATING_POINT
417
	wchar_t decimal_point;
418
	wchar_t softsign;		/* temporary negative sign for floats */
419
	union { int i; _PRINTF_FLOAT_TYPE fp; } _double_ = {0};
420
# define _fpvalue (_double_.fp)
421
	int expt;		/* integer value of exponent */
422
	int expsize = 0;	/* character count for expstr */
423
	wchar_t expstr[MAXEXPLEN];	/* buffer for exponent string */
424
	int lead;		/* sig figs before decimal or group sep */
425
#endif /* FLOATING_POINT */
426
#if defined (FLOATING_POINT) || defined (_WANT_IO_C99_FORMATS)
427
	int ndig = 0;		/* actual number of digits returned by cvt */
428
#endif
429
#if defined (FLOATING_POINT) && defined (_WANT_IO_C99_FORMATS)
430
	int nseps;		/* number of group separators with ' */
431
	int nrepeats;		/* number of repeats of the last group */
432
#endif
433
	u_quad_t _uquad;	/* integer arguments %[diouxX] */
434
	enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
435
	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */
436
	int realsz;		/* field size expanded by dprec */
437
	int size = 0;		/* size of converted field or string */
438
	wchar_t *xdigs = NULL;	/* digits for [xX] conversion */
439
#ifdef _FVWRITE_IN_STREAMIO
440
#define NIOV 8
441
	struct __suio uio;	/* output information: summary */
442
	struct __siov iov[NIOV];/* ... and individual io vectors */
443
	register struct __siov *iovp;/* for PRINT macro */
444
#endif
445
	wchar_t buf[BUF];	/* space for %c, %ls/%S, %[diouxX], %[aA] */
446
	wchar_t ox[2];		/* space for 0x hex-prefix */
447
	wchar_t *malloc_buf = NULL;/* handy pointer for malloced buffers */
448
 
449
	/*
450
	 * Choose PADSIZE to trade efficiency vs. size.  If larger printf
451
	 * fields occur frequently, increase PADSIZE and make the initialisers
452
	 * below longer.
453
	 */
454
#define	PADSIZE	16		/* pad chunk size */
455
	static _CONST wchar_t blanks[PADSIZE] =
456
	 {L' ',L' ',L' ',L' ',L' ',L' ',L' ',L' ',
457
	  L' ',L' ',L' ',L' ',L' ',L' ',L' ',L' '};
458
	static _CONST wchar_t zeroes[PADSIZE] =
459
	 {L'0',L'0',L'0',L'0',L'0',L'0',L'0',L'0',
460
	  L'0',L'0',L'0',L'0',L'0',L'0',L'0',L'0'};
461
 
462
#ifdef FLOATING_POINT
463
#ifdef _MB_CAPABLE
464
#ifdef __HAVE_LOCALE_INFO_EXTENDED__
465
	decimal_point = *__get_current_numeric_locale ()->wdecimal_point;
466
#else
467
	{
468
	  size_t nconv;
469
 
470
	  memset (&state, '\0', sizeof (state));
471
	  nconv = _mbrtowc_r (data, &decimal_point,
472
			      _localeconv_r (data)->decimal_point,
473
			      MB_CUR_MAX, &state);
474
	  if (nconv == (size_t) -1 || nconv == (size_t) -2)
475
	    decimal_point = L'.';
476
	}
477
#endif
478
#else
479
	decimal_point = (wchar_t) *_localeconv_r (data)->decimal_point;
480
#endif
481
#endif
482
	/*
483
	 * BEWARE, these `goto error' on error, and PAD uses `n'.
484
	 */
485
#ifdef _FVWRITE_IN_STREAMIO
486
#define	PRINT(ptr, len) { \
487
	iovp->iov_base = (char *) (ptr); \
488
	iovp->iov_len = (len) * sizeof (wchar_t); \
489
	uio.uio_resid += (len) * sizeof (wchar_t); \
490
	iovp++; \
491
	if (++uio.uio_iovcnt >= NIOV) { \
492
		if (__SPRINT(data, fp, &uio)) \
493
			goto error; \
494
		iovp = iov; \
495
	} \
496
}
497
#define	PAD(howmany, with) { \
498
	if ((n = (howmany)) > 0) { \
499
		while (n > PADSIZE) { \
500
			PRINT (with, PADSIZE); \
501
			n -= PADSIZE; \
502
		} \
503
		PRINT (with, n); \
504
	} \
505
}
506
#define PRINTANDPAD(p, ep, len, with) { \
507
	int n = (ep) - (p); \
508
	if (n > (len)) \
509
		n = (len); \
510
	if (n > 0) \
511
		PRINT((p), n); \
512
	PAD((len) - (n > 0 ? n : 0), (with)); \
513
}
514
#define	FLUSH() { \
515
	if (uio.uio_resid && __SPRINT(data, fp, &uio)) \
516
		goto error; \
517
	uio.uio_iovcnt = 0; \
518
	iovp = iov; \
519
}
520
#else
521
#define PRINT(ptr, len) {		\
522
	if (__SPRINT (data, fp, (_CONST char *)(ptr), (len) * sizeof (wchar_t)) == EOF) \
523
		goto error;		\
524
}
525
#define	PAD(howmany, with) {		\
526
	if ((n = (howmany)) > 0) {	\
527
		while (n > PADSIZE) {	\
528
			PRINT (with, PADSIZE);	\
529
			n -= PADSIZE;	\
530
		}			\
531
		PRINT (with, n);	\
532
	}				\
533
}
534
#define PRINTANDPAD(p, ep, len, with) {	\
535
	int n = (ep) - (p);		\
536
	if (n > (len))			\
537
		n = (len);		\
538
	if (n > 0)			\
539
		PRINT((p), n);		\
540
	PAD((len) - (n > 0 ? n : 0), (with)); \
541
}
542
#define	FLUSH()
543
#endif
544
 
545
	/* Macros to support positional arguments */
546
#ifndef _NO_POS_ARGS
547
# define GET_ARG(n, ap, type)						\
548
	(is_pos_arg							\
549
	 ? (n < numargs							\
550
	    ? args[n].val_##type					\
551
	    : get_arg (data, n, fmt_anchor, &ap, &numargs, args,	\
552
		       arg_type, &saved_fmt)->val_##type)		\
553
	 : (arg_index++ < numargs					\
554
	    ? args[n].val_##type					\
555
	    : (numargs < MAX_POS_ARGS					\
556
	       ? args[numargs++].val_##type = va_arg (ap, type)		\
557
	       : va_arg (ap, type))))
558
#else
559
# define GET_ARG(n, ap, type) (va_arg (ap, type))
560
#endif
561
 
562
	/*
563
	 * To extend shorts properly, we need both signed and unsigned
564
	 * argument extraction methods.
565
	 */
566
#ifndef _NO_LONGLONG
567
#define	SARG() \
568
	(flags&QUADINT ? GET_ARG (N, ap, quad_t) : \
569
	    flags&LONGINT ? GET_ARG (N, ap, long) : \
570
	    flags&SHORTINT ? (long)(short)GET_ARG (N, ap, int) : \
571
	    flags&CHARINT ? (long)(signed char)GET_ARG (N, ap, int) : \
572
	    (long)GET_ARG (N, ap, int))
573
#define	UARG() \
574
	(flags&QUADINT ? GET_ARG (N, ap, u_quad_t) : \
575
	    flags&LONGINT ? GET_ARG (N, ap, u_long) : \
576
	    flags&SHORTINT ? (u_long)(u_short)GET_ARG (N, ap, int) : \
577
	    flags&CHARINT ? (u_long)(unsigned char)GET_ARG (N, ap, int) : \
578
	    (u_long)GET_ARG (N, ap, u_int))
579
#else
580
#define	SARG() \
581
	(flags&LONGINT ? GET_ARG (N, ap, long) : \
582
	    flags&SHORTINT ? (long)(short)GET_ARG (N, ap, int) : \
583
	    flags&CHARINT ? (long)(signed char)GET_ARG (N, ap, int) : \
584
	    (long)GET_ARG (N, ap, int))
585
#define	UARG() \
586
	(flags&LONGINT ? GET_ARG (N, ap, u_long) : \
587
	    flags&SHORTINT ? (u_long)(u_short)GET_ARG (N, ap, int) : \
588
	    flags&CHARINT ? (u_long)(unsigned char)GET_ARG (N, ap, int) : \
589
	    (u_long)GET_ARG (N, ap, u_int))
590
#endif
591
 
592
#ifndef STRING_ONLY
593
	/* Initialize std streams if not dealing with sprintf family.  */
594
	CHECK_INIT (data, fp);
595
	_newlib_flockfile_start (fp);
596
 
597
	ORIENT(fp, 1);
598
 
599
	/* sorry, fwprintf(read_only_file, "") returns EOF, not 0 */
600
	if (cantwrite (data, fp)) {
601
		_newlib_flockfile_exit (fp);
602
		return (EOF);
603
	}
604
 
605
#ifdef _UNBUF_STREAM_OPT
606
	/* optimise fwprintf(stderr) (and other unbuffered Unix files) */
607
	if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
608
	    fp->_file >= 0) {
609
		_newlib_flockfile_exit (fp);
610
		return (__sbwprintf (data, fp, fmt0, ap));
611
	}
612
#endif
613
#else /* STRING_ONLY */
614
        /* Create initial buffer if we are called by asprintf family.  */
615
        if (fp->_flags & __SMBF && !fp->_bf._base)
616
        {
617
		fp->_bf._base = fp->_p = _malloc_r (data, 64);
618
		if (!fp->_p)
619
		{
620
			data->_errno = ENOMEM;
621
			return EOF;
622
		}
623
		fp->_bf._size = 64;
624
        }
625
#endif /* STRING_ONLY */
626
 
627
	fmt = (wchar_t *)fmt0;
628
#ifdef _FVWRITE_IN_STREAMIO
629
	uio.uio_iov = iovp = iov;
630
	uio.uio_resid = 0;
631
	uio.uio_iovcnt = 0;
632
#endif
633
	ret = 0;
634
#ifndef _NO_POS_ARGS
635
	arg_index = 0;
636
	saved_fmt = NULL;
637
	arg_type[0] = -1;
638
	numargs = 0;
639
	is_pos_arg = 0;
640
#endif
641
 
642
	/*
643
	 * Scan the format for conversions (`%' character).
644
	 */
645
	for (;;) {
646
	        cp = fmt;
647
                while (*fmt != L'\0' && *fmt != L'%')
648
                    ++fmt;
649
		if ((m = fmt - cp) != 0) {
650
			PRINT (cp, m);
651
			ret += m;
652
		}
653
                if (*fmt == L'\0')
654
                    goto done;
655
		fmt_anchor = fmt;
656
		fmt++;		/* skip over '%' */
657
 
658
		flags = 0;
659
		dprec = 0;
660
		width = 0;
661
		prec = -1;
662
		sign = L'\0';
663
#ifdef FLOATING_POINT
664
		lead = 0;
665
#ifdef _WANT_IO_C99_FORMATS
666
		nseps = nrepeats = 0;
667
#endif
668
#endif
669
#ifndef _NO_POS_ARGS
670
		N = arg_index;
671
		is_pos_arg = 0;
672
#endif
673
 
674
rflag:		ch = *fmt++;
675
reswitch:	switch (ch) {
676
#ifdef _WANT_IO_C99_FORMATS
677
		case L'\'':
678
#ifdef _MB_CAPABLE
679
#ifdef __HAVE_LOCALE_INFO_EXTENDED__
680
		  thousands_sep = *__get_current_numeric_locale ()->wthousands_sep;
681
#else
682
		  {
683
		    size_t nconv;
684
 
685
		    memset (&state, '\0', sizeof (state));
686
		    nconv = _mbrtowc_r (data, &thousands_sep,
687
					_localeconv_r (data)->thousands_sep,
688
					MB_CUR_MAX, &state);
689
		    if (nconv == (size_t) -1 || nconv == (size_t) -2)
690
		      thousands_sep = L'\0';
691
		  }
692
#endif
693
#else
694
		  thousands_sep = (wchar_t) *_localeconv_r(data)->thousands_sep;
695
#endif
696
		  grouping = _localeconv_r (data)->grouping;
697
		  if (thousands_sep && grouping && *grouping)
698
		    flags |= GROUPING;
699
		  goto rflag;
700
#endif
701
		case L' ':
702
			/*
703
			 * ``If the space and + flags both appear, the space
704
			 * flag will be ignored.''
705
			 *	-- ANSI X3J11
706
			 */
707
			if (!sign)
708
				sign = L' ';
709
			goto rflag;
710
		case L'#':
711
			flags |= ALT;
712
			goto rflag;
713
		case L'*':
714
#ifndef _NO_POS_ARGS
715
			/* we must check for positional arg used for dynamic width */
716
			n = N;
717
			old_is_pos_arg = is_pos_arg;
718
			is_pos_arg = 0;
719
			if (is_digit (*fmt)) {
720
				wchar_t *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 == L'$') {
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
 
744
			/*
745
			 * ``A negative field width argument is taken as a
746
			 * - flag followed by a positive field width.''
747
			 *	-- ANSI X3J11
748
			 * They don't exclude field widths read from args.
749
			 */
750
			width = GET_ARG (n, ap, int);
751
#ifndef _NO_POS_ARGS
752
			is_pos_arg = old_is_pos_arg;
753
#endif
754
			if (width >= 0)
755
				goto rflag;
756
			width = -width;
757
			/* FALLTHROUGH */
758
		case L'-':
759
			flags |= LADJUST;
760
			goto rflag;
761
		case L'+':
762
			sign = L'+';
763
			goto rflag;
764
		case L'.':
765
			if ((ch = *fmt++) == L'*') {
766
#ifndef _NO_POS_ARGS
767
				/* we must check for positional arg used for dynamic width */
768
				n = N;
769
				old_is_pos_arg = is_pos_arg;
770
				is_pos_arg = 0;
771
				if (is_digit (*fmt)) {
772
					wchar_t *old_fmt = fmt;
773
 
774
					n = 0;
775
					ch = *fmt++;
776
					do {
777
						n = 10 * n + to_digit (ch);
778
						ch = *fmt++;
779
					} while (is_digit (ch));
780
 
781
					if (ch == L'$') {
782
						if (n <= MAX_POS_ARGS) {
783
							n -= 1;
784
							is_pos_arg = 1;
785
						}
786
						else
787
							goto error;
788
					}
789
					else {
790
						fmt = old_fmt;
791
						goto rflag;
792
					}
793
				}
794
#endif /* !_NO_POS_ARGS */
795
				prec = GET_ARG (n, ap, int);
796
#ifndef _NO_POS_ARGS
797
				is_pos_arg = old_is_pos_arg;
798
#endif
799
				if (prec < 0)
800
					prec = -1;
801
				goto rflag;
802
			}
803
			n = 0;
804
			while (is_digit (ch)) {
805
				n = 10 * n + to_digit (ch);
806
				ch = *fmt++;
807
			}
808
			prec = n < 0 ? -1 : n;
809
			goto reswitch;
810
		case L'0':
811
			/*
812
			 * ``Note that 0 is taken as a flag, not as the
813
			 * beginning of a field width.''
814
			 *	-- ANSI X3J11
815
			 */
816
			flags |= ZEROPAD;
817
			goto rflag;
818
		case L'1': case L'2': case L'3': case L'4':
819
		case L'5': case L'6': case L'7': case L'8': case L'9':
820
			n = 0;
821
			do {
822
				n = 10 * n + to_digit (ch);
823
				ch = *fmt++;
824
			} while (is_digit (ch));
825
#ifndef _NO_POS_ARGS
826
			if (ch == L'$') {
827
				if (n <= MAX_POS_ARGS) {
828
					N = n - 1;
829
					is_pos_arg = 1;
830
					goto rflag;
831
				}
832
				else
833
					goto error;
834
			}
835
#endif /* !_NO_POS_ARGS */
836
			width = n;
837
			goto reswitch;
838
#ifdef FLOATING_POINT
839
		case L'L':
840
			flags |= LONGDBL;
841
			goto rflag;
842
#endif
843
		case L'h':
844
#ifdef _WANT_IO_C99_FORMATS
845
			if (*fmt == L'h') {
846
				fmt++;
847
				flags |= CHARINT;
848
			} else
849
#endif
850
				flags |= SHORTINT;
851
			goto rflag;
852
		case L'l':
853
#if defined _WANT_IO_C99_FORMATS || !defined _NO_LONGLONG
854
			if (*fmt == L'l') {
855
				fmt++;
856
				flags |= QUADINT;
857
			} else
858
#endif
859
				flags |= LONGINT;
860
			goto rflag;
861
		case L'q': /* GNU extension */
862
			flags |= QUADINT;
863
			goto rflag;
864
#ifdef _WANT_IO_C99_FORMATS
865
		case L'j':
866
		  if (sizeof (intmax_t) == sizeof (long))
867
		    flags |= LONGINT;
868
		  else
869
		    flags |= QUADINT;
870
		  goto rflag;
871
		case L'z':
872
		  if (sizeof (size_t) < sizeof (int))
873
		    /* POSIX states size_t is 16 or more bits, as is short.  */
874
		    flags |= SHORTINT;
875
		  else if (sizeof (size_t) == sizeof (int))
876
		    /* no flag needed */;
877
		  else if (sizeof (size_t) <= sizeof (long))
878
		    flags |= LONGINT;
879
		  else
880
		    /* POSIX states that at least one programming
881
		       environment must support size_t no wider than
882
		       long, but that means other environments can
883
		       have size_t as wide as long long.  */
884
		    flags |= QUADINT;
885
		  goto rflag;
886
		case L't':
887
		  if (sizeof (ptrdiff_t) < sizeof (int))
888
		    /* POSIX states ptrdiff_t is 16 or more bits, as
889
		       is short.  */
890
		    flags |= SHORTINT;
891
		  else if (sizeof (ptrdiff_t) == sizeof (int))
892
		    /* no flag needed */;
893
		  else if (sizeof (ptrdiff_t) <= sizeof (long))
894
		    flags |= LONGINT;
895
		  else
896
		    /* POSIX states that at least one programming
897
		       environment must support ptrdiff_t no wider than
898
		       long, but that means other environments can
899
		       have ptrdiff_t as wide as long long.  */
900
		    flags |= QUADINT;
901
		  goto rflag;
902
		case L'C':	/* POSIX extension */
903
#endif /* _WANT_IO_C99_FORMATS */
904
		case L'c':
905
			cp = buf;
906
			if (ch == L'c' && !(flags & LONGINT)) {
907
				wint_t wc = btowc ((int) GET_ARG (N, ap, int));
908
				if (wc == WEOF) {
909
				    fp->_flags |= __SERR;
910
				    goto error;
911
				}
912
				cp[0] = (wchar_t) wc;
913
			}
914
			else
915
			{
916
				cp[0] = GET_ARG (N, ap, int);
917
			}
918
			cp[1] = L'\0';
919
			size = 1;
920
			sign = L'\0';
921
			break;
922
		case L'd':
923
		case L'i':
924
			_uquad = SARG ();
925
#ifndef _NO_LONGLONG
926
			if ((quad_t)_uquad < 0)
927
#else
928
			if ((long) _uquad < 0)
929
#endif
930
			{
931
 
932
				_uquad = -_uquad;
933
				sign = L'-';
934
			}
935
			base = DEC;
936
			goto number;
937
#ifdef FLOATING_POINT
938
# ifdef _WANT_IO_C99_FORMATS
939
		case L'a':
940
		case L'A':
941
		case L'F':
942
# endif
943
		case L'e':
944
		case L'E':
945
		case L'f':
946
		case L'g':
947
		case L'G':
948
# ifdef _NO_LONGDBL
949
			if (flags & LONGDBL) {
950
				_fpvalue = (double) GET_ARG (N, ap, _LONG_DOUBLE);
951
			} else {
952
				_fpvalue = GET_ARG (N, ap, double);
953
			}
954
 
955
			/* do this before tricky precision changes
956
 
957
			   If the output is infinite or NaN, leading
958
			   zeros are not permitted.  Otherwise, scanf
959
			   could not read what printf wrote.
960
			 */
961
			if (isinf (_fpvalue)) {
962
				if (_fpvalue < 0)
963
					sign = '-';
964
				if (ch <= L'G') /* 'A', 'E', 'F', or 'G' */
965
					cp = L"INF";
966
				else
967
					cp = L"inf";
968
				size = 3;
969
				flags &= ~ZEROPAD;
970
				break;
971
			}
972
			if (isnan (_fpvalue)) {
973
				if (ch <= L'G') /* 'A', 'E', 'F', or 'G' */
974
					cp = L"NAN";
975
				else
976
					cp = L"nan";
977
				size = 3;
978
				flags &= ~ZEROPAD;
979
				break;
980
			}
981
 
982
# else /* !_NO_LONGDBL */
983
 
984
			if (flags & LONGDBL) {
985
				_fpvalue = GET_ARG (N, ap, _LONG_DOUBLE);
986
			} else {
987
				_fpvalue = (_LONG_DOUBLE)GET_ARG (N, ap, double);
988
			}
989
 
990
			/* do this before tricky precision changes */
991
			expt = _ldcheck (&_fpvalue);
992
			if (expt == 2) {
993
				if (_fpvalue < 0)
994
					sign = L'-';
995
				if (ch <= L'G') /* 'A', 'E', 'F', or 'G' */
996
					cp = L"INF";
997
				else
998
					cp = L"inf";
999
				size = 3;
1000
				flags &= ~ZEROPAD;
1001
				break;
1002
			}
1003
			if (expt == 1) {
1004
				if (ch <= L'G') /* 'A', 'E', 'F', or 'G' */
1005
					cp = L"NAN";
1006
				else
1007
					cp = L"nan";
1008
				size = 3;
1009
				flags &= ~ZEROPAD;
1010
				break;
1011
			}
1012
# endif /* !_NO_LONGDBL */
1013
 
1014
			cp = buf;
1015
# ifdef _WANT_IO_C99_FORMATS
1016
			if (ch == L'a' || ch == L'A') {
1017
				ox[0] = L'0';
1018
				ox[1] = ch == L'a' ? L'x' : L'X';
1019
				flags |= HEXPREFIX;
1020
				if (prec >= BUF)
1021
				  {
1022
				    if ((malloc_buf =
1023
					 (wchar_t *)_malloc_r (data, (prec + 1) * sizeof (wchar_t)))
1024
					== NULL)
1025
				      {
1026
					fp->_flags |= __SERR;
1027
					goto error;
1028
				      }
1029
				    cp = malloc_buf;
1030
				  }
1031
			} else
1032
# endif /* _WANT_IO_C99_FORMATS */
1033
			if (prec == -1) {
1034
				prec = DEFPREC;
1035
			} else if ((ch == L'g' || ch == L'G') && prec == 0) {
1036
				prec = 1;
1037
			}
1038
 
1039
			flags |= FPT;
1040
 
1041
			cp = wcvt (data, _fpvalue, prec, flags, &softsign,
1042
				   &expt, ch, &ndig, cp, BUF);
1043
 
1044
			/* If buf is not large enough for the converted wchar_t
1045
			   sequence, call wcvt again with a malloced new buffer.
1046
			   This should happen fairly rarely.
1047
			 */
1048
			if (cp == buf && ndig > BUF && malloc_buf == NULL) {
1049
				if ((malloc_buf =
1050
				    (wchar_t *)_malloc_r (data, ndig * sizeof (wchar_t)))
1051
				    == NULL)
1052
				  {
1053
				    fp->_flags |= __SERR;
1054
				    goto error;
1055
				  }
1056
				cp = wcvt (data, _fpvalue, prec, flags, &softsign,
1057
					   &expt, ch, &ndig, malloc_buf, ndig);
1058
			}
1059
 
1060
			if (ch == L'g' || ch == L'G') {
1061
				if (expt <= -4 || expt > prec)
1062
					ch -= 2; /* 'e' or 'E' */
1063
				else
1064
					ch = L'g';
1065
			}
1066
# ifdef _WANT_IO_C99_FORMATS
1067
			else if (ch == L'F')
1068
				ch = L'f';
1069
# endif
1070
			if (ch <= L'e') {	/* 'a', 'A', 'e', or 'E' fmt */
1071
				--expt;
1072
				expsize = wexponent (expstr, expt, ch);
1073
				size = expsize + ndig;
1074
				if (ndig > 1 || flags & ALT)
1075
					++size;
1076
# ifdef _WANT_IO_C99_FORMATS
1077
				flags &= ~GROUPING;
1078
# endif
1079
			} else {
1080
				if (ch == L'f') {		/* f fmt */
1081
					if (expt > 0) {
1082
						size = expt;
1083
						if (prec || flags & ALT)
1084
							size += prec + 1;
1085
					} else	/* "0.X" */
1086
						size = (prec || flags & ALT)
1087
							  ? prec + 2
1088
							  : 1;
1089
				} else if (expt >= ndig) { /* fixed g fmt */
1090
					size = expt;
1091
					if (flags & ALT)
1092
						++size;
1093
				} else
1094
					size = ndig + (expt > 0 ?
1095
						1 : 2 - expt);
1096
# ifdef _WANT_IO_C99_FORMATS
1097
				if ((flags & GROUPING) && expt > 0) {
1098
					/* space for thousands' grouping */
1099
					nseps = nrepeats = 0;
1100
					lead = expt;
1101
					while (*grouping != CHAR_MAX) {
1102
						if (lead <= *grouping)
1103
							break;
1104
						lead -= *grouping;
1105
						if (grouping[1]) {
1106
							nseps++;
1107
							grouping++;
1108
						} else
1109
							nrepeats++;
1110
					}
1111
					size += nseps + nrepeats;
1112
				} else
1113
# endif
1114
				lead = expt;
1115
			}
1116
			if (softsign)
1117
				sign = L'-';
1118
			break;
1119
#endif /* FLOATING_POINT */
1120
#ifdef _GLIBC_EXTENSION
1121
		case L'm':  /* GNU extension */
1122
			{
1123
				int dummy;
1124
				cp = (wchar_t *) _strerror_r (data, data->_errno, 1, &dummy);
1125
			}
1126
			flags &= ~LONGINT;
1127
			goto string;
1128
#endif
1129
		case L'n':
1130
#ifndef _NO_LONGLONG
1131
			if (flags & QUADINT)
1132
				*GET_ARG (N, ap, quad_ptr_t) = ret;
1133
			else
1134
#endif
1135
			if (flags & LONGINT)
1136
				*GET_ARG (N, ap, long_ptr_t) = ret;
1137
			else if (flags & SHORTINT)
1138
				*GET_ARG (N, ap, short_ptr_t) = ret;
1139
#ifdef _WANT_IO_C99_FORMATS
1140
			else if (flags & CHARINT)
1141
				*GET_ARG (N, ap, char_ptr_t) = ret;
1142
#endif
1143
			else
1144
				*GET_ARG (N, ap, int_ptr_t) = ret;
1145
			continue;	/* no output */
1146
		case L'o':
1147
			_uquad = UARG ();
1148
			base = OCT;
1149
#ifdef _WANT_IO_C99_FORMATS
1150
			flags &= ~GROUPING;
1151
#endif
1152
			goto nosign;
1153
		case L'p':
1154
			/*
1155
			 * ``The argument shall be a pointer to void.  The
1156
			 * value of the pointer is converted to a sequence
1157
			 * of printable characters, in an implementation-
1158
			 * defined manner.''
1159
			 *	-- ANSI X3J11
1160
			 */
1161
			/* NOSTRICT */
1162
			_uquad = (uintptr_t) GET_ARG (N, ap, void_ptr_t);
1163
			base = HEX;
1164
			xdigs = L"0123456789abcdef";
1165
			flags |= HEXPREFIX;
1166
			ox[0] = L'0';
1167
			ox[1] = ch = L'x';
1168
			goto nosign;
1169
		case L's':
1170
#ifdef _WANT_IO_C99_FORMATS
1171
		case L'S':	/* POSIX extension */
1172
#endif
1173
			cp = GET_ARG (N, ap, wchar_ptr_t);
1174
#ifdef _GLIBC_EXTENSION
1175
string:
1176
#endif
1177
			sign = '\0';
1178
#ifndef __OPTIMIZE_SIZE__
1179
			/* Behavior is undefined if the user passed a
1180
			   NULL string when precision is not 0.
1181
			   However, if we are not optimizing for size,
1182
			   we might as well mirror glibc behavior.  */
1183
			if (cp == NULL) {
1184
				cp = L"(null)";
1185
				size = ((unsigned) prec > 6U) ? 6 : prec;
1186
			}
1187
			else
1188
#endif /* __OPTIMIZE_SIZE__ */
1189
#ifdef _MB_CAPABLE
1190
			if (ch != L'S' && !(flags & LONGINT)) {
1191
				char *arg = (char *) cp;
1192
				size_t insize = 0, nchars = 0, nconv = 0;
1193
				mbstate_t ps;
1194
				wchar_t *p;
1195
 
1196
				if (prec >= 0) {
1197
					char *p = arg;
1198
					memset ((_PTR)&ps, '\0', sizeof (mbstate_t));
1199
					while (nchars < (size_t)prec) {
1200
						nconv = mbrlen (p, MB_CUR_MAX, &ps);
1201
						if (nconv == 0 || nconv == (size_t)-1 ||
1202
						    nconv == (size_t)-2)
1203
							break;
1204
						p += nconv;
1205
						++nchars;
1206
						insize += nconv;
1207
					}
1208
					if (nconv == (size_t) -1 || nconv == (size_t) -2) {
1209
						fp->_flags |= __SERR;
1210
						goto error;
1211
					}
1212
				} else
1213
					insize = strlen(arg);
1214
				if (insize >= BUF) {
1215
				    if ((malloc_buf = (wchar_t *) _malloc_r (data, (insize + 1) * sizeof (wchar_t)))
1216
					== NULL) {
1217
						fp->_flags |= __SERR;
1218
						goto error;
1219
					}
1220
					cp = malloc_buf;
1221
				} else
1222
					cp = buf;
1223
				memset ((_PTR)&ps, '\0', sizeof (mbstate_t));
1224
				p = cp;
1225
				while (insize != 0) {
1226
					nconv = _mbrtowc_r (data, p, arg, insize, &ps);
1227
					if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2)
1228
						break;
1229
					++p;
1230
					arg += nconv;
1231
					insize -= nconv;
1232
				}
1233
				if (nconv == (size_t) -1 || nconv == (size_t) -2) {
1234
					fp->_flags |= __SERR;
1235
					goto error;
1236
				}
1237
				*p = L'\0';
1238
				size = p - cp;
1239
			}
1240
#else
1241
			if (ch != L'S' && !(flags & LONGINT)) {
1242
				char *arg = (char *) cp;
1243
				size_t insize = 0;
1244
 
1245
				if (prec >= 0) {
1246
					char *p = memchr (arg, '\0', prec);
1247
					insize = p ? p - arg : prec;
1248
				} else
1249
					insize = strlen (arg);
1250
				if (insize >= BUF) {
1251
				    if ((malloc_buf = (wchar_t *) _malloc_r (data, (insize + 1) * sizeof (wchar_t)))
1252
					== NULL) {
1253
						fp->_flags |= __SERR;
1254
						goto error;
1255
					}
1256
					cp = malloc_buf;
1257
				} else
1258
					cp = buf;
1259
				for (size = 0; size < insize; ++size)
1260
					cp[size] = arg[size];
1261
				cp[size] = L'\0';
1262
			}
1263
#endif /* _MB_CAPABLE */
1264
			else if (prec >= 0) {
1265
				/*
1266
				 * can't use wcslen; can only look for the
1267
				 * NUL in the first `prec' characters, and
1268
				 * strlen () will go further.
1269
				 */
1270
				wchar_t *p = wmemchr (cp, L'\0', prec);
1271
 
1272
				if (p != NULL) {
1273
					size = p - cp;
1274
					if (size > prec)
1275
						size = prec;
1276
				} else
1277
					size = prec;
1278
			} else
1279
				size = wcslen (cp);
1280
 
1281
			break;
1282
		case L'u':
1283
			_uquad = UARG ();
1284
			base = DEC;
1285
			goto nosign;
1286
		case L'X':
1287
			xdigs = L"0123456789ABCDEF";
1288
			goto hex;
1289
		case L'x':
1290
			xdigs = L"0123456789abcdef";
1291
hex:			_uquad = UARG ();
1292
			base = HEX;
1293
			/* leading 0x/X only if non-zero */
1294
			if (flags & ALT && _uquad != 0) {
1295
				ox[0] = L'0';
1296
				ox[1] = ch;
1297
				flags |= HEXPREFIX;
1298
			}
1299
 
1300
#ifdef _WANT_IO_C99_FORMATS
1301
			flags &= ~GROUPING;
1302
#endif
1303
			/* unsigned conversions */
1304
nosign:			sign = L'\0';
1305
			/*
1306
			 * ``... diouXx conversions ... if a precision is
1307
			 * specified, the 0 flag will be ignored.''
1308
			 *	-- ANSI X3J11
1309
			 */
1310
number:			if ((dprec = prec) >= 0)
1311
				flags &= ~ZEROPAD;
1312
 
1313
			/*
1314
			 * ``The result of converting a zero value with an
1315
			 * explicit precision of zero is no characters.''
1316
			 *	-- ANSI X3J11
1317
			 */
1318
			cp = buf + BUF;
1319
			if (_uquad != 0 || prec != 0) {
1320
				/*
1321
				 * Unsigned mod is hard, and unsigned mod
1322
				 * by a constant is easier than that by
1323
				 * a variable; hence this switch.
1324
				 */
1325
				switch (base) {
1326
				case OCT:
1327
					do {
1328
						*--cp = to_char (_uquad & 7);
1329
						_uquad >>= 3;
1330
					} while (_uquad);
1331
					/* handle octal leading 0 */
1332
					if (flags & ALT && *cp != L'0')
1333
						*--cp = L'0';
1334
					break;
1335
 
1336
				case DEC:
1337
					/* many numbers are 1 digit */
1338
					if (_uquad < 10) {
1339
						*--cp = to_char(_uquad);
1340
						break;
1341
					}
1342
#ifdef _WANT_IO_C99_FORMATS
1343
					ndig = 0;
1344
#endif
1345
					do {
1346
					  *--cp = to_char (_uquad % 10);
1347
#ifdef _WANT_IO_C99_FORMATS
1348
					  ndig++;
1349
					  /* If (*grouping == CHAR_MAX) then no
1350
					     more grouping */
1351
					  if ((flags & GROUPING)
1352
					      && ndig == *grouping
1353
					      && *grouping != CHAR_MAX
1354
					      && _uquad > 9) {
1355
					    *--cp = thousands_sep;
1356
					    ndig = 0;
1357
					    /* If (grouping[1] == '\0') then we
1358
					       have to use *grouping character
1359
					       (last grouping rule) for all
1360
					       next cases. */
1361
					    if (grouping[1] != '\0')
1362
					      grouping++;
1363
					  }
1364
#endif
1365
					  _uquad /= 10;
1366
					} while (_uquad != 0);
1367
					break;
1368
 
1369
				case HEX:
1370
					do {
1371
						*--cp = xdigs[_uquad & 15];
1372
						_uquad >>= 4;
1373
					} while (_uquad);
1374
					break;
1375
 
1376
				default:
1377
					cp = L"bug in vfprintf: bad base";
1378
					size = wcslen (cp);
1379
					goto skipsize;
1380
				}
1381
			}
1382
                       /*
1383
			* ...result is to be converted to an 'alternate form'.
1384
			* For o conversion, it increases the precision to force
1385
			* the first digit of the result to be a zero."
1386
			*     -- ANSI X3J11
1387
			*
1388
			* To demonstrate this case, compile and run:
1389
                        *    printf ("%#.0o",0);
1390
			*/
1391
                       else if (base == OCT && (flags & ALT))
1392
                         *--cp = L'0';
1393
 
1394
			size = buf + BUF - cp;
1395
		skipsize:
1396
			break;
1397
		default:	/* "%?" prints ?, unless ? is NUL */
1398
			if (ch == L'\0')
1399
				goto done;
1400
			/* pretend it was %c with argument ch */
1401
			cp = buf;
1402
			*cp = ch;
1403
			size = 1;
1404
			sign = L'\0';
1405
			break;
1406
		}
1407
 
1408
		/*
1409
		 * All reasonable formats wind up here.  At this point, `cp'
1410
		 * points to a string which (if not flags&LADJUST) should be
1411
		 * padded out to `width' places.  If flags&ZEROPAD, it should
1412
		 * first be prefixed by any sign or other prefix; otherwise,
1413
		 * it should be blank padded before the prefix is emitted.
1414
		 * After any left-hand padding and prefixing, emit zeroes
1415
		 * required by a decimal [diouxX] precision, then print the
1416
		 * string proper, then emit zeroes required by any leftover
1417
		 * floating precision; finally, if LADJUST, pad with blanks.
1418
		 * If flags&FPT, ch must be in [aAeEfg].
1419
		 *
1420
		 * Compute actual size, so we know how much to pad.
1421
		 * size excludes decimal prec; realsz includes it.
1422
		 */
1423
		realsz = dprec > size ? dprec : size;
1424
		if (sign)
1425
			realsz++;
1426
		if (flags & HEXPREFIX)
1427
			realsz+= 2;
1428
 
1429
		/* right-adjusting blank padding */
1430
		if ((flags & (LADJUST|ZEROPAD)) == 0)
1431
			PAD (width - realsz, blanks);
1432
 
1433
		/* prefix */
1434
		if (sign)
1435
			PRINT (&sign, 1);
1436
		if (flags & HEXPREFIX)
1437
			PRINT (ox, 2);
1438
 
1439
		/* right-adjusting zero padding */
1440
		if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
1441
			PAD (width - realsz, zeroes);
1442
 
1443
		/* leading zeroes from decimal precision */
1444
		PAD (dprec - size, zeroes);
1445
 
1446
		/* the string or number proper */
1447
#ifdef FLOATING_POINT
1448
		if ((flags & FPT) == 0) {
1449
			PRINT (cp, size);
1450
		} else {	/* glue together f_p fragments */
1451
			if (ch >= L'f') {	/* 'f' or 'g' */
1452
				if (_fpvalue == 0) {
1453
					/* kludge for __dtoa irregularity */
1454
					PRINT (L"0", 1);
1455
					if (expt < ndig || flags & ALT) {
1456
						PRINT (&decimal_point, 1);
1457
						PAD (ndig - 1, zeroes);
1458
					}
1459
				} else if (expt <= 0) {
1460
					PRINT (L"0", 1);
1461
					if (expt || ndig || flags & ALT) {
1462
						PRINT (&decimal_point, 1);
1463
						PAD (-expt, zeroes);
1464
						PRINT (cp, ndig);
1465
					}
1466
				} else {
1467
					wchar_t *convbuf = cp;
1468
					PRINTANDPAD(cp, convbuf + ndig,
1469
						    lead, zeroes);
1470
					cp += lead;
1471
#ifdef _WANT_IO_C99_FORMATS
1472
					if (flags & GROUPING) {
1473
					    while (nseps > 0 || nrepeats > 0) {
1474
						if (nrepeats > 0)
1475
						    nrepeats--;
1476
						else {
1477
						    grouping--;
1478
						    nseps--;
1479
						}
1480
						PRINT (&thousands_sep, 1);
1481
						PRINTANDPAD (cp, convbuf + ndig,
1482
							     *grouping, zeroes);
1483
						cp += *grouping;
1484
					    }
1485
					    if (cp > convbuf + ndig)
1486
						cp = convbuf + ndig;
1487
					}
1488
#endif
1489
					if (expt < ndig || flags & ALT)
1490
					    PRINT (&decimal_point, 1);
1491
					PRINTANDPAD (cp, convbuf + ndig,
1492
						     ndig - expt, zeroes);
1493
				}
1494
 
1495
			} else {	/* 'a', 'A', 'e', or 'E' */
1496
				if (ndig > 1 || flags & ALT) {
1497
					PRINT (cp, 1);
1498
					cp++;
1499
					PRINT (&decimal_point, 1);
1500
					if (_fpvalue) {
1501
						PRINT (cp, ndig - 1);
1502
					} else	/* 0.[0..] */
1503
						/* __dtoa irregularity */
1504
						PAD (ndig - 1, zeroes);
1505
				} else	/* XeYYY */
1506
					PRINT (cp, 1);
1507
				PRINT (expstr, expsize);
1508
			}
1509
		}
1510
#else /* !FLOATING_POINT */
1511
		PRINT (cp, size);
1512
#endif
1513
		/* left-adjusting padding (always blank) */
1514
		if (flags & LADJUST)
1515
			PAD (width - realsz, blanks);
1516
 
1517
		/* finally, adjust ret */
1518
		ret += width > realsz ? width : realsz;
1519
 
1520
		FLUSH ();	/* copy out the I/O vectors */
1521
 
1522
                if (malloc_buf != NULL) {
1523
			_free_r (data, malloc_buf);
1524
			malloc_buf = NULL;
1525
		}
1526
	}
1527
done:
1528
	FLUSH ();
1529
error:
1530
	if (malloc_buf != NULL)
1531
		_free_r (data, malloc_buf);
1532
#ifndef STRING_ONLY
1533
	_newlib_flockfile_end (fp);
1534
#endif
1535
	return (__sferror (fp) ? EOF : ret);
1536
	/* NOTREACHED */
1537
}
1538
 
1539
#ifdef FLOATING_POINT
1540
 
1541
/* Using reentrant DATA, convert finite VALUE into a string of digits
1542
   with no decimal point, using NDIGITS precision and FLAGS as guides
1543
   to whether trailing zeros must be included.  Set *SIGN to nonzero
1544
   if VALUE was negative.  Set *DECPT to the exponent plus one.  Set
1545
   *LENGTH to the length of the returned string.  CH must be one of
1546
   [aAeEfFgG]; different from vfprintf.c:cvt(), the return string
1547
   lives in BUF regardless of CH.  LEN is the length of BUF, except
1548
   when CH is [aA], in which case LEN is not in use.  If BUF is not
1549
   large enough for the converted string, only the first LEN number
1550
   of characters will be returned in BUF, but *LENGTH will be set to
1551
   the full length of the string before the truncation.  */
1552
static wchar_t *
1553
wcvt(struct _reent *data, _PRINTF_FLOAT_TYPE value, int ndigits, int flags,
1554
     wchar_t *sign, int *decpt, int ch, int *length, wchar_t *buf, int len)
1555
{
1556
	int mode, dsgn;
1557
# ifdef _NO_LONGDBL
1558
	union double_union tmp;
1559
 
1560
	tmp.d = value;
1561
	if (word0 (tmp) & Sign_bit) { /* this will check for < 0 and -0.0 */
1562
		value = -value;
1563
		*sign = L'-';
1564
	} else
1565
		*sign = L'\0';
1566
# else /* !_NO_LONGDBL */
1567
	union
1568
	{
1569
	  struct ldieee ieee;
1570
	  _LONG_DOUBLE val;
1571
	} ld;
1572
 
1573
	ld.val = value;
1574
	if (ld.ieee.sign) { /* this will check for < 0 and -0.0 */
1575
		value = -value;
1576
		*sign = L'-';
1577
	} else
1578
		*sign = L'\0';
1579
# endif /* !_NO_LONGDBL */
1580
 
1581
# ifdef _WANT_IO_C99_FORMATS
1582
	if (ch == L'a' || ch == L'A') {
1583
		wchar_t *digits, *bp, *rve;
1584
		/* This code assumes FLT_RADIX is a power of 2.  The initial
1585
		   division ensures the digit before the decimal will be less
1586
		   than FLT_RADIX (unless it is rounded later).	 There is no
1587
		   loss of precision in these calculations.  */
1588
		value = FREXP (value, decpt) / 8;
1589
		if (!value)
1590
			*decpt = 1;
1591
		digits = ch == L'a' ? L"0123456789abcdef" : L"0123456789ABCDEF";
1592
		bp = buf;
1593
		do {
1594
			value *= 16;
1595
			mode = (int) value;
1596
			value -= mode;
1597
			*bp++ = digits[mode];
1598
		} while (ndigits-- && value);
1599
		if (value > 0.5 || (value == 0.5 && mode & 1)) {
1600
			/* round to even */
1601
			rve = bp;
1602
			while (*--rve == digits[0xf]) {
1603
				*rve = L'0';
1604
			}
1605
			*rve = *rve == L'9' ? digits[0xa] : *rve + 1;
1606
		} else {
1607
			while (ndigits-- >= 0) {
1608
				*bp++ = L'0';
1609
			}
1610
		}
1611
		*length = bp - buf;
1612
		return buf;
1613
	}
1614
# endif /* _WANT_IO_C99_FORMATS */
1615
	if (ch == L'f' || ch == L'F') {
1616
		mode = 3;		/* ndigits after the decimal point */
1617
	} else {
1618
		/* To obtain ndigits after the decimal point for the 'e'
1619
		 * and 'E' formats, round to ndigits + 1 significant
1620
		 * figures.
1621
		 */
1622
		if (ch == L'e' || ch == L'E') {
1623
			ndigits++;
1624
		}
1625
		mode = 2;		/* ndigits significant digits */
1626
	}
1627
 
1628
	{
1629
	  char *digits, *bp, *rve;
1630
#ifndef _MB_CAPABLE
1631
	  int i;
1632
#endif
1633
 
1634
	  digits = _DTOA_R (data, value, mode, ndigits, decpt, &dsgn, &rve);
1635
 
1636
	  if ((ch != L'g' && ch != L'G') || flags & ALT) {	/* Print trailing zeros */
1637
		bp = digits + ndigits;
1638
		if (ch == L'f' || ch == L'F') {
1639
			if (*digits == L'0' && value)
1640
				*decpt = -ndigits + 1;
1641
			bp += *decpt;
1642
		}
1643
		if (value == 0)	/* kludge for __dtoa irregularity */
1644
			rve = bp;
1645
		while (rve < bp)
1646
			*rve++ = '0';
1647
	  }
1648
 
1649
	  *length = rve - digits; /* full length of the string */
1650
#ifdef _MB_CAPABLE
1651
	  _mbsnrtowcs_r (data, buf, (const char **) &digits, *length,
1652
			 len, NULL);
1653
#else
1654
	  for (i = 0; i < *length && i < len; ++i)
1655
	    buf[i] = (wchar_t) digits[i];
1656
#endif
1657
	  return buf;
1658
	}
1659
}
1660
 
1661
static int
1662
wexponent(wchar_t *p0, int exp, int fmtch)
1663
{
1664
	register wchar_t *p, *t;
1665
	wchar_t expbuf[MAXEXPLEN];
1666
# ifdef _WANT_IO_C99_FORMATS
1667
	int isa = fmtch == L'a' || fmtch == L'A';
1668
# else
1669
#  define isa 0
1670
# endif
1671
 
1672
	p = p0;
1673
	*p++ = isa ? L'p' - L'a' + fmtch : fmtch;
1674
	if (exp < 0) {
1675
		exp = -exp;
1676
		*p++ = L'-';
1677
	}
1678
	else
1679
		*p++ = L'+';
1680
	t = expbuf + MAXEXPLEN;
1681
	if (exp > 9) {
1682
		do {
1683
			*--t = to_char (exp % 10);
1684
		} while ((exp /= 10) > 9);
1685
		*--t = to_char (exp);
1686
		for (; t < expbuf + MAXEXPLEN; *p++ = *t++);
1687
	}
1688
	else {
1689
		if (!isa)
1690
			*p++ = L'0';
1691
		*p++ = to_char (exp);
1692
	}
1693
	return (p - p0);
1694
}
1695
#endif /* FLOATING_POINT */
1696
 
1697
 
1698
#ifndef _NO_POS_ARGS
1699
 
1700
/* Positional argument support.
1701
   Written by Jeff Johnston
1702
 
1703
   Copyright (c) 2002 Red Hat Incorporated.
1704
   All rights reserved.
1705
 
1706
   Redistribution and use in source and binary forms, with or without
1707
   modification, are permitted provided that the following conditions are met:
1708
 
1709
      Redistributions of source code must retain the above copyright
1710
      notice, this list of conditions and the following disclaimer.
1711
 
1712
      Redistributions in binary form must reproduce the above copyright
1713
      notice, this list of conditions and the following disclaimer in the
1714
      documentation and/or other materials provided with the distribution.
1715
 
1716
      The name of Red Hat Incorporated may not be used to endorse
1717
      or promote products derived from this software without specific
1718
      prior written permission.
1719
 
1720
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1721
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1722
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1723
   DISCLAIMED.  IN NO EVENT SHALL RED HAT INCORPORATED BE LIABLE FOR ANY
1724
   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1725
   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1726
   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1727
   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1728
   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1729
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
1730
 
1731
/* function to get positional parameter N where n = N - 1 */
1732
static union arg_val *
1733
_DEFUN(get_arg, (data, n, fmt, ap, numargs_p, args, arg_type, last_fmt),
1734
       struct _reent *data _AND
1735
       int n               _AND
1736
       wchar_t *fmt        _AND
1737
       va_list *ap         _AND
1738
       int *numargs_p      _AND
1739
       union arg_val *args _AND
1740
       int *arg_type       _AND
1741
       wchar_t **last_fmt)
1742
{
1743
  wchar_t ch;
1744
  int number, flags;
1745
  int spec_type;
1746
  int numargs = *numargs_p;
1747
  __CH_CLASS chtype;
1748
  __STATE state, next_state;
1749
  __ACTION action;
1750
  int pos, last_arg;
1751
  int max_pos_arg = n;
1752
  /* Only need types that can be reached via vararg promotions.  */
1753
  enum types { INT, LONG_INT, QUAD_INT, CHAR_PTR, DOUBLE, LONG_DOUBLE, WIDE_CHAR };
1754
 
1755
  /* if this isn't the first call, pick up where we left off last time */
1756
  if (*last_fmt != NULL)
1757
    fmt = *last_fmt;
1758
 
1759
  /* we need to process either to end of fmt string or until we have actually
1760
     read the desired parameter from the vararg list. */
1761
  while (*fmt && n >= numargs)
1762
    {
1763
      while (*fmt != L'\0' && *fmt != L'%')
1764
				fmt += 1;
1765
 
1766
      if (*fmt == L'\0')
1767
				break;
1768
      state = START;
1769
      flags = 0;
1770
      pos = -1;
1771
      number = 0;
1772
      spec_type = INT;
1773
 
1774
      /* Use state/action table to process format specifiers.  We ignore invalid
1775
         formats and we are only interested in information that tells us how to
1776
         read the vararg list. */
1777
      while (state != DONE)
1778
	{
1779
	  ch = *fmt++;
1780
	  chtype = ch < (wchar_t) 256 ? __chclass[ch] : OTHER;
1781
	  next_state = __state_table[state][chtype];
1782
	  action = __action_table[state][chtype];
1783
	  state = next_state;
1784
 
1785
	  switch (action)
1786
	    {
1787
	    case GETMOD:  /* we have format modifier */
1788
	      switch (ch)
1789
		{
1790
		case L'h':
1791
		  /* No flag needed, since short and char promote to int.  */
1792
		  break;
1793
		case L'L':
1794
		  flags |= LONGDBL;
1795
		  break;
1796
		case L'q':
1797
		  flags |= QUADINT;
1798
		  break;
1799
# ifdef _WANT_IO_C99_FORMATS
1800
		case L'j':
1801
		  if (sizeof (intmax_t) == sizeof (long))
1802
		    flags |= LONGINT;
1803
		  else
1804
		    flags |= QUADINT;
1805
		  break;
1806
		case L'z':
1807
		  if (sizeof (size_t) <= sizeof (int))
1808
		    /* no flag needed */;
1809
		  else if (sizeof (size_t) <= sizeof (long))
1810
		    flags |= LONGINT;
1811
		  else
1812
		    /* POSIX states that at least one programming
1813
		       environment must support size_t no wider than
1814
		       long, but that means other environments can
1815
		       have size_t as wide as long long.  */
1816
		    flags |= QUADINT;
1817
		  break;
1818
		case L't':
1819
		  if (sizeof (ptrdiff_t) <= sizeof (int))
1820
		    /* no flag needed */;
1821
		  else if (sizeof (ptrdiff_t) <= sizeof (long))
1822
		    flags |= LONGINT;
1823
		  else
1824
		    /* POSIX states that at least one programming
1825
		       environment must support ptrdiff_t no wider than
1826
		       long, but that means other environments can
1827
		       have ptrdiff_t as wide as long long.  */
1828
		    flags |= QUADINT;
1829
		  break;
1830
# endif /* _WANT_IO_C99_FORMATS */
1831
		case L'l':
1832
		default:
1833
# if defined _WANT_IO_C99_FORMATS || !defined _NO_LONGLONG
1834
		  if (*fmt == L'l')
1835
		    {
1836
		      flags |= QUADINT;
1837
		      ++fmt;
1838
		    }
1839
		  else
1840
# endif
1841
		    flags |= LONGINT;
1842
		  break;
1843
		}
1844
	      break;
1845
	    case GETARG: /* we have format specifier */
1846
	      {
1847
		numargs &= (MAX_POS_ARGS - 1);
1848
		/* process the specifier and translate it to a type to fetch from varargs */
1849
		switch (ch)
1850
		  {
1851
		  case L'd':
1852
		  case L'i':
1853
		  case L'o':
1854
		  case L'x':
1855
		  case L'X':
1856
		  case L'u':
1857
		    if (flags & LONGINT)
1858
		      spec_type = LONG_INT;
1859
# ifndef _NO_LONGLONG
1860
		    else if (flags & QUADINT)
1861
		      spec_type = QUAD_INT;
1862
# endif
1863
		    else
1864
		      spec_type = INT;
1865
		    break;
1866
# ifdef _WANT_IO_C99_FORMATS
1867
		  case L'a':
1868
		  case L'A':
1869
		  case L'F':
1870
# endif
1871
		  case L'f':
1872
		  case L'g':
1873
		  case L'G':
1874
		  case L'E':
1875
		  case L'e':
1876
# ifndef _NO_LONGDBL
1877
		    if (flags & LONGDBL)
1878
		      spec_type = LONG_DOUBLE;
1879
		    else
1880
# endif
1881
		      spec_type = DOUBLE;
1882
		    break;
1883
		  case L's':
1884
# ifdef _WANT_IO_C99_FORMATS
1885
		  case L'S':	/* POSIX extension */
1886
# endif
1887
		  case L'p':
1888
		  case L'n':
1889
		    spec_type = CHAR_PTR;
1890
		    break;
1891
		  case L'c':
1892
# ifdef _WANT_IO_C99_FORMATS
1893
		    if (flags & LONGINT)
1894
		      spec_type = WIDE_CHAR;
1895
		    else
1896
# endif
1897
		      spec_type = INT;
1898
		    break;
1899
# ifdef _WANT_IO_C99_FORMATS
1900
		  case L'C':	/* POSIX extension */
1901
		    spec_type = WIDE_CHAR;
1902
		    break;
1903
# endif
1904
		  }
1905
 
1906
		/* if we have a positional parameter, just store the type, otherwise
1907
		   fetch the parameter from the vararg list */
1908
		if (pos != -1)
1909
		  arg_type[pos] = spec_type;
1910
		else
1911
		  {
1912
		    switch (spec_type)
1913
		      {
1914
		      case LONG_INT:
1915
			args[numargs++].val_long = va_arg (*ap, long);
1916
			break;
1917
		      case QUAD_INT:
1918
			args[numargs++].val_quad_t = va_arg (*ap, quad_t);
1919
			break;
1920
		      case WIDE_CHAR:
1921
			args[numargs++].val_wint_t = va_arg (*ap, wint_t);
1922
			break;
1923
		      case INT:
1924
			args[numargs++].val_int = va_arg (*ap, int);
1925
			break;
1926
		      case CHAR_PTR:
1927
			args[numargs++].val_wchar_ptr_t = va_arg (*ap, wchar_t *);
1928
			break;
1929
		      case DOUBLE:
1930
			args[numargs++].val_double = va_arg (*ap, double);
1931
			break;
1932
		      case LONG_DOUBLE:
1933
			args[numargs++].val__LONG_DOUBLE = va_arg (*ap, _LONG_DOUBLE);
1934
			break;
1935
		      }
1936
		  }
1937
	      }
1938
	      break;
1939
	    case GETPOS: /* we have positional specifier */
1940
	      if (arg_type[0] == -1)
1941
		memset (arg_type, 0, sizeof (int) * MAX_POS_ARGS);
1942
	      pos = number - 1;
1943
	      max_pos_arg = (max_pos_arg > pos ? max_pos_arg : pos);
1944
	      break;
1945
	    case PWPOS:  /* we have positional specifier for width or precision */
1946
	      if (arg_type[0] == -1)
1947
		memset (arg_type, 0, sizeof (int) * MAX_POS_ARGS);
1948
	      number -= 1;
1949
	      arg_type[number] = INT;
1950
	      max_pos_arg = (max_pos_arg > number ? max_pos_arg : number);
1951
	      break;
1952
	    case GETPWB: /* we require format pushback */
1953
	      --fmt;
1954
	      /* fallthrough */
1955
	    case GETPW:  /* we have a variable precision or width to acquire */
1956
	      args[numargs++].val_int = va_arg (*ap, int);
1957
	      break;
1958
	    case NUMBER: /* we have a number to process */
1959
	      number = (ch - '0');
1960
	      while ((ch = *fmt) != '\0' && is_digit (ch))
1961
		{
1962
		  number = number * 10 + (ch - '0');
1963
		  ++fmt;
1964
		}
1965
	      break;
1966
	    case SKIPNUM: /* we have a number to skip */
1967
	      while ((ch = *fmt) != '\0' && is_digit (ch))
1968
		++fmt;
1969
	      break;
1970
	    case NOOP:
1971
	    default:
1972
	      break; /* do nothing */
1973
	    }
1974
	}
1975
    }
1976
 
1977
  /* process all arguments up to at least the one we are looking for and if we
1978
     have seen the end of the string, then process up to the max argument needed */
1979
  if (*fmt == '\0')
1980
    last_arg = max_pos_arg;
1981
  else
1982
    last_arg = n;
1983
 
1984
  while (numargs <= last_arg)
1985
    {
1986
      switch (arg_type[numargs])
1987
	{
1988
	case LONG_INT:
1989
	  args[numargs++].val_long = va_arg (*ap, long);
1990
	  break;
1991
	case QUAD_INT:
1992
	  args[numargs++].val_quad_t = va_arg (*ap, quad_t);
1993
	  break;
1994
	case CHAR_PTR:
1995
	  args[numargs++].val_wchar_ptr_t = va_arg (*ap, wchar_t *);
1996
	  break;
1997
	case DOUBLE:
1998
	  args[numargs++].val_double = va_arg (*ap, double);
1999
	  break;
2000
	case LONG_DOUBLE:
2001
	  args[numargs++].val__LONG_DOUBLE = va_arg (*ap, _LONG_DOUBLE);
2002
	  break;
2003
	case WIDE_CHAR:
2004
	  args[numargs++].val_wint_t = va_arg (*ap, wint_t);
2005
	  break;
2006
	case INT:
2007
	default:
2008
	  args[numargs++].val_int = va_arg (*ap, int);
2009
	  break;
2010
	}
2011
    }
2012
 
2013
  /* alter the global numargs value and keep a reference to the last bit of the fmt
2014
     string we processed here because the caller will continue processing where we started */
2015
  *numargs_p = numargs;
2016
  *last_fmt = fmt;
2017
  return &args[n];
2018
}
2019
#endif /* !_NO_POS_ARGS */