authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-07 23:59:42-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-08 11:52:38-07:00
log9df0177f334ea02dc8c269b662edb3c013c7ffff
tree9fa31e8e68ceedf0fd8ee95c7db11325c81374f0
parent99922c2708bbbda4fcdc16a45a5d3071dd1495c0

mingw: add the mingw stdio functions back

We would rather use the ucrt for these, but sometimes dependencies on the mingw stdio functions creep in. 仕方ない. The cost is only paid if they are used; otherwise the symbols are garbage-collected at link time.

31 files changed, 7501 insertions(+), 0 deletions(-)

lib/libc/mingw/stdio/mingw_asprintf.c created+32
......@@ -0,0 +1,32 @@
1#define _GNU_SOURCE
2#define __CRT__NO_INLINE
3
4#include <stdio.h>
5#include <stdlib.h>
6#include <stdarg.h>
7
8int __mingw_asprintf(char ** __restrict__ ret,
9 const char * __restrict__ format,
10 ...) {
11 va_list ap;
12 int len;
13 va_start(ap,format);
14 /* Get Length */
15 len = __mingw_vsnprintf(NULL,0,format,ap);
16 if (len < 0) goto _end;
17 /* +1 for \0 terminator. */
18 *ret = malloc(len + 1);
19 /* Check malloc fail*/
20 if (!*ret) {
21 len = -1;
22 goto _end;
23 }
24 /* Write String */
25 __mingw_vsnprintf(*ret,len+1,format,ap);
26 /* Terminate explicitly */
27 (*ret)[len] = '\0';
28 _end:
29 va_end(ap);
30 return len;
31}
32
lib/libc/mingw/stdio/mingw_dummy__lock.c created+12
......@@ -0,0 +1,12 @@
1/**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the mingw-w64 runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6
7#include <internal.h>
8
9void __cdecl _lock(int locknum);
10void __cdecl _unlock(int locknum);
11void __cdecl _lock(__UNUSED_PARAM(int locknum)) { }
12void __cdecl _unlock(__UNUSED_PARAM(int locknum)) { }
lib/libc/mingw/stdio/mingw_fprintf.c created+58
......@@ -0,0 +1,58 @@
1/* fprintf.c
2 *
3 * $Id: fprintf.c,v 1.1 2008/08/11 22:41:55 keithmarshall Exp $
4 *
5 * Provides an implementation of the "fprintf" function, conforming
6 * generally to C99 and SUSv3/POSIX specifications, with extensions
7 * to support Microsoft's non-standard format specifications. This
8 * is included in libmingwex.a, whence it may replace the Microsoft
9 * function of the same name.
10 *
11 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
12 *
13 * This implementation of "fprintf" will normally be invoked by calling
14 * "__mingw_fprintf()" in preference to a direct reference to "fprintf()"
15 * itself; this leaves the MSVCRT implementation as the default, which
16 * will be deployed when user code invokes "fprint()". Users who then
17 * wish to use this implementation may either call "__mingw_fprintf()"
18 * directly, or may use conditional preprocessor defines, to redirect
19 * references to "fprintf()" to "__mingw_fprintf()".
20 *
21 * Compiling this module with "-D INSTALL_AS_DEFAULT" will change this
22 * recommended convention, such that references to "fprintf()" in user
23 * code will ALWAYS be redirected to "__mingw_fprintf()"; if this option
24 * is adopted, then users wishing to use the MSVCRT implementation of
25 * "fprintf()" will be forced to use a "back-door" mechanism to do so.
26 * Such a "back-door" mechanism is provided with MinGW, allowing the
27 * MSVCRT implementation to be called as "__msvcrt_fprintf()"; however,
28 * since users may not expect this behaviour, a standard libmingwex.a
29 * installation does not employ this option.
30 *
31 *
32 * This is free software. You may redistribute and/or modify it as you
33 * see fit, without restriction of copyright.
34 *
35 * This software is provided "as is", in the hope that it may be useful,
36 * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
37 * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE. At no
38 * time will the author accept any form of liability for any damages,
39 * however caused, resulting from the use of this software.
40 *
41 */
42#include <stdio.h>
43#include <stdarg.h>
44
45#include "mingw_pformat.h"
46
47int __cdecl __fprintf (FILE *, const APICHAR *, ...) __MINGW_NOTHROW;
48
49int __cdecl __fprintf(FILE *stream, const APICHAR *fmt, ...)
50{
51 register int retval;
52 va_list argv; va_start( argv, fmt );
53 _lock_file( stream );
54 retval = __pformat( PFORMAT_TO_FILE | PFORMAT_NOLIMIT, stream, 0, fmt, argv );
55 _unlock_file( stream );
56 va_end( argv );
57 return retval;
58}
lib/libc/mingw/stdio/mingw_fprintfw.c created+9
......@@ -0,0 +1,9 @@
1/**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the mingw-w64 runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6#define __BUILD_WIDEAPI 1
7
8#include "mingw_fprintf.c"
9
lib/libc/mingw/stdio/mingw_fscanf.c created+21
......@@ -0,0 +1,21 @@
1#include <stdarg.h>
2#include <stdio.h>
3#include <stdlib.h>
4
5extern int __mingw_vfscanf (FILE *stream, const char *format, va_list argp);
6
7int __mingw_fscanf (FILE *stream, const char *format, ...);
8
9int
10__mingw_fscanf (FILE *stream, const char *format, ...)
11{
12 va_list argp;
13 int r;
14
15 va_start (argp, format);
16 r = __mingw_vfscanf (stream, format, argp);
17 va_end (argp);
18
19 return r;
20}
21
lib/libc/mingw/stdio/mingw_fwscanf.c created+21
......@@ -0,0 +1,21 @@
1#include <stdarg.h>
2#include <stdio.h>
3#include <stdlib.h>
4
5extern int __mingw_vfwscanf (FILE *stream, const wchar_t *format, va_list argp);
6
7int __mingw_fwscanf (FILE *stream, const wchar_t *format, ...);
8
9int
10__mingw_fwscanf (FILE *stream, const wchar_t *format, ...)
11{
12 va_list argp;
13 int r;
14
15 va_start (argp, format);
16 r = __mingw_vfwscanf (stream, format, argp);
17 va_end (argp);
18
19 return r;
20}
21
lib/libc/mingw/stdio/mingw_lock.c created+102
......@@ -0,0 +1,102 @@
1#define _CRTIMP
2#include <stdio.h>
3#include <synchapi.h>
4#include "internal.h"
5
6/***
7 * Copy of MS functions _lock_file, _unlock_file which are missing from
8 * msvcrt.dll and msvcr80.dll. They are needed to atomic/lock stdio
9 * functions (printf, fprintf, vprintf, vfprintf). We need exactly the same
10 * lock that MS uses in msvcrt.dll because we can mix mingw-w64 code with
11 * original MS functions (puts, fputs for example).
12***/
13
14
15_CRTIMP void __cdecl _lock(int locknum);
16_CRTIMP void __cdecl _unlock(int locknum);
17#define _STREAM_LOCKS 16
18#define _IOLOCKED 0x8000
19
20
21/***
22* _lock_file - Lock a FILE
23*
24*Purpose:
25* Assert the lock for a stdio-level file
26*
27*Entry:
28* pf = __piob[] entry (pointer to a FILE or _FILEX)
29*
30*Exit:
31*
32*Exceptions:
33*
34*******************************************************************************/
35
36void __cdecl _lock_file( FILE *pf )
37{
38 /*
39 * The way the FILE (pointed to by pf) is locked depends on whether
40 * it is part of _iob[] or not
41 */
42 if ( (pf >= __acrt_iob_func(0)) && (pf <= __acrt_iob_func(_IOB_ENTRIES-1)) )
43 {
44 /*
45 * FILE lies in _iob[] so the lock lies in _locktable[].
46 */
47 _lock( _STREAM_LOCKS + (int)(pf - __acrt_iob_func(0)) );
48 /* We set _IOLOCKED to indicate we locked the stream */
49 pf->_flag |= _IOLOCKED;
50 }
51 else
52 /*
53 * Not part of _iob[]. Therefore, *pf is a _FILEX and the
54 * lock field of the struct is an initialized critical
55 * section.
56 */
57 EnterCriticalSection( &(((_FILEX *)pf)->lock) );
58}
59
60void *__MINGW_IMP_SYMBOL(_lock_file) = _lock_file;
61
62
63/***
64* _unlock_file - Unlock a FILE
65*
66*Purpose:
67* Release the lock for a stdio-level file
68*
69*Entry:
70* pf = __piob[] entry (pointer to a FILE or _FILEX)
71*
72*Exit:
73*
74*Exceptions:
75*
76*******************************************************************************/
77
78void __cdecl _unlock_file( FILE *pf )
79{
80 /*
81 * The way the FILE (pointed to by pf) is unlocked depends on whether
82 * it is part of _iob[] or not
83 */
84 if ( (pf >= __acrt_iob_func(0)) && (pf <= __acrt_iob_func(_IOB_ENTRIES-1)) )
85 {
86 /*
87 * FILE lies in _iob[] so the lock lies in _locktable[].
88 * We reset _IOLOCKED to indicate we unlock the stream.
89 */
90 pf->_flag &= ~_IOLOCKED;
91 _unlock( _STREAM_LOCKS + (int)(pf - __acrt_iob_func(0)) );
92 }
93 else
94 /*
95 * Not part of _iob[]. Therefore, *pf is a _FILEX and the
96 * lock field of the struct is an initialized critical
97 * section.
98 */
99 LeaveCriticalSection( &(((_FILEX *)pf)->lock) );
100}
101
102void *__MINGW_IMP_SYMBOL(_unlock_file) = _unlock_file;
lib/libc/mingw/stdio/mingw_pformat.c created+3312
......@@ -0,0 +1,3312 @@
1/* pformat.c
2 *
3 * $Id: pformat.c,v 1.9 2011/01/07 22:57:00 keithmarshall Exp $
4 *
5 * Provides a core implementation of the formatting capabilities
6 * common to the entire `printf()' family of functions; it conforms
7 * generally to C99 and SUSv3/POSIX specifications, with extensions
8 * to support Microsoft's non-standard format specifications.
9 *
10 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
11 *
12 * This is free software. You may redistribute and/or modify it as you
13 * see fit, without restriction of copyright.
14 *
15 * This software is provided "as is", in the hope that it may be useful,
16 * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
17 * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE. At no
18 * time will the author accept any form of liability for any damages,
19 * however caused, resulting from the use of this software.
20 *
21 * The elements of this implementation which deal with the formatting
22 * of floating point numbers, (i.e. the `%e', `%E', `%f', `%F', `%g'
23 * and `%G' format specifiers, but excluding the hexadecimal floating
24 * point `%a' and `%A' specifiers), make use of the `__gdtoa' function
25 * written by David M. Gay, and are modelled on his sample code, which
26 * has been deployed under its accompanying terms of use:--
27 *
28 ******************************************************************
29 * Copyright (C) 1997, 1999, 2001 Lucent Technologies
30 * All Rights Reserved
31 *
32 * Permission to use, copy, modify, and distribute this software and
33 * its documentation for any purpose and without fee is hereby
34 * granted, provided that the above copyright notice appear in all
35 * copies and that both that the copyright notice and this
36 * permission notice and warranty disclaimer appear in supporting
37 * documentation, and that the name of Lucent or any of its entities
38 * not be used in advertising or publicity pertaining to
39 * distribution of the software without specific, written prior
40 * permission.
41 *
42 * LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
43 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
44 * IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
45 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
46 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
47 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
48 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
49 * THIS SOFTWARE.
50 ******************************************************************
51 *
52 */
53
54#define __LARGE_MBSTATE_T
55
56#ifdef HAVE_CONFIG_H
57#include "config.h"
58#endif
59
60#include <stdio.h>
61#include <stdarg.h>
62#include <stddef.h>
63#include <stdint.h>
64#include <stdlib.h>
65#include <string.h>
66#include <limits.h>
67#include <locale.h>
68#include <wchar.h>
69
70#ifdef __ENABLE_DFP
71#ifndef __STDC_WANT_DEC_FP__
72#define __STDC_WANT_DEC_FP__ 1
73#endif
74
75#include "../math/DFP/dfp_internal.h"
76#endif /* __ENABLE_DFP */
77
78#include <math.h>
79
80/* FIXME: The following belongs in values.h, but current MinGW
81 * has nothing useful there! OTOH, values.h is not a standard
82 * header, and its use may be considered obsolete; perhaps it
83 * is better to just keep these definitions here.
84 */
85
86#include <pshpack1.h>
87/* workaround gcc bug */
88#if defined(__GNUC__) && !defined(__clang__)
89#define ATTRIB_GCC_STRUCT __attribute__((gcc_struct))
90#else
91#define ATTRIB_GCC_STRUCT
92#endif
93typedef struct ATTRIB_GCC_STRUCT __tI128 {
94 int64_t digits[2];
95} __tI128;
96
97typedef struct ATTRIB_GCC_STRUCT __tI128_2 {
98 uint32_t digits32[4];
99} __tI128_2;
100
101typedef union ATTRIB_GCC_STRUCT __uI128 {
102 __tI128 t128;
103 __tI128_2 t128_2;
104} __uI128;
105#include <poppack.h>
106
107#ifndef _VALUES_H
108/*
109 * values.h
110 *
111 */
112#define _VALUES_H
113
114#include <limits.h>
115
116#define _TYPEBITS(type) (sizeof(type) * CHAR_BIT)
117
118#if defined(__ENABLE_PRINTF128) || defined(__ENABLE_DFP)
119#define LLONGBITS _TYPEBITS(__tI128)
120#else
121#define LLONGBITS _TYPEBITS(long long)
122#endif
123
124#endif /* !defined _VALUES_H -- end of file */
125
126#include "mingw_pformat.h"
127
128/* Bit-map constants, defining the internal format control
129 * states, which propagate through the flags.
130 */
131#define PFORMAT_GROUPED 0x00001000
132#define PFORMAT_HASHED 0x00000800
133#define PFORMAT_LJUSTIFY 0x00000400
134#define PFORMAT_ZEROFILL 0x00000200
135
136#define PFORMAT_JUSTIFY (PFORMAT_LJUSTIFY | PFORMAT_ZEROFILL)
137#define PFORMAT_IGNORE -1
138
139#define PFORMAT_SIGNED 0x000001C0
140#define PFORMAT_POSITIVE 0x00000100
141#define PFORMAT_NEGATIVE 0x00000080
142#define PFORMAT_ADDSPACE 0x00000040
143
144#define PFORMAT_XCASE 0x00000020
145
146#define PFORMAT_LDOUBLE 0x00000004
147
148#ifdef __ENABLE_DFP
149#define PFORMAT_DECIM32 0x00020000
150#define PFORMAT_DECIM64 0x00040000
151#define PFORMAT_DECIM128 0x00080000
152#endif
153
154/* `%o' format digit extraction mask, and shift count...
155 * (These are constant, and do not propagate through the flags).
156 */
157#define PFORMAT_OMASK 0x00000007
158#define PFORMAT_OSHIFT 0x00000003
159
160/* `%x' and `%X' format digit extraction mask, and shift count...
161 * (These are constant, and do not propagate through the flags).
162 */
163#define PFORMAT_XMASK 0x0000000F
164#define PFORMAT_XSHIFT 0x00000004
165
166/* The radix point character, used in floating point formats, is
167 * localised on the basis of the active LC_NUMERIC locale category.
168 * It is stored locally, as a `wchar_t' entity, which is converted
169 * to a (possibly multibyte) character on output. Initialisation
170 * of the stored `wchar_t' entity, together with a record of its
171 * effective multibyte character length, is required each time
172 * `__pformat()' is entered, (static storage would not be thread
173 * safe), but this initialisation is deferred until it is actually
174 * needed; on entry, the effective character length is first set to
175 * the following value, (and the `wchar_t' entity is zeroed), to
176 * indicate that a call of `localeconv()' is needed, to complete
177 * the initialisation.
178 */
179#define PFORMAT_RPINIT -3
180
181/* The floating point format handlers return the following value
182 * for the radix point position index, when the argument value is
183 * infinite, or not a number.
184 */
185#define PFORMAT_INFNAN -32768
186
187typedef union
188{
189 /* A data type agnostic representation,
190 * for printf arguments of any integral data type...
191 */
192 signed long __pformat_long_t;
193 signed long long __pformat_llong_t;
194 unsigned long __pformat_ulong_t;
195 unsigned long long __pformat_ullong_t;
196 unsigned short __pformat_ushort_t;
197 unsigned char __pformat_uchar_t;
198 signed short __pformat_short_t;
199 signed char __pformat_char_t;
200 void * __pformat_ptr_t;
201 __uI128 __pformat_u128_t;
202} __pformat_intarg_t;
203
204typedef enum
205{
206 /* Format interpreter state indices...
207 * (used to identify the active phase of format string parsing).
208 */
209 PFORMAT_INIT = 0,
210 PFORMAT_SET_WIDTH,
211 PFORMAT_GET_PRECISION,
212 PFORMAT_SET_PRECISION,
213 PFORMAT_END
214} __pformat_state_t;
215
216typedef enum
217{
218 /* Argument length classification indices...
219 * (used for arguments representing integer data types).
220 */
221 PFORMAT_LENGTH_INT = 0,
222 PFORMAT_LENGTH_SHORT,
223 PFORMAT_LENGTH_LONG,
224 PFORMAT_LENGTH_LLONG,
225 PFORMAT_LENGTH_LLONG128,
226 PFORMAT_LENGTH_CHAR
227} __pformat_length_t;
228/*
229 * And a macro to map any arbitrary data type to an appropriate
230 * matching index, selected from those above; the compiler should
231 * collapse this to a simple assignment.
232 */
233
234#ifdef __GNUC__
235/* provides for some deadcode elimination via compile time eval */
236#define __pformat_arg_length(x) \
237__builtin_choose_expr ( \
238 __builtin_types_compatible_p (typeof (x), __tI128), \
239 PFORMAT_LENGTH_LLONG128, \
240 __builtin_choose_expr ( \
241 __builtin_types_compatible_p (typeof (x), long long), \
242 PFORMAT_LENGTH_LLONG, \
243 __builtin_choose_expr ( \
244 __builtin_types_compatible_p (typeof (x), long), \
245 PFORMAT_LENGTH_LONG, \
246 __builtin_choose_expr ( \
247 __builtin_types_compatible_p (typeof (x), short), \
248 PFORMAT_LENGTH_SHORT, \
249 __builtin_choose_expr ( \
250 __builtin_types_compatible_p (typeof (x), char), \
251 PFORMAT_LENGTH_CHAR, \
252 __builtin_choose_expr ( \
253 __builtin_types_compatible_p (typeof (x), __uI128), \
254 PFORMAT_LENGTH_LLONG128, \
255 __builtin_choose_expr ( \
256 __builtin_types_compatible_p (typeof (x), unsigned long), \
257 PFORMAT_LENGTH_LONG, \
258 __builtin_choose_expr ( \
259 __builtin_types_compatible_p (typeof (x), unsigned long long), \
260 PFORMAT_LENGTH_LLONG, \
261 __builtin_choose_expr ( \
262 __builtin_types_compatible_p (typeof (x), unsigned short), \
263 PFORMAT_LENGTH_SHORT, \
264 __builtin_choose_expr ( \
265 __builtin_types_compatible_p (typeof (x), unsigned char), \
266 PFORMAT_LENGTH_CHAR, \
267 PFORMAT_LENGTH_INT))))))))))
268
269#else
270#define __pformat_arg_length( type ) \
271 sizeof( type ) == sizeof( __tI128 ) ? PFORMAT_LENGTH_LLONG128 : \
272 sizeof( type ) == sizeof( long long ) ? PFORMAT_LENGTH_LLONG : \
273 sizeof( type ) == sizeof( long ) ? PFORMAT_LENGTH_LONG : \
274 sizeof( type ) == sizeof( short ) ? PFORMAT_LENGTH_SHORT : \
275 sizeof( type ) == sizeof( char ) ? PFORMAT_LENGTH_CHAR : \
276 /* should never need this default */ PFORMAT_LENGTH_INT
277#endif
278
279typedef struct
280{
281 /* Formatting and output control data...
282 * An instance of this control block is created, (on the stack),
283 * for each call to `__pformat()', and is passed by reference to
284 * each of the output handlers, as required.
285 */
286 void * dest;
287 int flags;
288 int width;
289 int precision;
290 int rplen;
291 wchar_t rpchr;
292 int thousands_chr_len;
293 wchar_t thousands_chr;
294 int count;
295 int quota;
296 int expmin;
297} __pformat_t;
298
299#if defined(__ENABLE_PRINTF128) || defined(__ENABLE_DFP)
300/* trim leading, leave at least n characters */
301static char * __bigint_trim_leading_zeroes(char *in, int n){
302 char *src = in;
303 int len = strlen(in);
304 while( len > n && *++src == '0') len--;
305
306 /* we want to null terminator too */
307 memmove(in, src, strlen(src) + 1);
308 return in;
309}
310
311/* LSB first */
312static
313void __bigint_to_string(const uint32_t *digits, const uint32_t digitlen, char *buff, const uint32_t bufflen){
314 int64_t digitsize = sizeof(*digits) * 8;
315 int64_t shiftpos = digitlen * digitsize - 1;
316 memset(buff, 0, bufflen);
317
318 while(shiftpos >= 0) {
319 /* increment */
320 for(uint32_t i = 0; i < bufflen - 1; i++){
321 buff[i] += (buff[i] > 4) ? 3 : 0;
322 }
323
324 /* shift left */
325 for(uint32_t i = 0; i < bufflen - 1; i++)
326 buff[i] <<= 1;
327
328 /* shift in */
329 buff[bufflen - 2] |= digits[shiftpos / digitsize] & (0x1 << (shiftpos % digitsize)) ? 1 : 0;
330
331 /* overflow check */
332 for(uint32_t i = bufflen - 1; i > 0; i--){
333 buff[i - 1] |= (buff[i] > 0xf);
334 buff[i] &= 0x0f;
335 }
336 shiftpos--;
337 }
338
339 for(uint32_t i = 0; i < bufflen - 1; i++){
340 buff[i] += '0';
341 }
342 buff[bufflen - 1] = '\0';
343}
344
345#if defined(__ENABLE_PRINTF128)
346/* LSB first, hex version */
347static
348void __bigint_to_stringx(const uint32_t *digits, const uint32_t digitlen, char *buff, const uint32_t bufflen, int upper){
349 int32_t stride = sizeof(*digits) * 2;
350 uint32_t lastpos = 0;
351
352 for(uint32_t i = 0; i < digitlen * stride; i++){
353 int32_t buffpos = bufflen - i - 2;
354 buff[buffpos] = (digits[ i / stride ] & (0xf << 4 * (i % stride))) >> ( 4 * (i % stride));
355 buff[buffpos] += (buff[buffpos] > 9) ? ((upper) ? 0x7 : 0x27) : 0;
356 buff[buffpos] += '0';
357 lastpos = buffpos;
358 if(buffpos == 0) break; /* sanity check */
359 }
360 memset(buff, '0', lastpos);
361 buff[bufflen - 1] = '\0';
362}
363
364/* LSB first, octet version */
365static
366void __bigint_to_stringo(const uint32_t *digits, const uint32_t digitlen, char *buff, const uint32_t bufflen){
367 const uint32_t digitsize = sizeof(*digits) * 8;
368 const uint64_t bits = digitsize * digitlen;
369 uint32_t pos = bufflen - 2;
370 uint32_t reg = 0;
371 for(uint32_t i = 0; i <= bits; i++){
372 reg |= (digits[ i / digitsize] & (0x1 << (i % digitsize))) ? 1 << (i % 3) : 0;
373 if( (i && ( i + 1) % 3 == 0) || (i + 1) == bits){ /* make sure all is committed after last bit */
374 buff[pos] = '0' + reg;
375 reg = 0;
376 if(!pos) break; /* sanity check */
377 pos--;
378 }
379 }
380 if(pos < bufflen - 1)
381 memset(buff,'0', pos + 1);
382 buff[bufflen - 1] = '\0';
383}
384#endif /* defined(__ENABLE_PRINTF128) */
385#endif /* defined(__ENABLE_PRINTF128) || defined(__ENABLE_DFP) */
386
387static
388void __pformat_putc( int c, __pformat_t *stream )
389{
390 /* Place a single character into the `__pformat()' output queue,
391 * provided any specified output quota has not been exceeded.
392 */
393 if( (stream->flags & PFORMAT_NOLIMIT) || (stream->quota > stream->count) )
394 {
395 /* Either there was no quota specified,
396 * or the active quota has not yet been reached.
397 */
398 if( stream->flags & PFORMAT_TO_FILE )
399 /*
400 * This is single character output to a FILE stream...
401 */
402 __fputc(c, (FILE *)(stream->dest));
403
404 else
405 /* Whereas, this is to an internal memory buffer...
406 */
407 ((APICHAR *)(stream->dest))[stream->count] = c;
408 }
409 ++stream->count;
410}
411
412static
413void __pformat_putchars( const char *s, int count, __pformat_t *stream )
414{
415#ifndef __BUILD_WIDEAPI
416 /* Handler for `%c' and (indirectly) `%s' conversion specifications.
417 *
418 * Transfer characters from the string buffer at `s', character by
419 * character, up to the number of characters specified by `count', or
420 * if `precision' has been explicitly set to a value less than `count',
421 * stopping after the number of characters specified for `precision',
422 * to the `__pformat()' output stream.
423 *
424 * Characters to be emitted are passed through `__pformat_putc()', to
425 * ensure that any specified output quota is honoured.
426 */
427 if( (stream->precision >= 0) && (count > stream->precision) )
428 /*
429 * Ensure that the maximum number of characters transferred doesn't
430 * exceed any explicitly set `precision' specification.
431 */
432 count = stream->precision;
433
434 /* Establish the width of any field padding required...
435 */
436 if( stream->width > count )
437 /*
438 * as the number of spaces equivalent to the number of characters
439 * by which those to be emitted is fewer than the field width...
440 */
441 stream->width -= count;
442
443 else
444 /* ignoring any width specification which is insufficient.
445 */
446 stream->width = PFORMAT_IGNORE;
447
448 if( (stream->width > 0) && ((stream->flags & PFORMAT_LJUSTIFY) == 0) )
449 /*
450 * When not doing flush left justification, (i.e. the `-' flag
451 * is not set), any residual unreserved field width must appear
452 * as blank padding, to the left of the output string.
453 */
454 while( stream->width-- )
455 __pformat_putc( '\x20', stream );
456
457 /* Emit the data...
458 */
459 while( count-- )
460 /*
461 * copying the requisite number of characters from the input.
462 */
463 __pformat_putc( *s++, stream );
464
465 /* If we still haven't consumed the entire specified field width,
466 * we must be doing flush left justification; any residual width
467 * must be filled with blanks, to the right of the output value.
468 */
469 while( stream->width-- > 0 )
470 __pformat_putc( '\x20', stream );
471
472#else /* __BUILD_WIDEAPI */
473
474 int len;
475
476 if( (stream->precision >= 0) && (count > stream->precision) )
477 count = stream->precision;
478
479 if( (stream->flags & PFORMAT_TO_FILE) && (stream->flags & PFORMAT_NOLIMIT) )
480 {
481 int __cdecl __ms_fwprintf(FILE *, const wchar_t *, ...);
482
483 if( stream->width > count )
484 {
485 if( (stream->flags & PFORMAT_LJUSTIFY) == 0 )
486 len = __ms_fwprintf( (FILE *)(stream->dest), L"%*.*S", stream->width, count, s );
487 else
488 len = __ms_fwprintf( (FILE *)(stream->dest), L"%-*.*S", stream->width, count, s );
489 }
490 else
491 {
492 len = __ms_fwprintf( (FILE *)(stream->dest), L"%.*S", count, s );
493 }
494 if( len > 0 )
495 stream->count += len;
496 stream->width = PFORMAT_IGNORE;
497 return;
498 }
499
500 if( stream->width > count )
501 stream->width -= count;
502 else
503 stream->width = PFORMAT_IGNORE;
504
505 if( (stream->width > 0) && ((stream->flags & PFORMAT_LJUSTIFY) == 0) )
506 while( stream->width-- )
507 __pformat_putc( '\x20', stream );
508
509 {
510 /* mbrtowc */
511 size_t l;
512 wchar_t w[12], *p;
513 while( count > 0 )
514 {
515 mbstate_t ps;
516 memset(&ps, 0, sizeof(ps) );
517 --count;
518 p = &w[0];
519 l = mbrtowc (p, s, strlen (s), &ps);
520 if (!l)
521 break;
522 if ((ssize_t)l < 0)
523 {
524 l = 1;
525 w[0] = (wchar_t) *s;
526 }
527 s += l;
528 __pformat_putc((int)w[0], stream);
529 }
530 }
531
532 while( stream->width-- > 0 )
533 __pformat_putc( '\x20', stream );
534
535#endif /* __BUILD_WIDEAPI */
536}
537
538static
539void __pformat_puts( const char *s, __pformat_t *stream )
540{
541 /* Handler for `%s' conversion specifications.
542 *
543 * Transfer a NUL terminated character string, character by character,
544 * stopping when the end of the string is encountered, or if `precision'
545 * has been explicitly set, when the specified number of characters has
546 * been emitted, if that is less than the length of the input string,
547 * to the `__pformat()' output stream.
548 *
549 * This is implemented as a trivial call to `__pformat_putchars()',
550 * passing the length of the input string as the character count,
551 * (after first verifying that the input pointer is not NULL).
552 */
553 if( s == NULL ) s = "(null)";
554
555 if( stream->precision >= 0 )
556 __pformat_putchars( s, strnlen( s, stream->precision ), stream );
557 else
558 __pformat_putchars( s, strlen( s ), stream );
559}
560
561static
562void __pformat_wputchars( const wchar_t *s, int count, __pformat_t *stream )
563{
564#ifndef __BUILD_WIDEAPI
565 /* Handler for `%C'(`%lc') and `%S'(`%ls') conversion specifications;
566 * (this is a wide character variant of `__pformat_putchars()').
567 *
568 * Each multibyte character sequence to be emitted is passed, byte
569 * by byte, through `__pformat_putc()', to ensure that any specified
570 * output quota is honoured.
571 */
572 char buf[16];
573 mbstate_t state;
574 int len = wcrtomb(buf, L'\0', &state);
575
576 if( (stream->precision >= 0) && (count > stream->precision) )
577 /*
578 * Ensure that the maximum number of characters transferred doesn't
579 * exceed any explicitly set `precision' specification.
580 */
581 count = stream->precision;
582
583 /* Establish the width of any field padding required...
584 */
585 if( stream->width > count )
586 /*
587 * as the number of spaces equivalent to the number of characters
588 * by which those to be emitted is fewer than the field width...
589 */
590 stream->width -= count;
591
592 else
593 /* ignoring any width specification which is insufficient.
594 */
595 stream->width = PFORMAT_IGNORE;
596
597 if( (stream->width > 0) && ((stream->flags & PFORMAT_LJUSTIFY) == 0) )
598 /*
599 * When not doing flush left justification, (i.e. the `-' flag
600 * is not set), any residual unreserved field width must appear
601 * as blank padding, to the left of the output string.
602 */
603 while( stream->width-- )
604 __pformat_putc( '\x20', stream );
605
606 /* Emit the data, converting each character from the wide
607 * to the multibyte domain as we go...
608 */
609 while( (count-- > 0) && ((len = wcrtomb( buf, *s++, &state )) > 0) )
610 {
611 char *p = buf;
612 while( len-- > 0 )
613 __pformat_putc( *p++, stream );
614 }
615
616 /* If we still haven't consumed the entire specified field width,
617 * we must be doing flush left justification; any residual width
618 * must be filled with blanks, to the right of the output value.
619 */
620 while( stream->width-- > 0 )
621 __pformat_putc( '\x20', stream );
622
623#else /* __BUILD_WIDEAPI */
624
625 int len;
626
627 if( (stream->precision >= 0) && (count > stream->precision) )
628 count = stream->precision;
629
630 if( (stream->flags & PFORMAT_TO_FILE) && (stream->flags & PFORMAT_NOLIMIT) )
631 {
632 int __cdecl __ms_fwprintf(FILE *, const wchar_t *, ...);
633
634 if( stream->width > count )
635 {
636 if( (stream->flags & PFORMAT_LJUSTIFY) == 0 )
637 len = __ms_fwprintf( (FILE *)(stream->dest), L"%*.*s", stream->width, count, s );
638 else
639 len = __ms_fwprintf( (FILE *)(stream->dest), L"%-*.*s", stream->width, count, s );
640 }
641 else
642 {
643 len = __ms_fwprintf( (FILE *)(stream->dest), L"%.*s", count, s );
644 }
645 if( len > 0 )
646 stream->count += len;
647 stream->width = PFORMAT_IGNORE;
648 return;
649 }
650
651 if( stream->width > count )
652 stream->width -= count;
653 else
654 stream->width = PFORMAT_IGNORE;
655
656 if( (stream->width > 0) && ((stream->flags & PFORMAT_LJUSTIFY) == 0) )
657 while( stream->width-- )
658 __pformat_putc( '\x20', stream );
659
660 len = count;
661 while(len-- > 0 && *s != 0)
662 {
663 __pformat_putc(*s++, stream);
664 }
665
666 while( stream->width-- > 0 )
667 __pformat_putc( '\x20', stream );
668
669#endif /* __BUILD_WIDEAPI */
670}
671
672static
673void __pformat_wcputs( const wchar_t *s, __pformat_t *stream )
674{
675 /* Handler for `%S' (`%ls') conversion specifications.
676 *
677 * Transfer a NUL terminated wide character string, character by
678 * character, converting to its equivalent multibyte representation
679 * on output, and stopping when the end of the string is encountered,
680 * or if `precision' has been explicitly set, when the specified number
681 * of characters has been emitted, if that is less than the length of
682 * the input string, to the `__pformat()' output stream.
683 *
684 * This is implemented as a trivial call to `__pformat_wputchars()',
685 * passing the length of the input string as the character count,
686 * (after first verifying that the input pointer is not NULL).
687 */
688 if( s == NULL ) s = L"(null)";
689
690 if( stream->precision >= 0 )
691 __pformat_wputchars( s, wcsnlen( s, stream->precision ), stream );
692 else
693 __pformat_wputchars( s, wcslen( s ), stream );
694}
695
696static
697int __pformat_int_bufsiz( int bias, int size, __pformat_t *stream )
698{
699 /* Helper to establish the size of the internal buffer, which
700 * is required to queue the ASCII decomposition of an integral
701 * data value, prior to transfer to the output stream.
702 */
703 size = ((size - 1 + LLONGBITS) / size) + bias;
704 size += (stream->precision > 0) ? stream->precision : 0;
705 if ((stream->flags & PFORMAT_GROUPED) != 0 && stream->thousands_chr != 0)
706 size += (size / 3);
707 return (size > stream->width) ? size : stream->width;
708}
709
710static
711void __pformat_int( __pformat_intarg_t value, __pformat_t *stream )
712{
713 /* Handler for `%d', `%i' and `%u' conversion specifications.
714 *
715 * Transfer the ASCII representation of an integer value parameter,
716 * formatted as a decimal number, to the `__pformat()' output queue;
717 * output will be truncated, if any specified quota is exceeded.
718 */
719 int32_t bufflen = __pformat_int_bufsiz(1, PFORMAT_OSHIFT, stream);
720#ifdef __ENABLE_PRINTF128
721 char *tmp_buff = NULL;
722#endif
723 char *buf = NULL;
724 char *p;
725 int precision;
726
727 buf = alloca(bufflen);
728 p = buf;
729 if( stream->flags & PFORMAT_NEGATIVE )
730#ifdef __ENABLE_PRINTF128
731 {
732 /* The input value might be negative, (i.e. it is a signed value)...
733 */
734 if( value.__pformat_u128_t.t128.digits[1] < 0) {
735 /*
736 * It IS negative, but we want to encode it as unsigned,
737 * displayed with a leading minus sign, so convert it...
738 */
739 /* two's complement */
740 value.__pformat_u128_t.t128.digits[0] = ~value.__pformat_u128_t.t128.digits[0];
741 value.__pformat_u128_t.t128.digits[1] = ~value.__pformat_u128_t.t128.digits[1];
742 value.__pformat_u128_t.t128.digits[0] += 1;
743 value.__pformat_u128_t.t128.digits[1] += (!value.__pformat_u128_t.t128.digits[0]) ? 1 : 0;
744 } else
745 /* It is unequivocally a POSITIVE value, so turn off the
746 * request to prefix it with a minus sign...
747 */
748 stream->flags &= ~PFORMAT_NEGATIVE;
749 }
750
751 tmp_buff = alloca(bufflen);
752 /* Encode the input value for display...
753 */
754 __bigint_to_string(value.__pformat_u128_t.t128_2.digits32,
755 4, tmp_buff, bufflen);
756 __bigint_trim_leading_zeroes(tmp_buff,1);
757
758 memset(p,0,bufflen);
759 for(int32_t i = strlen(tmp_buff) - 1; i >= 0; i--){
760 if ( i && (stream->flags & PFORMAT_GROUPED) != 0 && stream->thousands_chr != 0
761 && (i % 4) == 3)
762 {
763 *p++ = ',';
764 }
765 *p++ = tmp_buff[i];
766 if( i > bufflen - 1) break; /* sanity chec */
767 if( tmp_buff[i] == '\0' ) break; /* end */
768 }
769#else
770 {
771 /* The input value might be negative, (i.e. it is a signed value)...
772 */
773 if( value.__pformat_llong_t < 0LL )
774 /*
775 * It IS negative, but we want to encode it as unsigned,
776 * displayed with a leading minus sign, so convert it...
777 */
778 value.__pformat_llong_t = -value.__pformat_llong_t;
779
780 else
781 /* It is unequivocally a POSITIVE value, so turn off the
782 * request to prefix it with a minus sign...
783 */
784 stream->flags &= ~PFORMAT_NEGATIVE;
785 }
786while( value.__pformat_ullong_t )
787 {
788 /* decomposing it into its constituent decimal digits,
789 * in order from least significant to most significant, using
790 * the local buffer as a LIFO queue in which to store them.
791 */
792 if (p != buf && (stream->flags & PFORMAT_GROUPED) != 0 && stream->thousands_chr != 0
793 && ((p - buf) % 4) == 3)
794 {
795 *p++ = ',';
796 }
797 *p++ = '0' + (unsigned char)(value.__pformat_ullong_t % 10LL);
798 value.__pformat_ullong_t /= 10LL;
799 }
800#endif
801
802 if( (stream->precision > 0)
803 && ((precision = stream->precision - (p - buf)) > 0) )
804 /*
805 * We have not yet queued sufficient digits to fill the field width
806 * specified for minimum `precision'; pad with zeros to achieve this.
807 */
808 while( precision-- > 0 )
809 *p++ = '0';
810
811 if( (p == buf) && (stream->precision != 0) )
812 /*
813 * Input value was zero; make sure we print at least one digit,
814 * unless the precision is also explicitly zero.
815 */
816 *p++ = '0';
817
818 if( (stream->width > 0) && ((stream->width -= p - buf) > 0) )
819 {
820 /* We have now queued sufficient characters to display the input value,
821 * at the desired precision, but this will not fill the output field...
822 */
823 if( stream->flags & PFORMAT_SIGNED )
824 /*
825 * We will fill one additional space with a sign...
826 */
827 stream->width--;
828
829 if( (stream->precision < 0)
830 && ((stream->flags & PFORMAT_JUSTIFY) == PFORMAT_ZEROFILL) )
831 /*
832 * and the `0' flag is in effect, so we pad the remaining spaces,
833 * to the left of the displayed value, with zeros.
834 */
835 while( stream->width-- > 0 )
836 *p++ = '0';
837
838 else if( (stream->flags & PFORMAT_LJUSTIFY) == 0 )
839 /*
840 * the `0' flag is not in effect, and neither is the `-' flag,
841 * so we pad to the left of the displayed value with spaces, so that
842 * the value appears right justified within the output field.
843 */
844 while( stream->width-- > 0 )
845 __pformat_putc( '\x20', stream );
846 }
847
848 if( stream->flags & PFORMAT_NEGATIVE )
849 /*
850 * A negative value needs a sign...
851 */
852 *p++ = '-';
853
854 else if( stream->flags & PFORMAT_POSITIVE )
855 /*
856 * A positive value may have an optionally displayed sign...
857 */
858 *p++ = '+';
859
860 else if( stream->flags & PFORMAT_ADDSPACE )
861 /*
862 * Space was reserved for displaying a sign, but none was emitted...
863 */
864 *p++ = '\x20';
865
866 while( p > buf )
867 /*
868 * Emit the accumulated constituent digits,
869 * in order from most significant to least significant...
870 */
871 __pformat_putc( *--p, stream );
872
873 while( stream->width-- > 0 )
874 /*
875 * The specified output field has not yet been completely filled;
876 * the `-' flag must be in effect, resulting in a displayed value which
877 * appears left justified within the output field; we must pad the field
878 * to the right of the displayed value, by emitting additional spaces,
879 * until we reach the rightmost field boundary.
880 */
881 __pformat_putc( '\x20', stream );
882}
883
884static
885void __pformat_xint( int fmt, __pformat_intarg_t value, __pformat_t *stream )
886{
887 /* Handler for `%o', `%p', `%x' and `%X' conversions.
888 *
889 * These can be implemented using a simple `mask and shift' strategy;
890 * set up the mask and shift values appropriate to the conversion format,
891 * and allocate a suitably sized local buffer, in which to queue encoded
892 * digits of the formatted value, in preparation for output.
893 */
894 int width;
895 int shift = (fmt == 'o') ? PFORMAT_OSHIFT : PFORMAT_XSHIFT;
896 int bufflen = __pformat_int_bufsiz(2, shift, stream);
897 char *buf = NULL;
898#ifdef __ENABLE_PRINTF128
899 char *tmp_buf = NULL;
900#endif
901 char *p;
902 buf = alloca(bufflen);
903 p = buf;
904#ifdef __ENABLE_PRINTF128
905 tmp_buf = alloca(bufflen);
906 if(fmt == 'o'){
907 __bigint_to_stringo(value.__pformat_u128_t.t128_2.digits32,4,tmp_buf,bufflen);
908 } else {
909 __bigint_to_stringx(value.__pformat_u128_t.t128_2.digits32,4,tmp_buf,bufflen, !(fmt & PFORMAT_XCASE));
910 }
911 __bigint_trim_leading_zeroes(tmp_buf,0);
912
913 memset(buf,0,bufflen);
914 for(int32_t i = strlen(tmp_buf); i >= 0; i--)
915 *p++ = tmp_buf[i];
916#else
917 int mask = (fmt == 'o') ? PFORMAT_OMASK : PFORMAT_XMASK;
918 while( value.__pformat_ullong_t )
919 {
920 /* Encode the specified non-zero input value as a sequence of digits,
921 * in the appropriate `base' encoding and in reverse digit order, each
922 * encoded in its printable ASCII form, with no leading zeros, using
923 * the local buffer as a LIFO queue in which to store them.
924 */
925 char *q;
926 if( (*(q = p++) = '0' + (value.__pformat_ullong_t & mask)) > '9' )
927 *q = (*q + 'A' - '9' - 1) | (fmt & PFORMAT_XCASE);
928 value.__pformat_ullong_t >>= shift;
929 }
930#endif
931
932 if( p == buf )
933 /*
934 * Nothing was queued; input value must be zero, which should never be
935 * emitted in the `alternative' PFORMAT_HASHED style.
936 */
937 stream->flags &= ~PFORMAT_HASHED;
938
939 if( ((width = stream->precision) > 0) && ((width -= p - buf) > 0) )
940 /*
941 * We have not yet queued sufficient digits to fill the field width
942 * specified for minimum `precision'; pad with zeros to achieve this.
943 */
944 while( width-- > 0 )
945 *p++ = '0';
946
947 else if( (fmt == 'o') && (stream->flags & PFORMAT_HASHED) )
948 /*
949 * The field width specified for minimum `precision' has already
950 * been filled, but the `alternative' PFORMAT_HASHED style for octal
951 * output requires at least one initial zero; that will not have
952 * been queued, so add it now.
953 */
954 *p++ = '0';
955
956 if( (p == buf) && (stream->precision != 0) )
957 /*
958 * Still nothing queued for output, but the `precision' has not been
959 * explicitly specified as zero, (which is necessary if no output for
960 * an input value of zero is desired); queue exactly one zero digit.
961 */
962 *p++ = '0';
963
964 if( stream->width > (width = p - buf) )
965 /*
966 * Specified field width exceeds the minimum required...
967 * Adjust so that we retain only the additional padding width.
968 */
969 stream->width -= width;
970
971 else
972 /* Ignore any width specification which is insufficient.
973 */
974 stream->width = PFORMAT_IGNORE;
975
976 if( ((width = stream->width) > 0)
977 && (fmt != 'o') && (stream->flags & PFORMAT_HASHED) )
978 /*
979 * For `%#x' or `%#X' formats, (which have the `#' flag set),
980 * further reduce the padding width to accommodate the radix
981 * indicating prefix.
982 */
983 width -= 2;
984
985 if( (width > 0) && (stream->precision < 0)
986 && ((stream->flags & PFORMAT_JUSTIFY) == PFORMAT_ZEROFILL) )
987 /*
988 * When the `0' flag is set, and not overridden by the `-' flag,
989 * or by a specified precision, add sufficient leading zeros to
990 * consume the remaining field width.
991 */
992 while( width-- > 0 )
993 *p++ = '0';
994
995 if( (fmt != 'o') && (stream->flags & PFORMAT_HASHED) )
996 {
997 /* For formats other than octal, the PFORMAT_HASHED output style
998 * requires the addition of a two character radix indicator, as a
999 * prefix to the actual encoded numeric value.
1000 */
1001 *p++ = fmt;
1002 *p++ = '0';
1003 }
1004
1005 if( (width > 0) && ((stream->flags & PFORMAT_LJUSTIFY) == 0) )
1006 /*
1007 * When not doing flush left justification, (i.e. the `-' flag
1008 * is not set), any residual unreserved field width must appear
1009 * as blank padding, to the left of the output value.
1010 */
1011 while( width-- > 0 )
1012 __pformat_putc( '\x20', stream );
1013
1014 while( p > buf )
1015 /*
1016 * Move the queued output from the local buffer to the ultimate
1017 * destination, in LIFO order.
1018 */
1019 __pformat_putc( *--p, stream );
1020
1021 /* If we still haven't consumed the entire specified field width,
1022 * we must be doing flush left justification; any residual width
1023 * must be filled with blanks, to the right of the output value.
1024 */
1025 while( width-- > 0 )
1026 __pformat_putc( '\x20', stream );
1027}
1028
1029typedef union
1030{
1031 /* A multifaceted representation of an IEEE extended precision,
1032 * (80-bit), floating point number, facilitating access to its
1033 * component parts.
1034 */
1035 double __pformat_fpreg_double_t;
1036 long double __pformat_fpreg_ldouble_t;
1037 struct
1038 { unsigned long long __pformat_fpreg_mantissa;
1039 signed short __pformat_fpreg_exponent;
1040 };
1041 unsigned short __pformat_fpreg_bitmap[5];
1042 unsigned int __pformat_fpreg_bits;
1043} __pformat_fpreg_t;
1044
1045#ifdef _WIN32
1046/* TODO: make this unconditional in final release...
1047 * (see note at head of associated `#else' block.
1048 */
1049#include "../gdtoa/gdtoa.h"
1050
1051static __pformat_fpreg_t init_fpreg_ldouble( long double val )
1052{
1053 __pformat_fpreg_t x;
1054 x.__pformat_fpreg_ldouble_t = val;
1055
1056 if( sizeof( double ) == sizeof( long double ) )
1057 {
1058 /* Here, __pformat_fpreg_t expects to be initialized with a 80 bit long
1059 * double, but this platform doesn't have long doubles that differ from
1060 * regular 64 bit doubles. Therefore manually convert the 64 bit float
1061 * value to an 80 bit float value.
1062 */
1063 int exp = (x.__pformat_fpreg_mantissa >> 52) & 0x7ff;
1064 unsigned long long mant = x.__pformat_fpreg_mantissa & 0x000fffffffffffffULL;
1065 int topbit = exp ? 1 : 0;
1066 int signbit = x.__pformat_fpreg_mantissa >> 63;
1067
1068 if (exp == 0x7ff)
1069 exp = 0x7fff;
1070 else if (exp != 0)
1071 exp = exp - 1023 + 16383;
1072 else if (mant != 0) {
1073 /* Denormal when stored as a 64 bit double, but becomes a normal when
1074 * converted to 80 bit long double form. */
1075 exp = 1 - 1023 + 16383;
1076 while (!(mant & 0x0010000000000000ULL)) {
1077 /* Normalize the mantissa. */
1078 mant <<= 1;
1079 exp--;
1080 }
1081 topbit = 1; /* The top bit, which is implicit in the 64 bit form. */
1082 }
1083 x.__pformat_fpreg_mantissa = (mant << 11) | ((unsigned long long)topbit << 63);
1084 x.__pformat_fpreg_exponent = exp | (signbit << 15);
1085 }
1086
1087 return x;
1088}
1089
1090static
1091char *__pformat_cvt( int mode, long double val, int nd, int *dp, int *sign )
1092{
1093 /* Helper function, derived from David M. Gay's `g_xfmt()', calling
1094 * his `__gdtoa()' function in a manner to provide extended precision
1095 * replacements for `ecvt()' and `fcvt()'.
1096 */
1097 int k; unsigned int e = 0; char *ep;
1098 static FPI fpi = { 64, 1-16383-64+1, 32766-16383-64+1, FPI_Round_near, 0, 14 /* Int_max */ };
1099 __pformat_fpreg_t x = init_fpreg_ldouble( val );
1100
1101 k = __fpclassifyl( val );
1102
1103 /* Classify the argument into an appropriate `__gdtoa()' category...
1104 */
1105 if( k & FP_NAN )
1106 /*
1107 * identifying infinities or not-a-number...
1108 */
1109 k = (k & FP_NORMAL) ? STRTOG_Infinite : STRTOG_NaN;
1110
1111 else if( k & FP_NORMAL )
1112 {
1113 /* normal and near-zero `denormals'...
1114 */
1115 if( k & FP_ZERO )
1116 {
1117 /* with appropriate exponent adjustment for a `denormal'...
1118 */
1119 k = STRTOG_Denormal;
1120 e = 1 - 0x3FFF - 63;
1121 }
1122 else
1123 {
1124 /* or with `normal' exponent adjustment...
1125 */
1126 k = STRTOG_Normal;
1127 e = (x.__pformat_fpreg_exponent & 0x7FFF) - 0x3FFF - 63;
1128 }
1129 }
1130
1131 else
1132 /* or, if none of the above, it's a zero, (positive or negative).
1133 */
1134 k = STRTOG_Zero;
1135
1136 /* Check for negative values, always treating NaN as unsigned...
1137 * (return value is zero for positive/unsigned; non-zero for negative).
1138 */
1139 *sign = (k == STRTOG_NaN) ? 0 : x.__pformat_fpreg_exponent & 0x8000;
1140
1141 /* Finally, get the raw digit string, and radix point position index.
1142 */
1143 return __gdtoa( &fpi, e, &x.__pformat_fpreg_bits, &k, mode, nd, dp, &ep );
1144}
1145
1146static
1147char *__pformat_ecvt( long double x, int precision, int *dp, int *sign )
1148{
1149 /* A convenience wrapper for the above...
1150 * it emulates `ecvt()', but takes a `long double' argument.
1151 */
1152 return __pformat_cvt( 2, x, precision, dp, sign );
1153}
1154
1155static
1156char *__pformat_fcvt( long double x, int precision, int *dp, int *sign )
1157{
1158 /* A convenience wrapper for the above...
1159 * it emulates `fcvt()', but takes a `long double' argument.
1160 */
1161 return __pformat_cvt( 3, x, precision, dp, sign );
1162}
1163
1164/* The following are required, to clean up the `__gdtoa()' memory pool,
1165 * after processing the data returned by the above.
1166 */
1167#define __pformat_ecvt_release( value ) __freedtoa( value )
1168#define __pformat_fcvt_release( value ) __freedtoa( value )
1169
1170#else
1171/*
1172 * TODO: remove this before final release; it is included here as a
1173 * convenience for testing, without requiring a working `__gdtoa()'.
1174 */
1175static
1176char *__pformat_ecvt( long double x, int precision, int *dp, int *sign )
1177{
1178 /* Define in terms of `ecvt()'...
1179 */
1180 char *retval = ecvt( (double)(x), precision, dp, sign );
1181 if( isinf( x ) || isnan( x ) )
1182 {
1183 /* emulating `__gdtoa()' reporting for infinities and NaN.
1184 */
1185 *dp = PFORMAT_INFNAN;
1186 if( *retval == '-' )
1187 {
1188 /* Need to force the `sign' flag, (particularly for NaN).
1189 */
1190 ++retval; *sign = 1;
1191 }
1192 }
1193 return retval;
1194}
1195
1196static
1197char *__pformat_fcvt( long double x, int precision, int *dp, int *sign )
1198{
1199 /* Define in terms of `fcvt()'...
1200 */
1201 char *retval = fcvt( (double)(x), precision, dp, sign );
1202 if( isinf( x ) || isnan( x ) )
1203 {
1204 /* emulating `__gdtoa()' reporting for infinities and NaN.
1205 */
1206 *dp = PFORMAT_INFNAN;
1207 if( *retval == '-' )
1208 {
1209 /* Need to force the `sign' flag, (particularly for NaN).
1210 */
1211 ++retval; *sign = 1;
1212 }
1213 }
1214 return retval;
1215}
1216
1217/* No memory pool clean up needed, for these emulated cases...
1218 */
1219#define __pformat_ecvt_release( value ) /* nothing to be done */
1220#define __pformat_fcvt_release( value ) /* nothing to be done */
1221
1222/* TODO: end of conditional to be removed. */
1223#endif
1224
1225static
1226void __pformat_emit_radix_point( __pformat_t *stream )
1227{
1228 /* Helper to place a localised representation of the radix point
1229 * character at the ultimate destination, when formatting fixed or
1230 * floating point numbers.
1231 */
1232 if( stream->rplen == PFORMAT_RPINIT )
1233 {
1234 /* Radix point initialisation not yet completed;
1235 * establish a multibyte to `wchar_t' converter...
1236 */
1237 int len; wchar_t rpchr; mbstate_t state;
1238
1239 /* Initialise the conversion state...
1240 */
1241 memset( &state, 0, sizeof( state ) );
1242
1243 /* Fetch and convert the localised radix point representation...
1244 */
1245 if( (len = mbrtowc( &rpchr, localeconv()->decimal_point, 16, &state )) > 0 )
1246 /*
1247 * and store it, if valid.
1248 */
1249 stream->rpchr = rpchr;
1250
1251 /* In any case, store the reported effective multibyte length,
1252 * (or the error flag), marking initialisation as `done'.
1253 */
1254 stream->rplen = len;
1255 }
1256
1257 if( stream->rpchr != (wchar_t)(0) )
1258 {
1259 /* We have a localised radix point mark;
1260 * establish a converter to make it a multibyte character...
1261 */
1262#ifdef __BUILD_WIDEAPI
1263 __pformat_putc (stream->rpchr, stream);
1264#else
1265 int len; char buf[len = stream->rplen]; mbstate_t state;
1266
1267 /* Initialise the conversion state...
1268 */
1269 memset( &state, 0, sizeof( state ) );
1270
1271 /* Convert the `wchar_t' representation to multibyte...
1272 */
1273 if( (len = wcrtomb( buf, stream->rpchr, &state )) > 0 )
1274 {
1275 /* and copy to the output destination, when valid...
1276 */
1277 char *p = buf;
1278 while( len-- > 0 )
1279 __pformat_putc( *p++, stream );
1280 }
1281
1282 else
1283 /* otherwise fall back to plain ASCII '.'...
1284 */
1285 __pformat_putc( '.', stream );
1286#endif
1287 }
1288 else
1289 /* No localisation: just use ASCII '.'...
1290 */
1291 __pformat_putc( '.', stream );
1292}
1293
1294static
1295void __pformat_emit_numeric_value( int c, __pformat_t *stream )
1296{
1297 /* Convenience helper to transfer numeric data from an internal
1298 * formatting buffer to the ultimate destination...
1299 */
1300 if( c == '.' )
1301 /*
1302 * converting this internal representation of the the radix
1303 * point to the appropriately localised representation...
1304 */
1305 __pformat_emit_radix_point( stream );
1306 else if (c == ',')
1307 {
1308 wchar_t wcs;
1309 if ((wcs = stream->thousands_chr) != 0)
1310 __pformat_wputchars (&wcs, 1, stream);
1311 }
1312 else
1313 /* and passing all other characters through, unmodified.
1314 */
1315 __pformat_putc( c, stream );
1316}
1317
1318static
1319void __pformat_emit_inf_or_nan( int sign, char *value, __pformat_t *stream )
1320{
1321 /* Helper to emit INF or NAN where a floating point value
1322 * resolves to one of these special states.
1323 */
1324 int i;
1325 char buf[4];
1326 char *p = buf;
1327
1328 /* We use the string formatting helper to display INF/NAN,
1329 * but we don't want truncation if the precision set for the
1330 * original floating point output request was insufficient;
1331 * ignore it!
1332 */
1333 stream->precision = PFORMAT_IGNORE;
1334
1335 if( sign )
1336 /*
1337 * Negative infinity: emit the sign...
1338 */
1339 *p++ = '-';
1340
1341 else if( stream->flags & PFORMAT_POSITIVE )
1342 /*
1343 * Not negative infinity, but '+' flag is in effect;
1344 * thus, we emit a positive sign...
1345 */
1346 *p++ = '+';
1347
1348 else if( stream->flags & PFORMAT_ADDSPACE )
1349 /*
1350 * No sign required, but space was reserved for it...
1351 */
1352 *p++ = '\x20';
1353
1354 /* Copy the appropriate status indicator, up to a maximum of
1355 * three characters, transforming to the case corresponding to
1356 * the format specification...
1357 */
1358 for( i = 3; i > 0; --i )
1359 *p++ = (*value++ & ~PFORMAT_XCASE) | (stream->flags & PFORMAT_XCASE);
1360
1361 /* and emit the result.
1362 */
1363 __pformat_putchars( buf, p - buf, stream );
1364}
1365
1366static
1367void __pformat_emit_float( int sign, char *value, int len, __pformat_t *stream )
1368{
1369 /* Helper to emit a fixed point representation of numeric data,
1370 * as encoded by a prior call to `ecvt()' or `fcvt()'; (this does
1371 * NOT include the exponent, for floating point format).
1372 */
1373 if( len > 0 )
1374 {
1375 /* The magnitude of `x' is greater than or equal to 1.0...
1376 * reserve space in the output field, for the required number of
1377 * decimal digits to be placed before the decimal point...
1378 */
1379 if( stream->width >= len)
1380 /*
1381 * adjusting as appropriate, when width is sufficient...
1382 */
1383 stream->width -= len;
1384
1385 else
1386 /* or simply ignoring the width specification, if not.
1387 */
1388 stream->width = PFORMAT_IGNORE;
1389 }
1390
1391 else if( stream->width > 0 )
1392 /*
1393 * The magnitude of `x' is less than 1.0...
1394 * reserve space for exactly one zero before the decimal point.
1395 */
1396 stream->width--;
1397
1398 /* Reserve additional space for the digits which will follow the
1399 * decimal point...
1400 */
1401 if( (stream->width >= 0) && (stream->width > stream->precision) )
1402 /*
1403 * adjusting appropriately, when sufficient width remains...
1404 * (note that we must check both of these conditions, because
1405 * precision may be more negative than width, as a result of
1406 * adjustment to provide extra padding when trailing zeros
1407 * are to be discarded from "%g" format conversion with a
1408 * specified field width, but if width itself is negative,
1409 * then there is explicitly to be no padding anyway).
1410 */
1411 stream->width -= stream->precision;
1412
1413 else
1414 /* or again, ignoring the width specification, if not.
1415 */
1416 stream->width = PFORMAT_IGNORE;
1417
1418 /* Reserve space in the output field, for display of the decimal point,
1419 * unless the precision is explicity zero, with the `#' flag not set.
1420 */
1421 if ((stream->width > 0)
1422 && ((stream->precision > 0) || (stream->flags & PFORMAT_HASHED)))
1423 stream->width--;
1424
1425 if (len > 0 && (stream->flags & PFORMAT_GROUPED) != 0 && stream->thousands_chr != 0)
1426 {
1427 int cths = ((len + 2) / 3) - 1;
1428 while (cths > 0 && stream->width > 0)
1429 {
1430 --cths; stream->width--;
1431 }
1432 }
1433
1434 /* Reserve space in the output field, for display of the sign of the
1435 * formatted value, if required; (i.e. if the value is negative, or if
1436 * either the `space' or `+' formatting flags are set).
1437 */
1438 if( (stream->width > 0) && (sign || (stream->flags & PFORMAT_SIGNED)) )
1439 stream->width--;
1440
1441 /* Emit any padding space, as required to correctly right justify
1442 * the output within the alloted field width.
1443 */
1444 if( (stream->width > 0) && ((stream->flags & PFORMAT_JUSTIFY) == 0) )
1445 while( stream->width-- > 0 )
1446 __pformat_putc( '\x20', stream );
1447
1448 /* Emit the sign indicator, as appropriate...
1449 */
1450 if( sign )
1451 /*
1452 * mandatory, for negative values...
1453 */
1454 __pformat_putc( '-', stream );
1455
1456 else if( stream->flags & PFORMAT_POSITIVE )
1457 /*
1458 * optional, for positive values...
1459 */
1460 __pformat_putc( '+', stream );
1461
1462 else if( stream->flags & PFORMAT_ADDSPACE )
1463 /*
1464 * or just fill reserved space, when the space flag is in effect.
1465 */
1466 __pformat_putc( '\x20', stream );
1467
1468 /* If the `0' flag is in effect, and not overridden by the `-' flag,
1469 * then zero padding, to fill out the field, goes here...
1470 */
1471 if( (stream->width > 0)
1472 && ((stream->flags & PFORMAT_JUSTIFY) == PFORMAT_ZEROFILL) )
1473 while( stream->width-- > 0 )
1474 __pformat_putc( '0', stream );
1475
1476 /* Emit the digits of the encoded numeric value...
1477 */
1478 if( len > 0 )
1479 {
1480 /*
1481 * ...beginning with those which precede the radix point,
1482 * and appending any necessary significant trailing zeros.
1483 */
1484 do {
1485 __pformat_putc( *value ? *value++ : '0', stream);
1486 --len;
1487 if (len != 0 && (stream->flags & PFORMAT_GROUPED) != 0 && stream->thousands_chr != 0
1488 && (len % 3) == 0)
1489 __pformat_wputchars (&stream->thousands_chr, 1, stream);
1490 }
1491 while (len > 0);
1492 }
1493 else
1494 /* The magnitude of the encoded value is less than 1.0, so no
1495 * digits precede the radix point; we emit a mandatory initial
1496 * zero, followed immediately by the radix point.
1497 */
1498 __pformat_putc( '0', stream );
1499
1500 /* Unless the encoded value is integral, AND the radix point
1501 * is not expressly demanded by the `#' flag, we must insert
1502 * the appropriately localised radix point mark here...
1503 */
1504 if( (stream->precision > 0) || (stream->flags & PFORMAT_HASHED) )
1505 __pformat_emit_radix_point( stream );
1506
1507 /* When the radix point offset, `len', is negative, this implies
1508 * that additional zeros must appear, following the radix point,
1509 * and preceding the first significant digit...
1510 */
1511 if( len < 0 )
1512 {
1513 /* To accommodate these, we adjust the precision, (reducing it
1514 * by adding a negative value), and then we emit as many zeros
1515 * as are required.
1516 */
1517 stream->precision += len;
1518 do __pformat_putc( '0', stream );
1519 while( ++len < 0 );
1520 }
1521
1522 /* Now we emit any remaining significant digits, or trailing zeros,
1523 * until the required precision has been achieved.
1524 */
1525 while( stream->precision-- > 0 )
1526 __pformat_putc( *value ? *value++ : '0', stream );
1527}
1528
1529static
1530void __pformat_emit_efloat( int sign, char *value, int e, __pformat_t *stream )
1531{
1532 /* Helper to emit a floating point representation of numeric data,
1533 * as encoded by a prior call to `ecvt()' or `fcvt()'; (this DOES
1534 * include the following exponent).
1535 */
1536 int exp_width = 1;
1537 __pformat_intarg_t exponent; exponent.__pformat_llong_t = e -= 1;
1538
1539 /* Determine how many digit positions are required for the exponent.
1540 */
1541 while( (e /= 10) != 0 )
1542 exp_width++;
1543
1544 /* Ensure that this is at least as many as the standard requirement.
1545 * The C99 standard requires the expenent to contain at least two
1546 * digits, unless specified explicitly otherwise.
1547 */
1548 if (stream->expmin == -1)
1549 stream->expmin = 2;
1550 if( exp_width < stream->expmin )
1551 exp_width = stream->expmin;
1552
1553 /* Adjust the residual field width allocation, to allow for the
1554 * number of exponent digits to be emitted, together with a sign
1555 * and exponent separator...
1556 */
1557 if( stream->width > (exp_width += 2) )
1558 stream->width -= exp_width;
1559
1560 else
1561 /* ignoring the field width specification, if insufficient.
1562 */
1563 stream->width = PFORMAT_IGNORE;
1564
1565 /* Emit the significand, as a fixed point value with one digit
1566 * preceding the radix point.
1567 */
1568 __pformat_emit_float( sign, value, 1, stream );
1569
1570 /* Reset precision, to ensure the mandatory minimum number of
1571 * exponent digits will be emitted, and set the flags to ensure
1572 * the sign is displayed.
1573 */
1574 stream->precision = stream->expmin;
1575 stream->flags |= PFORMAT_SIGNED;
1576
1577 /* Emit the exponent separator.
1578 */
1579 __pformat_putc( ('E' | (stream->flags & PFORMAT_XCASE)), stream );
1580
1581 /* Readjust the field width setting, such that it again allows
1582 * for the digits of the exponent, (which had been discounted when
1583 * computing any left side padding requirement), so that they are
1584 * correctly included in the computation of any right side padding
1585 * requirement, (but here we exclude the exponent separator, which
1586 * has been emitted, and so counted already).
1587 */
1588 stream->width += exp_width - 1;
1589
1590 /* And finally, emit the exponent itself, as a signed integer,
1591 * with any padding required to achieve flush left justification,
1592 * (which will be added automatically, by `__pformat_int()').
1593 */
1594 __pformat_int( exponent, stream );
1595}
1596
1597static
1598void __pformat_float( long double x, __pformat_t *stream )
1599{
1600 /* Handler for `%f' and `%F' format specifiers.
1601 *
1602 * This wraps calls to `__pformat_cvt()', `__pformat_emit_float()'
1603 * and `__pformat_emit_inf_or_nan()', as appropriate, to achieve
1604 * output in fixed point format.
1605 */
1606 int sign, intlen; char *value;
1607
1608 /* Establish the precision for the displayed value, defaulting to six
1609 * digits following the decimal point, if not explicitly specified.
1610 */
1611 if( stream->precision < 0 )
1612 stream->precision = 6;
1613
1614 /* Encode the input value as ASCII, for display...
1615 */
1616 value = __pformat_fcvt( x, stream->precision, &intlen, &sign );
1617
1618 if( intlen == PFORMAT_INFNAN )
1619 /*
1620 * handle cases of `infinity' or `not-a-number'...
1621 */
1622 __pformat_emit_inf_or_nan( sign, value, stream );
1623
1624 else
1625 { /* or otherwise, emit the formatted result.
1626 */
1627 __pformat_emit_float( sign, value, intlen, stream );
1628
1629 /* and, if there is any residual field width as yet unfilled,
1630 * then we must be doing flush left justification, so pad out to
1631 * the right hand field boundary.
1632 */
1633 while( stream->width-- > 0 )
1634 __pformat_putc( '\x20', stream );
1635 }
1636
1637 /* Clean up `__pformat_fcvt()' memory allocation for `value'...
1638 */
1639 __pformat_fcvt_release( value );
1640}
1641
1642#ifdef __ENABLE_DFP
1643
1644typedef struct decimal128_decode {
1645 int64_t significand[2];
1646 int32_t exponent;
1647 int sig_neg;
1648 int exp_neg;
1649} decimal128_decode;
1650
1651static uint32_t dec128_decode(decimal128_decode *result, const _Decimal128 deci){
1652 int64_t significand2;
1653 int64_t significand1;
1654 int32_t exp_part;
1655 int8_t sig_sign;
1656 ud128 in;
1657 in.d = deci;
1658
1659 if(in.t0.bits == 0x3){ /*case 11 */
1660 /* should not enter here */
1661 sig_sign = in.t2.sign;
1662 exp_part = in.t2.exponent;
1663 significand1 = in.t2.mantissaL;
1664 significand2 = (in.t2.mantissaH | (0x1ULL << 49));
1665 } else {
1666 sig_sign = in.t1.sign;
1667 exp_part = in.t1.exponent;
1668 significand1 = in.t1.mantissaL;
1669 significand2 = in.t1.mantissaH;
1670 }
1671 exp_part -= 6176; /* exp bias */
1672
1673 result->significand[0] = significand1;
1674 result->significand[1] = significand2; /* higher */
1675 result->exponent = exp_part;
1676 result->exp_neg = (exp_part < 0 )? 1 : 0;
1677 result->sig_neg = sig_sign;
1678
1679 return 0;
1680}
1681
1682static
1683void __pformat_efloat_decimal(_Decimal128 x, __pformat_t *stream ){
1684 decimal128_decode in;
1685 char str_exp[8];
1686 char str_sig[40];
1687 int floatclass = __fpclassifyd128(x);
1688
1689 /* precision control */
1690 int32_t prec = ( (stream->precision < 0) || (stream->precision > 38) ) ?
1691 6 : stream->precision;
1692 int32_t max_prec;
1693 int32_t exp_strlen;
1694
1695 dec128_decode(&in,x);
1696
1697 if((floatclass & FP_INFINITE) == FP_INFINITE){
1698 stream->precision = 3;
1699 if(stream->flags & PFORMAT_SIGNED)
1700 __pformat_putc( in.sig_neg ? '-' : '+', stream );
1701 __pformat_puts( (stream->flags & PFORMAT_XCASE) ? "inf" : "INF", stream);
1702 return;
1703 } else if(floatclass & FP_NAN){
1704 stream->precision = 3;
1705 if(stream->flags & PFORMAT_SIGNED)
1706 __pformat_putc( in.sig_neg ? '-' : '+', stream );
1707 __pformat_puts( (stream->flags & PFORMAT_XCASE) ? "nan" : "NAN", stream);
1708 return;
1709 }
1710
1711 /* Stringify significand */
1712 __bigint_to_string(
1713 (uint32_t[4]){in.significand[0] & 0x0ffffffff, in.significand[0] >> 32, in.significand[1] & 0x0ffffffff, in.significand[1] >> 32 },
1714 4, str_sig, sizeof(str_sig));
1715 __bigint_trim_leading_zeroes(str_sig,1);
1716 max_prec = strlen(str_sig+1);
1717
1718 /* Try to canonize exponent */
1719 in.exponent += max_prec;
1720 in.exp_neg = (in.exponent < 0 ) ? 1 : 0;
1721
1722 /* stringify exponent */
1723 __bigint_to_string(
1724 (uint32_t[1]) { in.exp_neg ? -in.exponent : in.exponent},
1725 1, str_exp, sizeof(str_exp));
1726 exp_strlen = strlen(__bigint_trim_leading_zeroes(str_exp,3));
1727
1728 /* account for dot, +-e */
1729 for(int32_t spacers = 0; spacers < stream->width - max_prec - exp_strlen - 4; spacers++)
1730 __pformat_putc( ' ', stream );
1731
1732 /* optional sign */
1733 if (in.sig_neg || (stream->flags & PFORMAT_SIGNED)) {
1734 __pformat_putc( in.sig_neg ? '-' : '+', stream );
1735 } else if( stream->width - max_prec - exp_strlen - 4 > 0 ) {
1736 __pformat_putc( ' ', stream );
1737 }
1738 stream->width = 0;
1739 /* s.sss form */
1740 __pformat_putc(str_sig[0], stream);
1741 if(prec) {
1742 /* str_sig[prec+1] = '\0';*/
1743 __pformat_emit_radix_point(stream);
1744 __pformat_putchars(str_sig+1, prec, stream);
1745
1746 /* Pad with 0s */
1747 for(int i = max_prec; i < prec; i++)
1748 __pformat_putc('0', stream);
1749 }
1750
1751 stream->precision = exp_strlen; /* force puts to emit */
1752
1753 __pformat_putc( ('E' | (stream->flags & PFORMAT_XCASE)), stream );
1754 __pformat_putc( in.exp_neg ? '-' : '+', stream );
1755
1756 for(int32_t trailing = 0; trailing < 3 - exp_strlen; trailing++)
1757 __pformat_putc('0', stream);
1758 __pformat_putchars(str_exp, exp_strlen,stream);
1759}
1760
1761static
1762void __pformat_float_decimal(_Decimal128 x, __pformat_t *stream ){
1763 decimal128_decode in;
1764 char str_exp[8];
1765 char str_sig[40];
1766 int floatclass = __fpclassifyd128(x);
1767
1768 /* precision control */
1769 int prec = ( (stream->precision < 0) || (stream->precision > 38) ) ?
1770 6 : stream->precision;
1771 int max_prec;
1772
1773 dec128_decode(&in,x);
1774
1775 if((floatclass & FP_INFINITE) == FP_INFINITE){
1776 stream->precision = 3;
1777 if(stream->flags & PFORMAT_SIGNED)
1778 __pformat_putc( in.sig_neg ? '-' : '+', stream );
1779 __pformat_puts( (stream->flags & PFORMAT_XCASE) ? "inf" : "INF", stream);
1780 return;
1781 } else if(floatclass & FP_NAN){
1782 stream->precision = 3;
1783 if(stream->flags & PFORMAT_SIGNED)
1784 __pformat_putc( in.sig_neg ? '-' : '+', stream );
1785 __pformat_puts( (stream->flags & PFORMAT_XCASE) ? "nan" : "NAN", stream);
1786 return;
1787 }
1788
1789 /* Stringify significand */
1790 __bigint_to_string(
1791 (uint32_t[4]){in.significand[0] & 0x0ffffffff, in.significand[0] >> 32, in.significand[1] & 0x0ffffffff, in.significand[1] >> 32 },
1792 4, str_sig, sizeof(str_sig));
1793 __bigint_trim_leading_zeroes(str_sig,0);
1794 max_prec = strlen(str_sig);
1795
1796 /* stringify exponent */
1797 __bigint_to_string(
1798 (uint32_t[1]) { in.exp_neg ? -in.exponent : in.exponent},
1799 1, str_exp, sizeof(str_exp));
1800 __bigint_trim_leading_zeroes(str_exp,0);
1801
1802 int32_t decimal_place = max_prec + in.exponent;
1803 int32_t sig_written = 0;
1804
1805 /*account for . +- */
1806 for(int32_t spacers = 0; spacers < stream->width - decimal_place - prec - 2; spacers++)
1807 __pformat_putc( ' ', stream );
1808
1809 if (in.sig_neg || (stream->flags & PFORMAT_SIGNED)) {
1810 __pformat_putc( in.sig_neg ? '-' : '+', stream );
1811 } else if(stream->width - decimal_place - prec - 1 > 0){
1812 __pformat_putc( ' ', stream );
1813 }
1814
1815 if(decimal_place <= 0){ /* easy mode */
1816 __pformat_putc( '0', stream );
1817 points:
1818 __pformat_emit_radix_point(stream);
1819 for(int32_t written = 0; written < prec; written++){
1820 if(decimal_place < 0){ /* leading 0s */
1821 decimal_place++;
1822 __pformat_putc( '0', stream );
1823 /* significand */
1824 } else if ( sig_written < max_prec ){
1825 __pformat_putc( str_sig[sig_written], stream );
1826 sig_written++;
1827 } else { /* trailing 0s */
1828 __pformat_putc( '0', stream );
1829 }
1830 }
1831 } else { /* hard mode */
1832 for(; sig_written < decimal_place; sig_written++){
1833 __pformat_putc( str_sig[sig_written], stream );
1834 if(sig_written == max_prec - 1) break;
1835 }
1836 decimal_place -= sig_written;
1837 for(; decimal_place > 0; decimal_place--)
1838 __pformat_putc( '0', stream );
1839 goto points;
1840 }
1841
1842 return;
1843}
1844
1845static
1846void __pformat_gfloat_decimal(_Decimal128 x, __pformat_t *stream ){
1847 int prec = ( (stream->precision < 0)) ?
1848 6 : stream->precision;
1849 decimal128_decode in;
1850 dec128_decode(&in,x);
1851 if(in.exponent > prec) __pformat_efloat_decimal(x,stream);
1852 else __pformat_float_decimal(x,stream);
1853}
1854
1855#endif /* __ENABLE_DFP */
1856
1857static
1858void __pformat_efloat( long double x, __pformat_t *stream )
1859{
1860 /* Handler for `%e' and `%E' format specifiers.
1861 *
1862 * This wraps calls to `__pformat_cvt()', `__pformat_emit_efloat()'
1863 * and `__pformat_emit_inf_or_nan()', as appropriate, to achieve
1864 * output in floating point format.
1865 */
1866 int sign, intlen; char *value;
1867
1868 /* Establish the precision for the displayed value, defaulting to six
1869 * digits following the decimal point, if not explicitly specified.
1870 */
1871 if( stream->precision < 0 )
1872 stream->precision = 6;
1873
1874 /* Encode the input value as ASCII, for display...
1875 */
1876 value = __pformat_ecvt( x, stream->precision + 1, &intlen, &sign );
1877
1878 if( intlen == PFORMAT_INFNAN )
1879 /*
1880 * handle cases of `infinity' or `not-a-number'...
1881 */
1882 __pformat_emit_inf_or_nan( sign, value, stream );
1883
1884 else
1885 /* or otherwise, emit the formatted result.
1886 */
1887 __pformat_emit_efloat( sign, value, intlen, stream );
1888
1889 /* Clean up `__pformat_ecvt()' memory allocation for `value'...
1890 */
1891 __pformat_ecvt_release( value );
1892}
1893
1894static
1895void __pformat_gfloat( long double x, __pformat_t *stream )
1896{
1897 /* Handler for `%g' and `%G' format specifiers.
1898 *
1899 * This wraps calls to `__pformat_cvt()', `__pformat_emit_float()',
1900 * `__pformat_emit_efloat()' and `__pformat_emit_inf_or_nan()', as
1901 * appropriate, to achieve output in the more suitable of either
1902 * fixed or floating point format.
1903 */
1904 int sign, intlen; char *value;
1905
1906 /* Establish the precision for the displayed value, defaulting to
1907 * six significant digits, if not explicitly specified...
1908 */
1909 if( stream->precision < 0 )
1910 stream->precision = 6;
1911
1912 /* or to a minimum of one digit, otherwise...
1913 */
1914 else if( stream->precision == 0 )
1915 stream->precision = 1;
1916
1917 /* Encode the input value as ASCII, for display.
1918 */
1919 value = __pformat_ecvt( x, stream->precision, &intlen, &sign );
1920
1921 if( intlen == PFORMAT_INFNAN )
1922 /*
1923 * Handle cases of `infinity' or `not-a-number'.
1924 */
1925 __pformat_emit_inf_or_nan( sign, value, stream );
1926
1927 else if( (-4 < intlen) && (intlen <= stream->precision) )
1928 {
1929 /* Value lies in the acceptable range for fixed point output,
1930 * (i.e. the exponent is no less than minus four, and the number
1931 * of significant digits which precede the radix point is fewer
1932 * than the least number which would overflow the field width,
1933 * specified or implied by the established precision).
1934 */
1935 if( (stream->flags & PFORMAT_HASHED) == PFORMAT_HASHED )
1936 /*
1937 * The `#' flag is in effect...
1938 * Adjust precision to retain the specified number of significant
1939 * digits, with the proper number preceding the radix point, and
1940 * the balance following it...
1941 */
1942 stream->precision -= intlen;
1943
1944 else
1945 /* The `#' flag is not in effect...
1946 * Here we adjust the precision to accommodate all digits which
1947 * precede the radix point, but we truncate any balance following
1948 * it, to suppress output of non-significant trailing zeros...
1949 */
1950 if( ((stream->precision = strlen( value ) - intlen) < 0)
1951 /*
1952 * This may require a compensating adjustment to the field
1953 * width, to accommodate significant trailing zeros, which
1954 * precede the radix point...
1955 */
1956 && (stream->width > 0) )
1957 stream->width += stream->precision;
1958
1959 /* Now, we format the result as any other fixed point value.
1960 */
1961 __pformat_emit_float( sign, value, intlen, stream );
1962
1963 /* If there is any residual field width as yet unfilled, then
1964 * we must be doing flush left justification, so pad out to the
1965 * right hand field boundary.
1966 */
1967 while( stream->width-- > 0 )
1968 __pformat_putc( '\x20', stream );
1969 }
1970
1971 else
1972 { /* Value lies outside the acceptable range for fixed point;
1973 * one significant digit will precede the radix point, so we
1974 * decrement the precision to retain only the appropriate number
1975 * of additional digits following it, when we emit the result
1976 * in floating point format.
1977 */
1978 if( (stream->flags & PFORMAT_HASHED) == PFORMAT_HASHED )
1979 /*
1980 * The `#' flag is in effect...
1981 * Adjust precision to emit the specified number of significant
1982 * digits, with one preceding the radix point, and the balance
1983 * following it, retaining any non-significant trailing zeros
1984 * which are required to exactly match the requested precision...
1985 */
1986 stream->precision--;
1987
1988 else
1989 /* The `#' flag is not in effect...
1990 * Adjust precision to emit only significant digits, with one
1991 * preceding the radix point, and any others following it, but
1992 * suppressing non-significant trailing zeros...
1993 */
1994 stream->precision = strlen( value ) - 1;
1995
1996 /* Now, we format the result as any other floating point value.
1997 */
1998 __pformat_emit_efloat( sign, value, intlen, stream );
1999 }
2000
2001 /* Clean up `__pformat_ecvt()' memory allocation for `value'.
2002 */
2003 __pformat_ecvt_release( value );
2004}
2005
2006static
2007void __pformat_emit_xfloat( __pformat_fpreg_t value, __pformat_t *stream )
2008{
2009 /* Helper for emitting floating point data, originating as
2010 * either `double' or `long double' type, as a hexadecimal
2011 * representation of the argument value.
2012 */
2013 char buf[18 + 6], *p = buf;
2014 __pformat_intarg_t exponent; short exp_width = 2;
2015
2016 if (value.__pformat_fpreg_mantissa != 0 ||
2017 value.__pformat_fpreg_exponent != 0)
2018 {
2019 /* Reduce the exponent since the leading digit emited will start at
2020 * the 4th bit from the highest order bit instead, the later being
2021 * the leading digit of the floating point. Don't do this adjustment
2022 * if the value is an actual zero.
2023 */
2024 value.__pformat_fpreg_exponent -= 3;
2025 }
2026
2027 /* The mantissa field of the argument value representation can
2028 * accommodate at most 16 hexadecimal digits, of which one will
2029 * be placed before the radix point, leaving at most 15 digits
2030 * to satisfy any requested precision; thus...
2031 */
2032 if( (stream->precision >= 0) && (stream->precision < 15) )
2033 {
2034 /* When the user specifies a precision within this range,
2035 * we want to adjust the mantissa, to retain just the number
2036 * of digits required, rounding up when the high bit of the
2037 * leftmost discarded digit is set; (mask of 0x08 accounts
2038 * for exactly one digit discarded, shifting 4 bits per
2039 * digit, with up to 14 additional digits, to consume the
2040 * full availability of 15 precision digits).
2041 */
2042
2043 /* We then shift the mantissa one bit position back to the
2044 * right, to guard against possible overflow when the rounding
2045 * adjustment is added.
2046 */
2047 value.__pformat_fpreg_mantissa >>= 1;
2048
2049 /* We now add the rounding adjustment, noting that to keep the
2050 * 0x08 mask aligned with the shifted mantissa, we also need to
2051 * shift it right by one bit initially, changing its starting
2052 * value to 0x04...
2053 */
2054 value.__pformat_fpreg_mantissa += 0x04LL << (4 * (14 - stream->precision));
2055 if( (value.__pformat_fpreg_mantissa & (LLONG_MAX + 1ULL)) == 0ULL )
2056 /*
2057 * When the rounding adjustment would not have overflowed,
2058 * then we shift back to the left again, to fill the vacated
2059 * bit we reserved to accommodate the carry.
2060 */
2061 value.__pformat_fpreg_mantissa <<= 1;
2062
2063 else
2064 {
2065 /* Otherwise the rounding adjustment would have overflowed,
2066 * so the carry has already filled the vacated bit; the effect
2067 * of this is equivalent to an increment of the exponent. We will
2068 * discard a whole digit to match glibc's behavior.
2069 */
2070 value.__pformat_fpreg_exponent += 4;
2071 value.__pformat_fpreg_mantissa >>= 3;
2072 }
2073
2074 /* We now complete the rounding to the required precision, by
2075 * shifting the unwanted digits out, from the right hand end of
2076 * the mantissa.
2077 */
2078 value.__pformat_fpreg_mantissa >>= 4 * (15 - stream->precision);
2079 }
2080
2081 /* Don't print anything if mantissa is zero unless we have to satisfy
2082 * desired precision.
2083 */
2084 if( value.__pformat_fpreg_mantissa || stream->precision > 0 )
2085 {
2086 /* Encode the significant digits of the mantissa in hexadecimal
2087 * ASCII notation, ready for transfer to the output stream...
2088 */
2089 for( int i=stream->precision >= 15 || stream->precision < 0 ? 16 : stream->precision + 1; i>0; --i )
2090 {
2091 /* taking the rightmost digit in each pass...
2092 */
2093 unsigned c = value.__pformat_fpreg_mantissa & 0xF;
2094 if( i == 1 )
2095 {
2096 /* inserting the radix point, when we reach the last,
2097 * (i.e. the most significant digit), unless we found no
2098 * less significant digits, with no mandatory radix point
2099 * inclusion, and no additional required precision...
2100 */
2101 if( (p > buf)
2102 || (stream->flags & PFORMAT_HASHED) || (stream->precision > 0) )
2103 {
2104 /*
2105 * Internally, we represent the radix point as an ASCII '.';
2106 * we will replace it with any locale specific alternative,
2107 * at the time of transfer to the ultimate destination.
2108 */
2109 *p++ = '.';
2110 }
2111 }
2112
2113 else if( stream->precision > 0 )
2114 /*
2115 * we have not yet fulfilled the desired precision,
2116 * and we have not yet found the most significant digit,
2117 * so account for the current digit, within the field
2118 * width required to meet the specified precision.
2119 */
2120 stream->precision--;
2121
2122 if( (c > 0) || (p > buf) || (stream->precision >= 0) )
2123 {
2124 /*
2125 * Ignoring insignificant trailing zeros, (unless required to
2126 * satisfy specified precision), store the current encoded digit
2127 * into the pending output buffer, in LIFO order, and using the
2128 * appropriate case for digits in the `A'..`F' range.
2129 */
2130 *p++ = c > 9 ? (c - 10 + 'A') | (stream->flags & PFORMAT_XCASE) : c + '0';
2131 }
2132 /* Shift out the current digit, (4-bit logical shift right),
2133 * to align the next more significant digit to be extracted,
2134 * and encoded in the next pass.
2135 */
2136 value.__pformat_fpreg_mantissa >>= 4;
2137 }
2138 }
2139
2140 if( p == buf )
2141 {
2142 /* Nothing has been queued for output...
2143 * We need at least one zero, and possibly a radix point.
2144 */
2145 if( (stream->precision > 0) || (stream->flags & PFORMAT_HASHED) )
2146 *p++ = '.';
2147
2148 *p++ = '0';
2149 }
2150
2151 if( stream->width > 0 )
2152 {
2153 /* Adjust the user specified field width, to account for the
2154 * number of digits minimally required, to display the encoded
2155 * value, at the requested precision.
2156 *
2157 * FIXME: this uses the minimum number of digits possible for
2158 * representation of the binary exponent, in strict conformance
2159 * with C99 and POSIX specifications. Although there appears to
2160 * be no Microsoft precedent for doing otherwise, we may wish to
2161 * relate this to the `_get_output_format()' result, to maintain
2162 * consistency with `%e', `%f' and `%g' styles.
2163 */
2164 int min_width = p - buf;
2165 int exponent2 = value.__pformat_fpreg_exponent;
2166
2167 /* If we have not yet queued sufficient digits to fulfil the
2168 * requested precision, then we must adjust the minimum width
2169 * specification, to accommodate the additional digits which
2170 * are required to do so.
2171 */
2172 if( stream->precision > 0 )
2173 min_width += stream->precision;
2174
2175 /* Adjust the minimum width requirement, to accomodate the
2176 * sign, radix indicator and at least one exponent digit...
2177 */
2178 min_width += stream->flags & PFORMAT_SIGNED ? 6 : 5;
2179 while( (exponent2 = exponent2 / 10) != 0 )
2180 {
2181 /* and increase as required, if additional exponent digits
2182 * are needed, also saving the exponent field width adjustment,
2183 * for later use when that is emitted.
2184 */
2185 min_width++;
2186 exp_width++;
2187 }
2188
2189 if( stream->width > min_width )
2190 {
2191 /* When specified field width exceeds the minimum required,
2192 * adjust to retain only the excess...
2193 */
2194 stream->width -= min_width;
2195
2196 /* and then emit any required left side padding spaces.
2197 */
2198 if( (stream->flags & PFORMAT_JUSTIFY) == 0 )
2199 while( stream->width-- > 0 )
2200 __pformat_putc( '\x20', stream );
2201 }
2202
2203 else
2204 /* Specified field width is insufficient; just ignore it!
2205 */
2206 stream->width = PFORMAT_IGNORE;
2207 }
2208
2209 /* Emit the sign of the encoded value, as required...
2210 */
2211 if( stream->flags & PFORMAT_NEGATIVE )
2212 /*
2213 * this is mandatory, to indicate a negative value...
2214 */
2215 __pformat_putc( '-', stream );
2216
2217 else if( stream->flags & PFORMAT_POSITIVE )
2218 /*
2219 * but this is optional, for a positive value...
2220 */
2221 __pformat_putc( '+', stream );
2222
2223 else if( stream->flags & PFORMAT_ADDSPACE )
2224 /*
2225 * with this optional alternative.
2226 */
2227 __pformat_putc( '\x20', stream );
2228
2229 /* Prefix a `0x' or `0X' radix indicator to the encoded value,
2230 * with case appropriate to the format specification.
2231 */
2232 __pformat_putc( '0', stream );
2233 __pformat_putc( 'X' | (stream->flags & PFORMAT_XCASE), stream );
2234
2235 /* If the `0' flag is in effect...
2236 * Zero padding, to fill out the field, goes here...
2237 */
2238 if( (stream->width > 0) && (stream->flags & PFORMAT_ZEROFILL) )
2239 while( stream->width-- > 0 )
2240 __pformat_putc( '0', stream );
2241
2242 /* Next, we emit the encoded value, without its exponent...
2243 */
2244 while( p > buf )
2245 __pformat_emit_numeric_value( *--p, stream );
2246
2247 /* followed by any additional zeros needed to satisfy the
2248 * precision specification...
2249 */
2250 while( stream->precision-- > 0 )
2251 __pformat_putc( '0', stream );
2252
2253 /* then the exponent prefix, (C99 and POSIX specify `p'),
2254 * in the case appropriate to the format specification...
2255 */
2256 __pformat_putc( 'P' | (stream->flags & PFORMAT_XCASE), stream );
2257
2258 /* and finally, the decimal representation of the binary exponent,
2259 * as a signed value with mandatory sign displayed, in a field width
2260 * adjusted to accommodate it, LEFT justified, with any additional
2261 * right side padding remaining from the original field width.
2262 */
2263 stream->width += exp_width;
2264 stream->flags |= PFORMAT_SIGNED;
2265 /* sign extend */
2266 exponent.__pformat_u128_t.t128.digits[1] = (value.__pformat_fpreg_exponent < 0) ? -1 : 0;
2267 exponent.__pformat_u128_t.t128.digits[0] = value.__pformat_fpreg_exponent;
2268 __pformat_int( exponent, stream );
2269}
2270
2271static
2272void __pformat_xldouble( long double x, __pformat_t *stream )
2273{
2274 /* Handler for `%La' and `%LA' format specifiers, (with argument
2275 * value specified as `long double' type).
2276 */
2277 unsigned sign_bit = 0;
2278 __pformat_fpreg_t z = init_fpreg_ldouble( x );
2279
2280 /* First check for NaN; it is emitted unsigned...
2281 */
2282 if( isnan( x ) )
2283 __pformat_emit_inf_or_nan( sign_bit, "NaN", stream );
2284
2285 else
2286 { /* Capture the sign bit up-front, so we can show it correctly
2287 * even when the argument value is zero or infinite.
2288 */
2289 if( (sign_bit = (z.__pformat_fpreg_exponent & 0x8000)) != 0 )
2290 stream->flags |= PFORMAT_NEGATIVE;
2291
2292 /* Check for infinity, (positive or negative)...
2293 */
2294 if( isinf( x ) )
2295 /*
2296 * displaying the appropriately signed indicator,
2297 * when appropriate.
2298 */
2299 __pformat_emit_inf_or_nan( sign_bit, "Inf", stream );
2300
2301 else
2302 { /* The argument value is a representable number...
2303 * extract the effective value of the biased exponent...
2304 */
2305 z.__pformat_fpreg_exponent &= 0x7FFF;
2306 if( z.__pformat_fpreg_exponent == 0 )
2307 {
2308 /* A biased exponent value of zero means either a
2309 * true zero value, if the mantissa field also has
2310 * a zero value, otherwise...
2311 */
2312 if( z.__pformat_fpreg_mantissa != 0 )
2313 {
2314 /* ...this mantissa represents a subnormal value.
2315 */
2316 z.__pformat_fpreg_exponent = 1 - 0x3FFF;
2317 }
2318 }
2319 else
2320 /* This argument represents a non-zero normal number;
2321 * eliminate the bias from the exponent...
2322 */
2323 z.__pformat_fpreg_exponent -= 0x3FFF;
2324
2325 /* Finally, hand the adjusted representation off to the
2326 * generalised hexadecimal floating point format handler...
2327 */
2328 __pformat_emit_xfloat( z, stream );
2329 }
2330 }
2331}
2332
2333static
2334void __pformat_xdouble( double x, __pformat_t *stream )
2335{
2336 /* Handler for `%la' and `%lA' format specifiers, (with argument
2337 * value specified as `double' type).
2338 */
2339 unsigned sign_bit = 0;
2340 __pformat_fpreg_t z = init_fpreg_ldouble( (long double)x );
2341
2342 /* First check for NaN; it is emitted unsigned...
2343 */
2344 if( isnan( x ) )
2345 __pformat_emit_inf_or_nan( sign_bit, "NaN", stream );
2346
2347 else
2348 { /* Capture the sign bit up-front, so we can show it correctly
2349 * even when the argument value is zero or infinite.
2350 */
2351 if( (sign_bit = (z.__pformat_fpreg_exponent & 0x8000)) != 0 )
2352 stream->flags |= PFORMAT_NEGATIVE;
2353
2354 /* Check for infinity, (positive or negative)...
2355 */
2356 if( isinf( x ) )
2357 /*
2358 * displaying the appropriately signed indicator,
2359 * when appropriate.
2360 */
2361 __pformat_emit_inf_or_nan( sign_bit, "Inf", stream );
2362
2363 else
2364 { /* The argument value is a representable number...
2365 * extract the effective value of the biased exponent...
2366 */
2367 z.__pformat_fpreg_exponent &= 0x7FFF;
2368
2369 /* If the double value was a denormalized number, it might have been renormalized by
2370 * the conversion to long double. We will redenormalize it.
2371 */
2372 if( z.__pformat_fpreg_exponent != 0 && z.__pformat_fpreg_exponent <= (0x3FFF - 0x3FF) )
2373 {
2374 int shifted = (0x3FFF - 0x3FF) - z.__pformat_fpreg_exponent + 1;
2375 z.__pformat_fpreg_mantissa >>= shifted;
2376 z.__pformat_fpreg_exponent += shifted;
2377 }
2378
2379 if( z.__pformat_fpreg_exponent == 0 )
2380 {
2381 /* A biased exponent value of zero means either a
2382 * true zero value, if the mantissa field also has
2383 * a zero value, otherwise...
2384 */
2385 if( z.__pformat_fpreg_mantissa != 0 )
2386 {
2387 /* ...this mantissa represents a subnormal value.
2388 */
2389 z.__pformat_fpreg_exponent = 1 - 0x3FF + 3;
2390 }
2391 }
2392 else
2393 /* This argument represents a non-zero normal number;
2394 * eliminate the bias from the exponent...
2395 */
2396 z.__pformat_fpreg_exponent -= 0x3FFF - 3;
2397
2398 /* Shift the mantissa so the leading 4 bits digit is 0 or 1.
2399 * The exponent was also adjusted by 3 previously.
2400 */
2401 z.__pformat_fpreg_mantissa >>= 3;
2402
2403 /* Finally, hand the adjusted representation off to the
2404 * generalised hexadecimal floating point format handler...
2405 */
2406 __pformat_emit_xfloat( z, stream );
2407 }
2408 }
2409}
2410
2411int
2412__pformat (int flags, void *dest, int max, const APICHAR *fmt, va_list argv)
2413{
2414 int c;
2415 int saved_errno = errno;
2416
2417 __pformat_t stream =
2418 {
2419 /* Create and initialise a format control block
2420 * for this output request.
2421 */
2422 dest, /* output goes to here */
2423 flags &= PFORMAT_TO_FILE | PFORMAT_NOLIMIT, /* only these valid initially */
2424 PFORMAT_IGNORE, /* no field width yet */
2425 PFORMAT_IGNORE, /* nor any precision spec */
2426 PFORMAT_RPINIT, /* radix point uninitialised */
2427 (wchar_t)(0), /* leave it unspecified */
2428 0,
2429 (wchar_t)(0), /* leave it unspecified */
2430 0, /* zero output char count */
2431 max, /* establish output limit */
2432 -1 /* exponent chars preferred;
2433 -1 means to be determined. */
2434 };
2435
2436#ifdef __BUILD_WIDEAPI
2437 const APICHAR *literal_string_start = NULL;
2438#endif
2439
2440 format_scan: while( (c = *fmt++) != 0 )
2441 {
2442 /* Format string parsing loop...
2443 * The entry point is labelled, so that we can return to the start state
2444 * from within the inner `conversion specification' interpretation loop,
2445 * as soon as a conversion specification has been resolved.
2446 */
2447 if( c == '%' )
2448 {
2449 /* Initiate parsing of a `conversion specification'...
2450 */
2451 __pformat_intarg_t argval;
2452 __pformat_state_t state = PFORMAT_INIT;
2453 __pformat_length_t length = PFORMAT_LENGTH_INT;
2454
2455 /* Save the current format scan position, so that we can backtrack
2456 * in the event of encountering an invalid format specification...
2457 */
2458 const APICHAR *backtrack = fmt;
2459
2460 /* Restart capture for dynamic field width and precision specs...
2461 */
2462 int *width_spec = &stream.width;
2463
2464 #ifdef __BUILD_WIDEAPI
2465 if (literal_string_start)
2466 {
2467 stream.width = stream.precision = PFORMAT_IGNORE;
2468 __pformat_wputchars( literal_string_start, fmt - literal_string_start - 1, &stream );
2469 literal_string_start = NULL;
2470 }
2471 #endif
2472
2473 /* Reset initial state for flags, width and precision specs...
2474 */
2475 stream.flags = flags;
2476 stream.width = stream.precision = PFORMAT_IGNORE;
2477
2478 while( *fmt )
2479 {
2480 switch( c = *fmt++ )
2481 {
2482 /* Data type specifiers...
2483 * All are terminal, so exit the conversion spec parsing loop
2484 * with a `goto format_scan', thus resuming at the outer level
2485 * in the regular format string parser.
2486 */
2487 case '%':
2488 /*
2489 * Not strictly a data type specifier...
2490 * it simply converts as a literal `%' character.
2491 *
2492 * FIXME: should we require this to IMMEDIATELY follow the
2493 * initial `%' of the "conversion spec"? (glibc `printf()'
2494 * on GNU/Linux does NOT appear to require this, but POSIX
2495 * and SUSv3 do seem to demand it).
2496 */
2497 #ifndef __BUILD_WIDEAPI
2498 __pformat_putc( c, &stream );
2499 #else
2500 stream.width = stream.precision = PFORMAT_IGNORE;
2501 __pformat_wputchars( L"%", 1, &stream );
2502 #endif
2503 goto format_scan;
2504
2505 case 'C':
2506 /*
2507 * Equivalent to `%lc'; set `length' accordingly,
2508 * and simply fall through.
2509 */
2510 length = PFORMAT_LENGTH_LONG;
2511
2512 /* fallthrough */
2513
2514 case 'c':
2515 /*
2516 * Single, (or single multibyte), character output...
2517 *
2518 * We handle these by copying the argument into our local
2519 * `argval' buffer, and then we pass the address of that to
2520 * either `__pformat_putchars()' or `__pformat_wputchars()',
2521 * as appropriate, effectively formatting it as a string of
2522 * the appropriate type, with a length of one.
2523 *
2524 * A side effect of this method of handling character data
2525 * is that, if the user sets a precision of zero, then no
2526 * character is actually emitted; we don't want that, so we
2527 * forcibly override any user specified precision.
2528 */
2529 stream.precision = PFORMAT_IGNORE;
2530
2531 /* Now we invoke the appropriate format handler...
2532 */
2533 if( (length == PFORMAT_LENGTH_LONG)
2534 || (length == PFORMAT_LENGTH_LLONG) )
2535 {
2536 /* considering any `long' type modifier as a reference to
2537 * `wchar_t' data, (which is promoted to an `int' argument)...
2538 */
2539 wchar_t iargval = (wchar_t)(va_arg( argv, int ));
2540 __pformat_wputchars( &iargval, 1, &stream );
2541 }
2542 else
2543 { /* while anything else is simply taken as `char', (which
2544 * is also promoted to an `int' argument)...
2545 */
2546 argval.__pformat_uchar_t = (unsigned char)(va_arg( argv, int ));
2547 __pformat_putchars( (char *)(&argval), 1, &stream );
2548 }
2549 goto format_scan;
2550
2551 case 'S':
2552 /*
2553 * Equivalent to `%ls'; set `length' accordingly,
2554 * and simply fall through.
2555 */
2556 length = PFORMAT_LENGTH_LONG;
2557
2558 /* fallthrough */
2559
2560 case 's':
2561 if( (length == PFORMAT_LENGTH_LONG)
2562 || (length == PFORMAT_LENGTH_LLONG))
2563 {
2564 /* considering any `long' type modifier as a reference to
2565 * a `wchar_t' string...
2566 */
2567 __pformat_wcputs( va_arg( argv, wchar_t * ), &stream );
2568 }
2569 else
2570 /* This is normal string output;
2571 * we simply invoke the appropriate handler...
2572 */
2573 __pformat_puts( va_arg( argv, char * ), &stream );
2574 goto format_scan;
2575 case 'm': /* strerror (errno) */
2576 __pformat_puts (strerror (saved_errno), &stream);
2577 goto format_scan;
2578
2579 case 'o':
2580 case 'u':
2581 case 'x':
2582 case 'X':
2583 /*
2584 * Unsigned integer values; octal, decimal or hexadecimal format...
2585 */
2586 stream.flags &= ~PFORMAT_POSITIVE;
2587#if __ENABLE_PRINTF128
2588 argval.__pformat_u128_t.t128.digits[1] = 0LL; /* no sign extend needed */
2589 if( length == PFORMAT_LENGTH_LLONG128 )
2590 argval.__pformat_u128_t.t128 = va_arg( argv, __tI128 );
2591 else
2592#endif
2593 if( length == PFORMAT_LENGTH_LLONG ) {
2594 /*
2595 * with an `unsigned long long' argument, which we
2596 * process `as is'...
2597 */
2598 argval.__pformat_ullong_t = va_arg( argv, unsigned long long );
2599
2600 } else if( length == PFORMAT_LENGTH_LONG ) {
2601 /*
2602 * or with an `unsigned long', which we promote to
2603 * `unsigned long long'...
2604 */
2605 argval.__pformat_ullong_t = va_arg( argv, unsigned long );
2606
2607 } else
2608 { /* or for any other size, which will have been promoted
2609 * to `unsigned int', we select only the appropriately sized
2610 * least significant segment, and again promote to the same
2611 * size as `unsigned long long'...
2612 */
2613 argval.__pformat_ullong_t = va_arg( argv, unsigned int );
2614 if( length == PFORMAT_LENGTH_SHORT )
2615 /*
2616 * from `unsigned short'...
2617 */
2618 argval.__pformat_ullong_t = argval.__pformat_ushort_t;
2619
2620 else if( length == PFORMAT_LENGTH_CHAR )
2621 /*
2622 * or even from `unsigned char'...
2623 */
2624 argval.__pformat_ullong_t = argval.__pformat_uchar_t;
2625 }
2626
2627 /* so we can pass any size of argument to either of two
2628 * common format handlers...
2629 */
2630 if( c == 'u' )
2631 /*
2632 * depending on whether output is to be encoded in
2633 * decimal format...
2634 */
2635 __pformat_int( argval, &stream );
2636
2637 else
2638 /* or in octal or hexadecimal format...
2639 */
2640 __pformat_xint( c, argval, &stream );
2641
2642 goto format_scan;
2643
2644 case 'd':
2645 case 'i':
2646 /*
2647 * Signed integer values; decimal format...
2648 * This is similar to `u', but must process `argval' as signed,
2649 * and be prepared to handle negative numbers.
2650 */
2651 stream.flags |= PFORMAT_NEGATIVE;
2652#if __ENABLE_PRINTF128
2653 if( length == PFORMAT_LENGTH_LLONG128 ) {
2654 argval.__pformat_u128_t.t128 = va_arg( argv, __tI128 );
2655 goto skip_sign; /* skip sign extend */
2656 } else
2657#endif
2658 if( length == PFORMAT_LENGTH_LLONG ){
2659 /*
2660 * The argument is a `long long' type...
2661 */
2662 argval.__pformat_u128_t.t128.digits[0] = va_arg( argv, long long );
2663 } else if( length == PFORMAT_LENGTH_LONG ) {
2664 /*
2665 * or here, a `long' type...
2666 */
2667 argval.__pformat_u128_t.t128.digits[0] = va_arg( argv, long );
2668 } else
2669 { /* otherwise, it's an `int' type...
2670 */
2671 argval.__pformat_u128_t.t128.digits[0] = va_arg( argv, int );
2672 if( length == PFORMAT_LENGTH_SHORT )
2673 /*
2674 * but it was promoted from a `short' type...
2675 */
2676 argval.__pformat_u128_t.t128.digits[0] = argval.__pformat_short_t;
2677 else if( length == PFORMAT_LENGTH_CHAR )
2678 /*
2679 * or even from a `char' type...
2680 */
2681 argval.__pformat_u128_t.t128.digits[0] = argval.__pformat_char_t;
2682 }
2683
2684 /* In any case, all share a common handler...
2685 */
2686 argval.__pformat_u128_t.t128.digits[1] = (argval.__pformat_llong_t < 0) ? -1LL : 0LL;
2687#if __ENABLE_PRINTF128
2688 skip_sign:
2689#endif
2690 __pformat_int( argval, &stream );
2691 goto format_scan;
2692
2693 case 'p':
2694 /*
2695 * Pointer argument; format as hexadecimal, subject to...
2696 */
2697 if( (state == PFORMAT_INIT) && (stream.flags == flags) )
2698 {
2699 /* Here, the user didn't specify any particular
2700 * formatting attributes. We must choose a default
2701 * which will be compatible with Microsoft's (broken)
2702 * scanf() implementation, (i.e. matching the default
2703 * used by MSVCRT's printf(), which appears to resemble
2704 * "%0.8X" for 32-bit pointers); in particular, we MUST
2705 * NOT adopt a GNU-like format resembling "%#x", because
2706 * Microsoft's scanf() will choke on the "0x" prefix.
2707 */
2708 stream.flags |= PFORMAT_ZEROFILL;
2709 stream.precision = 2 * sizeof( uintptr_t );
2710 }
2711 argval.__pformat_u128_t.t128.digits[0] = va_arg( argv, uintptr_t );
2712 argval.__pformat_u128_t.t128.digits[1] = 0;
2713 __pformat_xint( 'x', argval, &stream );
2714 goto format_scan;
2715
2716 case 'e':
2717 /*
2718 * Floating point format, with lower case exponent indicator
2719 * and lower case `inf' or `nan' representation when required;
2720 * select lower case mode, and simply fall through...
2721 */
2722 stream.flags |= PFORMAT_XCASE;
2723
2724 /* fallthrough */
2725
2726 case 'E':
2727 /*
2728 * Floating point format, with upper case exponent indicator
2729 * and upper case `INF' or `NAN' representation when required,
2730 * (or lower case for all of these, on fall through from above);
2731 * select lower case mode, and simply fall through...
2732 */
2733#ifdef __ENABLE_DFP
2734 if( stream.flags & PFORMAT_DECIM32 )
2735 /* Is a 32bit decimal float */
2736 __pformat_efloat_decimal((_Decimal128)va_arg( argv, _Decimal32 ), &stream );
2737 else if( stream.flags & PFORMAT_DECIM64 )
2738 /*
2739 * Is a 64bit decimal float
2740 */
2741 __pformat_efloat_decimal((_Decimal128)va_arg( argv, _Decimal64 ), &stream );
2742 else if( stream.flags & PFORMAT_DECIM128 )
2743 /*
2744 * Is a 128bit decimal float
2745 */
2746 __pformat_efloat_decimal(va_arg( argv, _Decimal128 ), &stream );
2747 else
2748#endif /* __ENABLE_DFP */
2749 if( stream.flags & PFORMAT_LDOUBLE )
2750 /*
2751 * for a `long double' argument...
2752 */
2753 __pformat_efloat( va_arg( argv, long double ), &stream );
2754
2755 else
2756 /* or just a `double', which we promote to `long double',
2757 * so the two may share a common format handler.
2758 */
2759 __pformat_efloat( (long double)(va_arg( argv, double )), &stream );
2760
2761 goto format_scan;
2762
2763 case 'f':
2764 /*
2765 * Fixed point format, using lower case for `inf' and
2766 * `nan', when appropriate; select lower case mode, and
2767 * simply fall through...
2768 */
2769 stream.flags |= PFORMAT_XCASE;
2770
2771 /* fallthrough */
2772
2773 case 'F':
2774 /*
2775 * Fixed case format using upper case, or lower case on
2776 * fall through from above, for `INF' and `NAN'...
2777 */
2778#ifdef __ENABLE_DFP
2779 if( stream.flags & PFORMAT_DECIM32 )
2780 /* Is a 32bit decimal float */
2781 __pformat_float_decimal((_Decimal128)va_arg( argv, _Decimal32 ), &stream );
2782 else if( stream.flags & PFORMAT_DECIM64 )
2783 /*
2784 * Is a 64bit decimal float
2785 */
2786 __pformat_float_decimal((_Decimal128)va_arg( argv, _Decimal64 ), &stream );
2787 else if( stream.flags & PFORMAT_DECIM128 )
2788 /*
2789 * Is a 128bit decimal float
2790 */
2791 __pformat_float_decimal(va_arg( argv, _Decimal128 ), &stream );
2792 else
2793#endif /* __ENABLE_DFP */
2794 if( stream.flags & PFORMAT_LDOUBLE )
2795 /*
2796 * for a `long double' argument...
2797 */
2798 __pformat_float( va_arg( argv, long double ), &stream );
2799
2800 else
2801 /* or just a `double', which we promote to `long double',
2802 * so the two may share a common format handler.
2803 */
2804 __pformat_float( (long double)(va_arg( argv, double )), &stream );
2805
2806 goto format_scan;
2807
2808 case 'g':
2809 /*
2810 * Generalised floating point format, with lower case
2811 * exponent indicator when required; select lower case
2812 * mode, and simply fall through...
2813 */
2814 stream.flags |= PFORMAT_XCASE;
2815
2816 /* fallthrough */
2817
2818 case 'G':
2819 /*
2820 * Generalised floating point format, with upper case,
2821 * or on fall through from above, with lower case exponent
2822 * indicator when required...
2823 */
2824#ifdef __ENABLE_DFP
2825 if( stream.flags & PFORMAT_DECIM32 )
2826 /* Is a 32bit decimal float */
2827 __pformat_gfloat_decimal((_Decimal128)va_arg( argv, _Decimal32 ), &stream );
2828 else if( stream.flags & PFORMAT_DECIM64 )
2829 /*
2830 * Is a 64bit decimal float
2831 */
2832 __pformat_gfloat_decimal((_Decimal128)va_arg( argv, _Decimal64 ), &stream );
2833 else if( stream.flags & PFORMAT_DECIM128 )
2834 /*
2835 * Is a 128bit decimal float
2836 */
2837 __pformat_gfloat_decimal(va_arg( argv, _Decimal128 ), &stream );
2838 else
2839#endif /* __ENABLE_DFP */
2840 if( stream.flags & PFORMAT_LDOUBLE )
2841 /*
2842 * for a `long double' argument...
2843 */
2844 __pformat_gfloat( va_arg( argv, long double ), &stream );
2845
2846 else
2847 /* or just a `double', which we promote to `long double',
2848 * so the two may share a common format handler.
2849 */
2850 __pformat_gfloat( (long double)(va_arg( argv, double )), &stream );
2851
2852 goto format_scan;
2853
2854 case 'a':
2855 /*
2856 * Hexadecimal floating point format, with lower case radix
2857 * and exponent indicators; select the lower case mode, and
2858 * fall through...
2859 */
2860 stream.flags |= PFORMAT_XCASE;
2861
2862 /* fallthrough */
2863
2864 case 'A':
2865 /*
2866 * Hexadecimal floating point format; handles radix and
2867 * exponent indicators in either upper or lower case...
2868 */
2869 if( sizeof( double ) != sizeof( long double ) && stream.flags & PFORMAT_LDOUBLE )
2870 /*
2871 * with a `long double' argument...
2872 */
2873 __pformat_xldouble( va_arg( argv, long double ), &stream );
2874
2875 else
2876 /* or just a `double'.
2877 */
2878 __pformat_xdouble( va_arg( argv, double ), &stream );
2879
2880 goto format_scan;
2881
2882 case 'n':
2883 /*
2884 * Save current output character count...
2885 */
2886 if( length == PFORMAT_LENGTH_CHAR )
2887 /*
2888 * to a signed `char' destination...
2889 */
2890 *va_arg( argv, char * ) = stream.count;
2891
2892 else if( length == PFORMAT_LENGTH_SHORT )
2893 /*
2894 * or to a signed `short'...
2895 */
2896 *va_arg( argv, short * ) = stream.count;
2897
2898 else if( length == PFORMAT_LENGTH_LONG )
2899 /*
2900 * or to a signed `long'...
2901 */
2902 *va_arg( argv, long * ) = stream.count;
2903
2904 else if( length == PFORMAT_LENGTH_LLONG )
2905 /*
2906 * or to a signed `long long'...
2907 */
2908 *va_arg( argv, long long * ) = stream.count;
2909
2910 else
2911 /*
2912 * or, by default, to a signed `int'.
2913 */
2914 *va_arg( argv, int * ) = stream.count;
2915
2916 goto format_scan;
2917
2918 /* Argument length modifiers...
2919 * These are non-terminal; each sets the format parser
2920 * into the PFORMAT_END state, and ends with a `break'.
2921 */
2922 case 'h':
2923 /*
2924 * Interpret the argument as explicitly of a `short'
2925 * or `char' data type, truncated from the standard
2926 * length defined for integer promotion.
2927 */
2928 if( *fmt == 'h' )
2929 {
2930 /* Modifier is `hh'; data type is `char' sized...
2931 * Skip the second `h', and set length accordingly.
2932 */
2933 ++fmt;
2934 length = PFORMAT_LENGTH_CHAR;
2935 }
2936
2937 else
2938 /* Modifier is `h'; data type is `short' sized...
2939 */
2940 length = PFORMAT_LENGTH_SHORT;
2941
2942 state = PFORMAT_END;
2943 break;
2944
2945 case 'j':
2946 /*
2947 * Interpret the argument as being of the same size as
2948 * a `intmax_t' entity...
2949 */
2950 length = __pformat_arg_length( intmax_t );
2951 state = PFORMAT_END;
2952 break;
2953
2954# ifdef _WIN32
2955
2956 case 'I':
2957 /*
2958 * The MSVCRT implementation of the printf() family of
2959 * functions explicitly uses...
2960 */
2961#ifdef __ENABLE_PRINTF128
2962 if( (fmt[0] == '1') && (fmt[1] == '2') && (fmt[2] == '8')){
2963 length = PFORMAT_LENGTH_LLONG128;
2964 fmt += 3;
2965 } else
2966#endif
2967 if( (fmt[0] == '6') && (fmt[1] == '4') )
2968 {
2969 /* I64' instead of `ll',
2970 * when referring to `long long' integer types...
2971 */
2972 length = PFORMAT_LENGTH_LLONG;
2973 fmt += 2;
2974 } else
2975 if( (fmt[0] == '3') && (fmt[1] == '2') )
2976 {
2977 /* and `I32' instead of `l',
2978 * when referring to `long' integer types...
2979 */
2980 length = PFORMAT_LENGTH_LONG;
2981 fmt += 2;
2982 }
2983
2984 else
2985 /* or unqualified `I' instead of `t' or `z',
2986 * when referring to `ptrdiff_t' or `size_t' entities;
2987 * (we will choose to map it to `ptrdiff_t').
2988 */
2989 length = __pformat_arg_length( ptrdiff_t );
2990
2991 state = PFORMAT_END;
2992 break;
2993
2994# endif
2995
2996#ifdef __ENABLE_DFP
2997 case 'H':
2998 stream.flags |= PFORMAT_DECIM32;
2999 state = PFORMAT_END;
3000 break;
3001
3002 case 'D':
3003 /*
3004 * Interpret the argument as explicitly of a
3005 * `_Decimal64' or `_Decimal128' data type.
3006 */
3007 if( *fmt == 'D' )
3008 {
3009 /* Modifier is `DD'; data type is `_Decimal128' sized...
3010 * Skip the second `D', and set length accordingly.
3011 */
3012 ++fmt;
3013 stream.flags |= PFORMAT_DECIM128;
3014 }
3015
3016 else
3017 /* Modifier is `D'; data type is `_Decimal64' sized...
3018 */
3019 stream.flags |= PFORMAT_DECIM64;
3020
3021 state = PFORMAT_END;
3022 break;
3023#endif /* __ENABLE_DFP */
3024 case 'l':
3025 /*
3026 * Interpret the argument as explicitly of a
3027 * `long' or `long long' data type.
3028 */
3029 if( *fmt == 'l' )
3030 {
3031 /* Modifier is `ll'; data type is `long long' sized...
3032 * Skip the second `l', and set length accordingly.
3033 */
3034 ++fmt;
3035 length = PFORMAT_LENGTH_LLONG;
3036 }
3037
3038 else
3039 /* Modifier is `l'; data type is `long' sized...
3040 */
3041 length = PFORMAT_LENGTH_LONG;
3042
3043 state = PFORMAT_END;
3044 break;
3045
3046 case 'L':
3047 /*
3048 * Identify the appropriate argument as a `long double',
3049 * when associated with `%a', `%A', `%e', `%E', `%f', `%F',
3050 * `%g' or `%G' format specifications.
3051 */
3052 stream.flags |= PFORMAT_LDOUBLE;
3053 state = PFORMAT_END;
3054 break;
3055
3056 case 't':
3057 /*
3058 * Interpret the argument as being of the same size as
3059 * a `ptrdiff_t' entity...
3060 */
3061 length = __pformat_arg_length( ptrdiff_t );
3062 state = PFORMAT_END;
3063 break;
3064
3065 case 'z':
3066 /*
3067 * Interpret the argument as being of the same size as
3068 * a `size_t' entity...
3069 */
3070 length = __pformat_arg_length( size_t );
3071 state = PFORMAT_END;
3072 break;
3073
3074 /* Precision indicator...
3075 * May appear once only; it must precede any modifier
3076 * for argument length, or any data type specifier.
3077 */
3078 case '.':
3079 if( state < PFORMAT_GET_PRECISION )
3080 {
3081 /* We haven't seen a precision specification yet,
3082 * so initialise it to zero, (in case no digits follow),
3083 * and accept any following digits as the precision.
3084 */
3085 stream.precision = 0;
3086 width_spec = &stream.precision;
3087 state = PFORMAT_GET_PRECISION;
3088 }
3089
3090 else
3091 /* We've already seen a precision specification,
3092 * so this is just junk; proceed to end game.
3093 */
3094 state = PFORMAT_END;
3095
3096 /* Either way, we must not fall through here.
3097 */
3098 break;
3099
3100 /* Variable field width, or precision specification,
3101 * derived from the argument list...
3102 */
3103 case '*':
3104 /*
3105 * When this appears...
3106 */
3107 if( width_spec
3108 && ((state == PFORMAT_INIT) || (state == PFORMAT_GET_PRECISION)) )
3109 {
3110 /* in proper context; assign to field width
3111 * or precision, as appropriate.
3112 */
3113 if( (*width_spec = va_arg( argv, int )) < 0 )
3114 {
3115 /* Assigned value was negative...
3116 */
3117 if( state == PFORMAT_INIT )
3118 {
3119 /* For field width, this is equivalent to
3120 * a positive value with the `-' flag...
3121 */
3122 stream.flags |= PFORMAT_LJUSTIFY;
3123 stream.width = -stream.width;
3124 }
3125
3126 else
3127 /* while as a precision specification,
3128 * it should simply be ignored.
3129 */
3130 stream.precision = PFORMAT_IGNORE;
3131 }
3132 }
3133
3134 else
3135 /* out of context; give up on width and precision
3136 * specifications for this conversion.
3137 */
3138 state = PFORMAT_END;
3139
3140 /* Mark as processed...
3141 * we must not see `*' again, in this context.
3142 */
3143 width_spec = NULL;
3144 break;
3145
3146 /* Formatting flags...
3147 * Must appear while in the PFORMAT_INIT state,
3148 * and are non-terminal, so again, end with `break'.
3149 */
3150 case '#':
3151 /*
3152 * Select alternate PFORMAT_HASHED output style.
3153 */
3154 if( state == PFORMAT_INIT )
3155 stream.flags |= PFORMAT_HASHED;
3156 break;
3157
3158 case '+':
3159 /*
3160 * Print a leading sign with numeric output,
3161 * for both positive and negative values.
3162 */
3163 if( state == PFORMAT_INIT )
3164 stream.flags |= PFORMAT_POSITIVE;
3165 break;
3166
3167 case '-':
3168 /*
3169 * Select left justification of displayed output
3170 * data, within the output field width, instead of
3171 * the default flush right justification.
3172 */
3173 if( state == PFORMAT_INIT )
3174 stream.flags |= PFORMAT_LJUSTIFY;
3175 break;
3176
3177 case '\'':
3178 /*
3179 * This is an XSI extension to the POSIX standard,
3180 * which we do not support, at present.
3181 */
3182 if (state == PFORMAT_INIT)
3183 {
3184 stream.flags |= PFORMAT_GROUPED; /* $$$$ */
3185 int len; wchar_t rpchr; mbstate_t cstate;
3186 memset (&cstate, 0, sizeof(state));
3187 if ((len = mbrtowc( &rpchr, localeconv()->thousands_sep, 16, &cstate)) > 0)
3188 stream.thousands_chr = rpchr;
3189 stream.thousands_chr_len = len;
3190 }
3191 break;
3192
3193 case '\x20':
3194 /*
3195 * Reserve a single space, within the output field,
3196 * for display of the sign of signed data; this will
3197 * be occupied by the minus sign, if the data value
3198 * is negative, or by a plus sign if the data value
3199 * is positive AND the `+' flag is also present, or
3200 * by a space otherwise. (Technically, this flag
3201 * is redundant, if the `+' flag is present).
3202 */
3203 if( state == PFORMAT_INIT )
3204 stream.flags |= PFORMAT_ADDSPACE;
3205 break;
3206
3207 case '0':
3208 /*
3209 * May represent a flag, to activate the `pad with zeros'
3210 * option, or it may simply be a digit in a width or in a
3211 * precision specification...
3212 */
3213 if( state == PFORMAT_INIT )
3214 {
3215 /* This is the flag usage...
3216 */
3217 stream.flags |= PFORMAT_ZEROFILL;
3218 break;
3219 }
3220
3221 /* fallthrough */
3222
3223 default:
3224 /*
3225 * If we didn't match anything above, then we will check
3226 * for digits, which we may accumulate to generate field
3227 * width or precision specifications...
3228 */
3229 if( (state < PFORMAT_END) && ('9' >= c) && (c >= '0') )
3230 {
3231 if( state == PFORMAT_INIT )
3232 /*
3233 * Initial digits explicitly relate to field width...
3234 */
3235 state = PFORMAT_SET_WIDTH;
3236
3237 else if( state == PFORMAT_GET_PRECISION )
3238 /*
3239 * while those following a precision indicator
3240 * explicitly relate to precision.
3241 */
3242 state = PFORMAT_SET_PRECISION;
3243
3244 if( width_spec )
3245 {
3246 /* We are accepting a width or precision specification...
3247 */
3248 if( *width_spec < 0 )
3249 /*
3250 * and accumulation hasn't started yet; we simply
3251 * initialise the accumulator with the current digit
3252 * value, converting from ASCII to decimal.
3253 */
3254 *width_spec = c - '0';
3255
3256 else
3257 /* Accumulation has already started; we perform a
3258 * `leftwise decimal digit shift' on the accumulator,
3259 * (i.e. multiply it by ten), then add the decimal
3260 * equivalent value of the current digit.
3261 */
3262 *width_spec = *width_spec * 10 + c - '0';
3263 }
3264 }
3265
3266 else
3267 {
3268 /* We found a digit out of context, or some other character
3269 * with no designated meaning; reject this format specification,
3270 * backtrack, and emit it as literal text...
3271 */
3272 fmt = backtrack;
3273 #ifndef __BUILD_WIDEAPI
3274 __pformat_putc( '%', &stream );
3275 #else
3276 stream.width = stream.precision = PFORMAT_IGNORE;
3277 __pformat_wputchars( L"%", 1, &stream );
3278 #endif
3279 goto format_scan;
3280 }
3281 }
3282 }
3283 }
3284
3285 else
3286 /* We just parsed a character which is not included within any format
3287 * specification; we simply emit it as a literal.
3288 */
3289 #ifndef __BUILD_WIDEAPI
3290 __pformat_putc( c, &stream );
3291 #else
3292 if (literal_string_start == NULL)
3293 literal_string_start = fmt - 1;
3294 #endif
3295 }
3296
3297 /* When we have fully dispatched the format string, the return value is the
3298 * total number of bytes we transferred to the output destination.
3299 */
3300#ifdef __BUILD_WIDEAPI
3301 if (literal_string_start)
3302 {
3303 stream.width = stream.precision = PFORMAT_IGNORE;
3304 __pformat_wputchars( literal_string_start, fmt - literal_string_start - 1, &stream );
3305 }
3306#endif
3307
3308 return stream.count;
3309}
3310
3311/* $RCSfile: pformat.c,v $Revision: 1.9 $: end of file */
3312
lib/libc/mingw/stdio/mingw_pformat.h created+99
......@@ -0,0 +1,99 @@
1#ifndef PFORMAT_H
2/*
3 * pformat.h
4 *
5 * $Id: pformat.h,v 1.1 2008/07/28 23:24:20 keithmarshall Exp $
6 *
7 * A private header, defining the `pformat' API; it is to be included
8 * in each compilation unit implementing any of the `printf' family of
9 * functions, but serves no useful purpose elsewhere.
10 *
11 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
12 *
13 * This is free software. You may redistribute and/or modify it as you
14 * see fit, without restriction of copyright.
15 *
16 * This software is provided "as is", in the hope that it may be useful,
17 * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
18 * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE. At no
19 * time will the author accept any form of liability for any damages,
20 * however caused, resulting from the use of this software.
21 */
22#define PFORMAT_H
23
24/* The following macros reproduce definitions from _mingw.h,
25 * so that compilation will not choke, if using any compiler
26 * other than the MinGW implementation of GCC.
27 */
28#ifndef __cdecl
29# ifdef __GNUC__
30# define __cdecl __attribute__((__cdecl__))
31# else
32# define __cdecl
33# endif
34#endif
35
36#ifndef __MINGW_GNUC_PREREQ
37# if defined __GNUC__ && defined __GNUC_MINOR__
38# define __MINGW_GNUC_PREREQ( major, minor )\
39 (__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))
40# else
41# define __MINGW_GNUC_PREREQ( major, minor )
42# endif
43#endif
44
45#ifndef __MINGW_NOTHROW
46# if __MINGW_GNUC_PREREQ( 3, 3 )
47# define __MINGW_NOTHROW __attribute__((__nothrow__))
48# else
49# define __MINGW_NOTHROW
50# endif
51#endif
52
53#ifdef __BUILD_WIDEAPI
54#define APICHAR wchar_t
55#else
56#define APICHAR char
57#endif
58
59/* The following are the declarations specific to the `pformat' API...
60 */
61#define PFORMAT_TO_FILE 0x2000
62#define PFORMAT_NOLIMIT 0x4000
63
64#if defined(__MINGW32__) || defined(__MINGW64__)
65 /*
66 * Map MinGW specific function names, for use in place of the generic
67 * implementation defined equivalent function names.
68 */
69#ifdef __BUILD_WIDEAPI
70# define __pformat __mingw_wpformat
71#define __fputc(X,STR) fputwc((wchar_t) (X), (STR))
72
73# define __printf __mingw_wprintf
74# define __fprintf __mingw_fwprintf
75# define __sprintf __mingw_swprintf
76# define __snprintf __mingw_snwprintf
77
78# define __vprintf __mingw_vwprintf
79# define __vfprintf __mingw_vfwprintf
80# define __vsprintf __mingw_vswprintf
81# define __vsnprintf __mingw_vsnwprintf
82#else
83# define __pformat __mingw_pformat
84#define __fputc(X,STR) fputc((X), (STR))
85
86# define __printf __mingw_printf
87# define __fprintf __mingw_fprintf
88# define __sprintf __mingw_sprintf
89# define __snprintf __mingw_snprintf
90
91# define __vprintf __mingw_vprintf
92# define __vfprintf __mingw_vfprintf
93# define __vsprintf __mingw_vsprintf
94# define __vsnprintf __mingw_vsnprintf
95#endif /* __BUILD_WIDEAPI */
96#endif
97
98int __cdecl __pformat(int, void *, int, const APICHAR *, va_list) __MINGW_NOTHROW;
99#endif /* !defined PFORMAT_H */
lib/libc/mingw/stdio/mingw_pformatw.c created+9
......@@ -0,0 +1,9 @@
1/**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the mingw-w64 runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6#define __BUILD_WIDEAPI 1
7
8#include "mingw_pformat.c"
9
lib/libc/mingw/stdio/mingw_printf.c created+59
......@@ -0,0 +1,59 @@
1/* printf.c
2 *
3 * $Id: printf.c,v 1.1 2008/08/11 22:41:55 keithmarshall Exp $
4 *
5 * Provides an implementation of the "printf" function, conforming
6 * generally to C99 and SUSv3/POSIX specifications, with extensions
7 * to support Microsoft's non-standard format specifications. This
8 * is included in libmingwex.a, whence it may replace the Microsoft
9 * function of the same name.
10 *
11 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
12 *
13 * This implementation of "printf" will normally be invoked by calling
14 * "__mingw_printf()" in preference to a direct reference to "printf()"
15 * itself; this leaves the MSVCRT implementation as the default, which
16 * will be deployed when user code invokes "print()". Users who then
17 * wish to use this implementation may either call "__mingw_printf()"
18 * directly, or may use conditional preprocessor defines, to redirect
19 * references to "printf()" to "__mingw_printf()".
20 *
21 * Compiling this module with "-D INSTALL_AS_DEFAULT" will change this
22 * recommended convention, such that references to "printf()" in user
23 * code will ALWAYS be redirected to "__mingw_printf()"; if this option
24 * is adopted, then users wishing to use the MSVCRT implementation of
25 * "printf()" will be forced to use a "back-door" mechanism to do so.
26 * Such a "back-door" mechanism is provided with MinGW, allowing the
27 * MSVCRT implementation to be called as "__msvcrt_printf()"; however,
28 * since users may not expect this behaviour, a standard libmingwex.a
29 * installation does not employ this option.
30 *
31 *
32 * This is free software. You may redistribute and/or modify it as you
33 * see fit, without restriction of copyright.
34 *
35 * This software is provided "as is", in the hope that it may be useful,
36 * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
37 * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE. At no
38 * time will the author accept any form of liability for any damages,
39 * however caused, resulting from the use of this software.
40 *
41 */
42#include <stdio.h>
43#include <stdarg.h>
44
45#include "mingw_pformat.h"
46
47int __cdecl __printf(const APICHAR *, ...) __MINGW_NOTHROW;
48
49int __cdecl __printf(const APICHAR *fmt, ...)
50{
51 register int retval;
52 va_list argv; va_start( argv, fmt );
53 _lock_file( stdout );
54 retval = __pformat( PFORMAT_TO_FILE | PFORMAT_NOLIMIT, stdout, 0, fmt, argv );
55 _unlock_file( stdout );
56 va_end( argv );
57 return retval;
58}
59
lib/libc/mingw/stdio/mingw_printfw.c created+9
......@@ -0,0 +1,9 @@
1/**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the mingw-w64 runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6#define __BUILD_WIDEAPI 1
7
8#include "mingw_printf.c"
9
lib/libc/mingw/stdio/mingw_scanf.c created+28
......@@ -0,0 +1,28 @@
1#include <stdarg.h>
2#include <stdio.h>
3#include <stdlib.h>
4
5extern int __mingw_vfscanf (FILE *stream, const char *format, va_list argp);
6
7int __mingw_scanf (const char *format, ...);
8int __mingw_vscanf (const char *format, va_list argp);
9
10int
11__mingw_scanf (const char *format, ...)
12{
13 va_list argp;
14 int r;
15
16 va_start (argp, format);
17 r = __mingw_vfscanf (stdin, format, argp);
18 va_end (argp);
19
20 return r;
21}
22
23int
24__mingw_vscanf (const char *format, va_list argp)
25{
26 return __mingw_vfscanf (stdin, format, argp);
27}
28
lib/libc/mingw/stdio/mingw_snprintf.c created+40
......@@ -0,0 +1,40 @@
1/* snprintf.c
2 *
3 * $Id: snprintf.c,v 1.3 2008/07/28 23:24:20 keithmarshall Exp $
4 *
5 * Provides an implementation of the "snprintf" function, conforming
6 * generally to C99 and SUSv3/POSIX specifications, with extensions
7 * to support Microsoft's non-standard format specifications. This
8 * is included in libmingwex.a, replacing the redirection through
9 * libmoldnames.a, to the MSVCRT standard "_snprintf" function; (the
10 * standard MSVCRT function remains available, and may be invoked
11 * directly, using this fully qualified form of its name).
12 *
13 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
14 *
15 * This is free software. You may redistribute and/or modify it as you
16 * see fit, without restriction of copyright.
17 *
18 * This software is provided "as is", in the hope that it may be useful,
19 * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
20 * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE. At no
21 * time will the author accept any form of liability for any damages,
22 * however caused, resulting from the use of this software.
23 *
24 */
25
26#include <stdio.h>
27#include <stdarg.h>
28
29#include "mingw_pformat.h"
30
31int __cdecl __snprintf (APICHAR *, size_t, const APICHAR *fmt, ...) __MINGW_NOTHROW;
32int __cdecl __vsnprintf (APICHAR *, size_t, const APICHAR *fmt, va_list) __MINGW_NOTHROW;
33
34int __cdecl __snprintf(APICHAR *buf, size_t length, const APICHAR *fmt, ...)
35{
36 va_list argv; va_start( argv, fmt );
37 register int retval = __vsnprintf( buf, length, fmt, argv );
38 va_end( argv );
39 return retval;
40}
lib/libc/mingw/stdio/mingw_snprintfw.c created+9
......@@ -0,0 +1,9 @@
1/**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the mingw-w64 runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6#define __BUILD_WIDEAPI 1
7
8#include "mingw_snprintf.c"
9
lib/libc/mingw/stdio/mingw_sprintf.c created+56
......@@ -0,0 +1,56 @@
1/* sprintf.c
2 *
3 * $Id: sprintf.c,v 1.1 2008/08/11 22:41:55 keithmarshall Exp $
4 *
5 * Provides an implementation of the "sprintf" function, conforming
6 * generally to C99 and SUSv3/POSIX specifications, with extensions
7 * to support Microsoft's non-standard format specifications. This
8 * is included in libmingwex.a, whence it may replace the Microsoft
9 * function of the same name.
10 *
11 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
12 *
13 * This implementation of "sprintf" will normally be invoked by calling
14 * "__mingw_sprintf()" in preference to a direct reference to "sprintf()"
15 * itself; this leaves the MSVCRT implementation as the default, which
16 * will be deployed when user code invokes "sprint()". Users who then
17 * wish to use this implementation may either call "__mingw_sprintf()"
18 * directly, or may use conditional preprocessor defines, to redirect
19 * references to "sprintf()" to "__mingw_sprintf()".
20 *
21 * Compiling this module with "-D INSTALL_AS_DEFAULT" will change this
22 * recommended convention, such that references to "sprintf()" in user
23 * code will ALWAYS be redirected to "__mingw_sprintf()"; if this option
24 * is adopted, then users wishing to use the MSVCRT implementation of
25 * "sprintf()" will be forced to use a "back-door" mechanism to do so.
26 * Such a "back-door" mechanism is provided with MinGW, allowing the
27 * MSVCRT implementation to be called as "__msvcrt_sprintf()"; however,
28 * since users may not expect this behaviour, a standard libmingwex.a
29 * installation does not employ this option.
30 *
31 *
32 * This is free software. You may redistribute and/or modify it as you
33 * see fit, without restriction of copyright.
34 *
35 * This software is provided "as is", in the hope that it may be useful,
36 * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
37 * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE. At no
38 * time will the author accept any form of liability for any damages,
39 * however caused, resulting from the use of this software.
40 *
41 */
42#include <stdio.h>
43#include <stdarg.h>
44
45#include "mingw_pformat.h"
46
47int __cdecl __sprintf (APICHAR *, const APICHAR *, ...) __MINGW_NOTHROW;
48
49int __cdecl __sprintf(APICHAR *buf, const APICHAR *fmt, ...)
50{
51 register int retval;
52 va_list argv; va_start( argv, fmt );
53 buf[retval = __pformat( PFORMAT_NOLIMIT, buf, 0, fmt, argv )] = '\0';
54 va_end( argv );
55 return retval;
56}
lib/libc/mingw/stdio/mingw_sprintfw.c created+10
......@@ -0,0 +1,10 @@
1/**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the mingw-w64 runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6#define __BUILD_WIDEAPI 1
7#define _CRT_NON_CONFORMING_SWPRINTFS 1
8
9#include "mingw_sprintf.c"
10
lib/libc/mingw/stdio/mingw_sscanf.c created+20
......@@ -0,0 +1,20 @@
1#include <stdarg.h>
2#include <stdlib.h>
3
4extern int __mingw_vsscanf (const char *buf, const char *format, va_list argp);
5
6int __mingw_sscanf (const char *buf, const char *format, ...);
7
8int
9__mingw_sscanf (const char *buf, const char *format, ...)
10{
11 va_list argp;
12 int r;
13
14 va_start (argp, format);
15 r = __mingw_vsscanf (buf, format, argp);
16 va_end (argp);
17
18 return r;
19}
20
lib/libc/mingw/stdio/mingw_swscanf.c created+20
......@@ -0,0 +1,20 @@
1#include <stdarg.h>
2#include <stdlib.h>
3
4extern int __mingw_vswscanf (const wchar_t *buf, const wchar_t *format, va_list argp);
5
6int __mingw_swscanf (const wchar_t *buf, const wchar_t *format, ...);
7
8int
9__mingw_swscanf (const wchar_t *buf, const wchar_t *format, ...)
10{
11 va_list argp;
12 int r;
13
14 va_start (argp, format);
15 r = __mingw_vswscanf (buf, format, argp);
16 va_end (argp);
17
18 return r;
19}
20
lib/libc/mingw/stdio/mingw_vasprintf.c created+25
......@@ -0,0 +1,25 @@
1#define _GNU_SOURCE
2#define __CRT__NO_INLINE
3
4#include <stdio.h>
5#include <stdlib.h>
6#include <stdarg.h>
7
8int __mingw_vasprintf(char ** __restrict__ ret,
9 const char * __restrict__ format,
10 va_list ap) {
11 int len;
12 /* Get Length */
13 len = __mingw_vsnprintf(NULL,0,format,ap);
14 if (len < 0) return -1;
15 /* +1 for \0 terminator. */
16 *ret = malloc(len + 1);
17 /* Check malloc fail*/
18 if (!*ret) return -1;
19 /* Write String */
20 __mingw_vsnprintf(*ret,len+1,format,ap);
21 /* Terminate explicitly */
22 (*ret)[len] = '\0';
23 return len;
24}
25
lib/libc/mingw/stdio/mingw_vfprintf.c created+58
......@@ -0,0 +1,58 @@
1/* vfprintf.c
2 *
3 * $Id: vfprintf.c,v 1.1 2008/08/11 22:41:55 keithmarshall Exp $
4 *
5 * Provides an implementation of the "vfprintf" function, conforming
6 * generally to C99 and SUSv3/POSIX specifications, with extensions
7 * to support Microsoft's non-standard format specifications. This
8 * is included in libmingwex.a, whence it may replace the Microsoft
9 * function of the same name.
10 *
11 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
12 *
13 * This implementation of "vfprintf" will normally be invoked by calling
14 * "__mingw_vfprintf()" in preference to a direct reference to "vfprintf()"
15 * itself; this leaves the MSVCRT implementation as the default, which
16 * will be deployed when user code invokes "vfprint()". Users who then
17 * wish to use this implementation may either call "__mingw_vfprintf()"
18 * directly, or may use conditional preprocessor defines, to redirect
19 * references to "vfprintf()" to "__mingw_vfprintf()".
20 *
21 * Compiling this module with "-D INSTALL_AS_DEFAULT" will change this
22 * recommended convention, such that references to "vfprintf()" in user
23 * code will ALWAYS be redirected to "__mingw_vfprintf()"; if this option
24 * is adopted, then users wishing to use the MSVCRT implementation of
25 * "vfprintf()" will be forced to use a "back-door" mechanism to do so.
26 * Such a "back-door" mechanism is provided with MinGW, allowing the
27 * MSVCRT implementation to be called as "__msvcrt_vfprintf()"; however,
28 * since users may not expect this behaviour, a standard libmingwex.a
29 * installation does not employ this option.
30 *
31 *
32 * This is free software. You may redistribute and/or modify it as you
33 * see fit, without restriction of copyright.
34 *
35 * This software is provided "as is", in the hope that it may be useful,
36 * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
37 * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE. At no
38 * time will the author accept any form of liability for any damages,
39 * however caused, resulting from the use of this software.
40 *
41 */
42#include <stdio.h>
43#include <stdarg.h>
44
45#include "mingw_pformat.h"
46
47int __cdecl __vfprintf (FILE *, const APICHAR *, va_list) __MINGW_NOTHROW;
48
49int __cdecl __vfprintf(FILE *stream, const APICHAR *fmt, va_list argv)
50{
51 register int retval;
52
53 _lock_file( stream );
54 retval = __pformat( PFORMAT_TO_FILE | PFORMAT_NOLIMIT, stream, 0, fmt, argv );
55 _unlock_file( stream );
56
57 return retval;
58}
lib/libc/mingw/stdio/mingw_vfprintfw.c created+9
......@@ -0,0 +1,9 @@
1/**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the mingw-w64 runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6#define __BUILD_WIDEAPI 1
7
8#include "mingw_vfprintf.c"
9
lib/libc/mingw/stdio/mingw_vfscanf.c created+1632
......@@ -0,0 +1,1632 @@
1/*
2 This Software is provided under the Zope Public License (ZPL) Version 2.1.
3
4 Copyright (c) 2011 by the mingw-w64 project
5
6 See the AUTHORS file for the list of contributors to the mingw-w64 project.
7
8 This license has been certified as open source. It has also been designated
9 as GPL compatible by the Free Software Foundation (FSF).
10
11 Redistribution and use in source and binary forms, with or without
12 modification, are permitted provided that the following conditions are met:
13
14 1. Redistributions in source code must retain the accompanying copyright
15 notice, this list of conditions, and the following disclaimer.
16 2. Redistributions in binary form must reproduce the accompanying
17 copyright notice, this list of conditions, and the following disclaimer
18 in the documentation and/or other materials provided with the
19 distribution.
20 3. Names of the copyright holders must not be used to endorse or promote
21 products derived from this software without prior written permission
22 from the copyright holders.
23 4. The right to distribute this software or to use it for any purpose does
24 not give you the right to use Servicemarks (sm) or Trademarks (tm) of
25 the copyright holders. Use of them is covered by separate agreement
26 with the copyright holders.
27 5. If any files are modified, you must cause the modified files to carry
28 prominent notices stating that you changed the files and the date of
29 any change.
30
31 Disclaimer
32
33 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
34 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
36 EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
37 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
38 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
39 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
40 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
41 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
42 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43*/
44
45#define __LARGE_MBSTATE_T
46
47#include <limits.h>
48#include <stddef.h>
49#include <stdarg.h>
50#include <stdio.h>
51#include <stdint.h>
52#include <stdlib.h>
53#include <string.h>
54#include <wchar.h>
55#include <ctype.h>
56#include <wctype.h>
57#include <locale.h>
58#include <errno.h>
59
60/* Helper flags for conversion. */
61#define IS_C 0x0001
62#define IS_S 0x0002
63#define IS_L 0x0004
64#define IS_LL 0x0008
65#define IS_SIGNED_NUM 0x0010
66#define IS_POINTER 0x0020
67#define IS_HEX_FLOAT 0x0040
68#define IS_SUPPRESSED 0x0080
69#define USE_GROUP 0x0100
70#define USE_GNU_ALLOC 0x0200
71#define USE_POSIX_ALLOC 0x0400
72
73#define IS_ALLOC_USED (USE_GNU_ALLOC | USE_POSIX_ALLOC)
74
75/* internal stream structure with back-buffer. */
76typedef struct _IFP
77{
78 __extension__ union {
79 void *fp;
80 const char *str;
81 };
82 int bch[1024];
83 unsigned int is_string : 1;
84 int back_top;
85 unsigned int seen_eof : 1;
86} _IFP;
87
88static void *
89get_va_nth (va_list argp, unsigned int n)
90{
91 va_list ap;
92 if (!n) abort ();
93 va_copy (ap, argp);
94 while (--n > 0)
95 (void) va_arg(ap, void *);
96 return va_arg (ap, void *);
97}
98
99static void
100optimize_alloc (char **p, char *end, size_t alloc_sz)
101{
102 size_t need_sz;
103 char *h;
104
105 if (!p || !*p)
106 return;
107
108 need_sz = end - *p;
109 if (need_sz == alloc_sz)
110 return;
111
112 if ((h = (char *) realloc (*p, need_sz)) != NULL)
113 *p = h;
114}
115
116static void
117back_ch (int c, _IFP *s, size_t *rin, int not_eof)
118{
119 if (!not_eof && c == EOF)
120 return;
121 if (s->is_string == 0)
122 {
123 FILE *fp = s->fp;
124 ungetc (c, fp);
125 rin[0] -= 1;
126 return;
127 }
128 rin[0] -= 1;
129 s->bch[s->back_top] = c;
130 s->back_top += 1;
131}
132
133static int
134in_ch (_IFP *s, size_t *rin)
135{
136 int r;
137 if (s->back_top)
138 {
139 s->back_top -= 1;
140 r = s->bch[s->back_top];
141 rin[0] += 1;
142 }
143 else if (s->seen_eof)
144 {
145 return EOF;
146 }
147 else if (s->is_string)
148 {
149 const char *ps = s->str;
150 r = ((int) *ps) & 0xff;
151 ps++;
152 if (r != 0)
153 {
154 rin[0] += 1;
155 s->str = ps;
156 return r;
157 }
158 s->seen_eof = 1;
159 return EOF;
160 }
161 else
162 {
163 FILE *fp = (FILE *) s->fp;
164 r = getc (fp);
165 if (r != EOF)
166 rin[0] += 1;
167 else s->seen_eof = 1;
168 }
169 return r;
170}
171
172static int
173match_string (_IFP *s, size_t *rin, int *c, const char *str)
174{
175 int ch = *c;
176
177 if (*str == 0)
178 return 1;
179
180 if (*str != (char) tolower (ch))
181 return 0;
182 ++str;
183 while (*str != 0)
184 {
185 if ((ch = in_ch (s, rin)) == EOF)
186 {
187 c[0] = ch;
188 return 0;
189 }
190
191 if (*str != (char) tolower (ch))
192 {
193 c[0] = ch;
194 return 0;
195 }
196 ++str;
197 }
198 c[0] = ch;
199 return 1;
200}
201
202struct gcollect
203{
204 size_t count;
205 struct gcollect *next;
206 char **ptrs[32];
207};
208
209static void
210release_ptrs (struct gcollect **pt, char **wbuf)
211{
212 struct gcollect *pf;
213 size_t cnt;
214
215 if (wbuf)
216 {
217 free (*wbuf);
218 *wbuf = NULL;
219 }
220 if (!pt || (pf = *pt) == NULL)
221 return;
222 while (pf != NULL)
223 {
224 struct gcollect *pf_sv = pf;
225 for (cnt = 0; cnt < pf->count; ++cnt)
226 {
227 free (*pf->ptrs[cnt]);
228 *pf->ptrs[cnt] = NULL;
229 }
230 pf = pf->next;
231 free (pf_sv);
232 }
233 *pt = NULL;
234}
235
236static int
237cleanup_return (int rval, struct gcollect **pfree, char **strp, char **wbuf)
238{
239 if (rval == EOF)
240 release_ptrs (pfree, wbuf);
241 else
242 {
243 if (pfree)
244 {
245 struct gcollect *pf = *pfree, *pf_sv;
246 while (pf != NULL)
247 {
248 pf_sv = pf;
249 pf = pf->next;
250 free (pf_sv);
251 }
252 *pfree = NULL;
253 }
254 if (strp != NULL)
255 {
256 free (*strp);
257 *strp = NULL;
258 }
259 if (wbuf)
260 {
261 free (*wbuf);
262 *wbuf = NULL;
263 }
264 }
265 return rval;
266}
267
268static struct gcollect *
269resize_gcollect (struct gcollect *pf)
270{
271 struct gcollect *np;
272 if (pf && pf->count < 32)
273 return pf;
274 np = malloc (sizeof (struct gcollect));
275 np->count = 0;
276 np->next = pf;
277 return np;
278}
279
280static char *
281resize_wbuf (size_t wpsz, size_t *wbuf_max_sz, char *old)
282{
283 char *wbuf;
284 size_t nsz;
285 if (*wbuf_max_sz != wpsz)
286 return old;
287 nsz = (256 > (2 * wbuf_max_sz[0]) ? 256 : (2 * wbuf_max_sz[0]));
288 if (!old)
289 wbuf = (char *) malloc (nsz);
290 else
291 wbuf = (char *) realloc (old, nsz);
292 if (!wbuf)
293 {
294 if (old)
295 free (old);
296 }
297 else
298 *wbuf_max_sz = nsz;
299 return wbuf;
300}
301
302static int
303__mingw_sformat (_IFP *s, const char *format, va_list argp)
304{
305 const char *f = format;
306 struct gcollect *gcollect = NULL;
307 size_t read_in = 0, wbuf_max_sz = 0, cnt;
308 ssize_t str_sz = 0;
309 char *str = NULL, **pstr = NULL, *wbuf = NULL;
310 wchar_t *wstr = NULL;
311 int rval = 0, c = 0, ignore_ws = 0;
312 va_list arg;
313 unsigned char fc;
314 unsigned int npos;
315 int width, flags, base = 0, errno_sv;
316 size_t wbuf_cur_sz, read_in_sv, new_sz, n;
317 char seen_dot, seen_exp, is_neg, not_in;
318 char *tmp_wbuf_ptr, buf[MB_LEN_MAX];
319 const char *lc_decimal_point, *lc_thousands_sep;
320 mbstate_t state, cstate;
321 union {
322 unsigned long long ull;
323 unsigned long ul;
324 long long ll;
325 long l;
326 } cv_val;
327
328 arg = argp;
329
330 if (!s || s->fp == NULL || !format)
331 {
332 errno = EINVAL;
333 return EOF;
334 }
335
336 memset (&state, 0, sizeof (state));
337
338 lc_decimal_point = localeconv()->decimal_point;
339 lc_thousands_sep = localeconv()->thousands_sep;
340 if (lc_thousands_sep != NULL && *lc_thousands_sep == 0)
341 lc_thousands_sep = NULL;
342
343 while (*f != 0)
344 {
345 if (!isascii ((unsigned char) *f))
346 {
347 int len;
348
349 if ((len = mbrlen (f, strlen (f), &state)) > 0)
350 {
351 do
352 {
353 if ((c = in_ch (s, &read_in)) == EOF || c != (unsigned char) *f++)
354 {
355 back_ch (c, s, &read_in, 1);
356 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
357 }
358 }
359 while (--len > 0);
360
361 continue;
362 }
363 }
364
365 fc = *f++;
366 if (fc != '%')
367 {
368 if (isspace (fc))
369 ignore_ws = 1;
370 else
371 {
372 if ((c = in_ch (s, &read_in)) == EOF)
373 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
374
375 if (ignore_ws)
376 {
377 ignore_ws = 0;
378 if (isspace (c))
379 {
380 do
381 {
382 if ((c = in_ch (s, &read_in)) == EOF)
383 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
384 }
385 while (isspace (c));
386 }
387 }
388
389 if (c != fc)
390 {
391 back_ch (c, s, &read_in, 0);
392 return cleanup_return (rval, &gcollect, pstr, &wbuf);
393 }
394 }
395
396 continue;
397 }
398
399 width = flags = 0;
400 npos = 0;
401 wbuf_cur_sz = 0;
402
403 if (isdigit ((unsigned char) *f))
404 {
405 const char *svf = f;
406 npos = (unsigned char) *f++ - '0';
407 while (isdigit ((unsigned char) *f))
408 npos = npos * 10 + ((unsigned char) *f++ - '0');
409 if (*f != '$')
410 {
411 npos = 0;
412 f = svf;
413 }
414 else
415 f++;
416 }
417
418 do
419 {
420 if (*f == '*')
421 flags |= IS_SUPPRESSED;
422 else if (*f == '\'')
423 {
424 if (lc_thousands_sep)
425 flags |= USE_GROUP;
426 }
427 else if (*f == 'I')
428 {
429 /* we don't support locale's digits (i18N), but ignore it for now silently. */
430 ;
431#ifdef _WIN32
432 if (f[1] == '6' && f[2] == '4')
433 {
434 flags |= IS_LL | IS_L;
435 f += 2;
436 }
437 else if (f[1] == '3' && f[2] == '2')
438 {
439 flags |= IS_L;
440 f += 2;
441 }
442 else
443 {
444#ifdef _WIN64
445 flags |= IS_LL | IS_L;
446#else
447 flags |= IS_L;
448#endif
449 }
450#endif
451 }
452 else
453 break;
454 ++f;
455 }
456 while (1);
457
458 while (isdigit ((unsigned char) *f))
459 width = width * 10 + ((unsigned char) *f++ - '0');
460
461 if (!width)
462 width = -1;
463
464 switch (*f)
465 {
466 case 'h':
467 ++f;
468 flags |= (*f == 'h' ? IS_C : IS_S);
469 if (*f == 'h')
470 ++f;
471 break;
472 case 'l':
473 ++f;
474 flags |= (*f == 'l' ? IS_LL : 0) | IS_L;
475 if (*f == 'l')
476 ++f;
477 break;
478 case 'q': case 'L':
479 ++f;
480 flags |= IS_LL | IS_L;
481 break;
482 case 'a':
483 if (f[1] != 's' && f[1] != 'S' && f[1] != '[')
484 break;
485 ++f;
486 flags |= USE_GNU_ALLOC;
487 break;
488 case 'm':
489 flags |= USE_POSIX_ALLOC;
490 ++f;
491 if (*f == 'l')
492 {
493 flags |= IS_L;
494 f++;
495 }
496 break;
497 case 'z':
498#ifdef _WIN64
499 flags |= IS_LL | IS_L;
500#else
501 flags |= IS_L;
502#endif
503 ++f;
504 break;
505 case 'j':
506 if (sizeof (uintmax_t) > sizeof (unsigned long))
507 flags |= IS_LL;
508 else if (sizeof (uintmax_t) > sizeof (unsigned int))
509 flags |= IS_L;
510 ++f;
511 break;
512 case 't':
513#ifdef _WIN64
514 flags |= IS_LL;
515#else
516 flags |= IS_L;
517#endif
518 ++f;
519 break;
520 case 0:
521 return cleanup_return (rval, &gcollect, pstr, &wbuf);
522 default:
523 break;
524 }
525
526 if (*f == 0)
527 return cleanup_return (rval, &gcollect, pstr, &wbuf);
528
529 fc = *f++;
530 if (ignore_ws || (fc != '[' && fc != 'c' && fc != 'C' && fc != 'n'))
531 {
532 errno_sv = errno;
533 errno = 0;
534 do
535 {
536 if ((c == EOF || (c = in_ch (s, &read_in)) == EOF)
537 && errno == EINTR)
538 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
539 }
540 while (isspace (c));
541
542 ignore_ws = 0;
543 errno = errno_sv;
544 back_ch (c, s, &read_in, 0);
545 }
546
547 switch (fc)
548 {
549 case 'c':
550 if ((flags & IS_L) != 0)
551 fc = 'C';
552 break;
553 case 's':
554 if ((flags & IS_L) != 0)
555 fc = 'S';
556 break;
557 }
558
559 switch (fc)
560 {
561 case '%':
562 if ((c = in_ch (s, &read_in)) == EOF)
563 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
564 if (c != fc)
565 {
566 back_ch (c, s, &read_in, 1);
567 return cleanup_return (rval, &gcollect, pstr, &wbuf);
568 }
569 break;
570
571 case 'n':
572 if ((flags & IS_SUPPRESSED) == 0)
573 {
574 if ((flags & IS_LL) != 0)
575 *(npos != 0 ? (long long *) get_va_nth (argp, npos) : va_arg (arg, long long *)) = read_in;
576 else if ((flags & IS_L) != 0)
577 *(npos != 0 ? (long *) get_va_nth (argp, npos) : va_arg (arg, long *)) = read_in;
578 else if ((flags & IS_S) != 0)
579 *(npos != 0 ? (short *) get_va_nth (argp, npos) : va_arg (arg, short *)) = read_in;
580 else if ((flags & IS_C) != 0)
581 *(npos != 0 ? (char *) get_va_nth (argp, npos) : va_arg (arg, char *)) = read_in;
582 else
583 *(npos != 0 ? (int *) get_va_nth (argp, npos) : va_arg (arg, int *)) = read_in;
584 }
585 break;
586
587 case 'c':
588 if (width == -1)
589 width = 1;
590
591 if ((flags & IS_SUPPRESSED) == 0)
592 {
593 if ((flags & IS_ALLOC_USED) != 0)
594 {
595 if (npos != 0)
596 pstr = (char **) get_va_nth (argp, npos);
597 else
598 pstr = va_arg (arg, char **);
599
600 if (!pstr)
601 return cleanup_return (rval, &gcollect, pstr, &wbuf);
602
603 str_sz = (width > 1024 ? 1024 : width);
604 if ((str = *pstr = (char *) malloc (str_sz)) == NULL)
605 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
606
607 gcollect = resize_gcollect (gcollect);
608 gcollect->ptrs[gcollect->count++] = pstr;
609 }
610 else
611 {
612 if (npos != 0)
613 str = (char *) get_va_nth (argp, npos);
614 else
615 str = va_arg (arg, char *);
616 if (!str)
617 return cleanup_return (rval, &gcollect, pstr, &wbuf);
618 }
619 }
620
621 if ((c = in_ch (s, &read_in)) == EOF)
622 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
623
624 if ((flags & IS_SUPPRESSED) == 0)
625 {
626 do
627 {
628 if ((flags & IS_ALLOC_USED) != 0 && str == (*pstr + str_sz))
629 {
630 new_sz = str_sz + (str_sz >= width ? width - 1 : str_sz);
631 while ((str = (char *) realloc (*pstr, new_sz)) == NULL
632 && new_sz > (size_t) (str_sz + 1))
633 new_sz = str_sz + 1;
634 if (!str)
635 {
636 release_ptrs (&gcollect, &wbuf);
637 return EOF;
638 }
639 *pstr = str;
640 str += str_sz;
641 str_sz = new_sz;
642 }
643 *str++ = c;
644 }
645 while (--width > 0 && (c = in_ch (s, &read_in)) != EOF);
646 }
647 else
648 while (--width > 0 && (c = in_ch (s, &read_in)) != EOF);
649
650 if ((flags & IS_SUPPRESSED) == 0)
651 {
652 optimize_alloc (pstr, str, str_sz);
653 pstr = NULL;
654 ++rval;
655 }
656
657 break;
658
659 case 'C':
660 if (width == -1)
661 width = 1;
662
663 if ((flags & IS_SUPPRESSED) == 0)
664 {
665 if ((flags & IS_ALLOC_USED) != 0)
666 {
667 if (npos != 0)
668 pstr = (char **) get_va_nth (argp, npos);
669 else
670 pstr = va_arg (arg, char **);
671
672 if (!pstr)
673 return cleanup_return (rval, &gcollect, pstr, &wbuf);
674 str_sz = (width > 1024 ? 1024 : width);
675 *pstr = (char *) malloc (str_sz * sizeof (wchar_t));
676 if ((wstr = (wchar_t *) *pstr) == NULL)
677 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
678 gcollect = resize_gcollect (gcollect);
679 gcollect->ptrs[gcollect->count++] = pstr;
680 }
681 else
682 {
683 if (npos != 0)
684 wstr = (wchar_t *) get_va_nth (argp, npos);
685 else
686 wstr = va_arg (arg, wchar_t *);
687 if (!wstr)
688 return cleanup_return (rval, &gcollect, pstr, &wbuf);
689 }
690 }
691
692 if ((c = in_ch (s, &read_in)) == EOF)
693 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
694
695 memset (&cstate, 0, sizeof (cstate));
696
697 do
698 {
699 buf[0] = c;
700
701 if ((flags & IS_SUPPRESSED) == 0 && (flags & IS_ALLOC_USED) != 0
702 && wstr == ((wchar_t *) *pstr + str_sz))
703 {
704 new_sz = str_sz + (str_sz > width ? width - 1 : str_sz);
705
706 while ((wstr = (wchar_t *) realloc (*pstr, new_sz * sizeof (wchar_t))) == NULL
707 && new_sz > (size_t) (str_sz + 1))
708 new_sz = str_sz + 1;
709 if (!wstr)
710 {
711 release_ptrs (&gcollect, &wbuf);
712 return EOF;
713 }
714 *pstr = (char *) wstr;
715 wstr += str_sz;
716 str_sz = new_sz;
717 }
718
719 while (1)
720 {
721 n = mbrtowc ((flags & IS_SUPPRESSED) == 0 ? wstr : NULL, buf, 1, &cstate);
722
723 if (n == (size_t) -2)
724 {
725 if ((c = in_ch (s, &read_in)) == EOF)
726 {
727 errno = EILSEQ;
728 return cleanup_return (rval, &gcollect, pstr, &wbuf);
729 }
730
731 buf[0] = c;
732 continue;
733 }
734
735 if (n != 1)
736 {
737 errno = EILSEQ;
738 return cleanup_return (rval, &gcollect, pstr, &wbuf);
739 }
740 break;
741 }
742
743 ++wstr;
744 }
745 while (--width > 0 && (c = in_ch (s, &read_in)) != EOF);
746
747 if ((flags & IS_SUPPRESSED) == 0)
748 {
749 optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t));
750 pstr = NULL;
751 ++rval;
752 }
753 break;
754
755 case 's':
756 if ((flags & IS_SUPPRESSED) == 0)
757 {
758 if ((flags & IS_ALLOC_USED) != 0)
759 {
760 if (npos != 0)
761 pstr = (char **) get_va_nth (argp, npos);
762 else
763 pstr = va_arg (arg, char **);
764
765 if (!pstr)
766 return cleanup_return (rval, &gcollect, pstr, &wbuf);
767
768 str_sz = 100;
769 if ((str = *pstr = (char *) malloc (100)) == NULL)
770 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
771 gcollect = resize_gcollect (gcollect);
772 gcollect->ptrs[gcollect->count++] = pstr;
773 }
774 else
775 {
776 if (npos != 0)
777 str = (char *) get_va_nth (argp, npos);
778 else
779 str = va_arg (arg, char *);
780 if (!str)
781 return cleanup_return (rval, &gcollect, pstr, &wbuf);
782 }
783 }
784
785 if ((c = in_ch (s, &read_in)) == EOF)
786 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
787
788 do
789 {
790 if (isspace (c))
791 {
792 back_ch (c, s, &read_in, 1);
793 break;
794 }
795
796 if ((flags & IS_SUPPRESSED) == 0)
797 {
798 *str++ = c;
799 if ((flags & IS_ALLOC_USED) != 0 && str == (*pstr + str_sz))
800 {
801 new_sz = str_sz * 2;
802
803 while ((str = (char *) realloc (*pstr, new_sz)) == NULL
804 && new_sz > (size_t) (str_sz + 1))
805 new_sz = str_sz + 1;
806 if (!str)
807 {
808 if ((flags & USE_POSIX_ALLOC) == 0)
809 {
810 (*pstr)[str_sz - 1] = 0;
811 pstr = NULL;
812 ++rval;
813 }
814 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
815 }
816 *pstr = str;
817 str += str_sz;
818 str_sz = new_sz;
819 }
820 }
821 }
822 while ((width <= 0 || --width > 0) && (c = in_ch (s, &read_in)) != EOF);
823
824 if ((flags & IS_SUPPRESSED) == 0)
825 {
826 *str++ = 0;
827 optimize_alloc (pstr, str, str_sz);
828 pstr = NULL;
829 ++rval;
830 }
831 break;
832
833 case 'S':
834 if ((flags & IS_SUPPRESSED) == 0)
835 {
836 if ((flags & IS_ALLOC_USED) != 0)
837 {
838 if (npos != 0)
839 pstr = (char **) get_va_nth (argp, npos);
840 else
841 pstr = va_arg (arg, char **);
842
843 if (!pstr)
844 return cleanup_return (rval, &gcollect, pstr, &wbuf);
845
846 str_sz = 100;
847 *pstr = (char *) malloc (100 * sizeof (wchar_t));
848 if ((wstr = (wchar_t *) *pstr) == NULL)
849 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
850 gcollect = resize_gcollect (gcollect);
851 gcollect->ptrs[gcollect->count++] = pstr;
852 }
853 else
854 {
855 if (npos != 0)
856 wstr = (wchar_t *) get_va_nth (argp, npos);
857 else
858 wstr = va_arg (arg, wchar_t *);
859 if (!wstr)
860 return cleanup_return (rval, &gcollect, pstr, &wbuf);
861 }
862 }
863
864 if ((c = in_ch (s, &read_in)) == EOF)
865 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
866
867 memset (&cstate, 0, sizeof (cstate));
868
869 do
870 {
871 if (isspace (c))
872 {
873 back_ch (c, s, &read_in, 1);
874 break;
875 }
876
877 buf[0] = c;
878
879 while (1)
880 {
881 n = mbrtowc ((flags & IS_SUPPRESSED) == 0 ? wstr : NULL, buf, 1, &cstate);
882
883 if (n == (size_t) -2)
884 {
885 if ((c = in_ch (s, &read_in)) == EOF)
886 {
887 errno = EILSEQ;
888 return cleanup_return (rval, &gcollect, pstr, &wbuf);
889 }
890
891 buf[0] = c;
892 continue;
893 }
894
895 if (n != 1)
896 {
897 errno = EILSEQ;
898 return cleanup_return (rval, &gcollect, pstr, &wbuf);
899 }
900
901 ++wstr;
902 break;
903 }
904
905 if ((flags & IS_SUPPRESSED) == 0 && (flags & IS_ALLOC_USED) != 0
906 && wstr == ((wchar_t *) *pstr + str_sz))
907 {
908 new_sz = str_sz * 2;
909 while ((wstr = (wchar_t *) realloc (*pstr, new_sz * sizeof (wchar_t))) == NULL
910 && new_sz > (size_t) (str_sz + 1))
911 new_sz = str_sz + 1;
912 if (!wstr)
913 {
914 if ((flags & USE_POSIX_ALLOC) == 0)
915 {
916 ((wchar_t *) (*pstr))[str_sz - 1] = 0;
917 pstr = NULL;
918 ++rval;
919 }
920 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
921 }
922 *pstr = (char *) wstr;
923 wstr += str_sz;
924 str_sz = new_sz;
925 }
926 }
927 while ((width <= 0 || --width > 0) && (c = in_ch (s, &read_in)) != EOF);
928
929 if ((flags & IS_SUPPRESSED) == 0)
930 {
931 *wstr++ = 0;
932 optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t));
933 pstr = NULL;
934 ++rval;
935 }
936 break;
937
938 case 'd': case 'i':
939 case 'o': case 'p':
940 case 'u':
941 case 'x': case 'X':
942 switch (fc)
943 {
944 case 'd':
945 flags |= IS_SIGNED_NUM;
946 base = 10;
947 break;
948 case 'i':
949 flags |= IS_SIGNED_NUM;
950 base = 0;
951 break;
952 case 'o':
953 base = 8;
954 break;
955 case 'p':
956 base = 16;
957 flags &= ~(IS_S | IS_LL | IS_L);
958 #ifdef _WIN64
959 flags |= IS_LL;
960 #endif
961 flags |= IS_L | IS_POINTER;
962 break;
963 case 'u':
964 base = 10;
965 break;
966 case 'x': case 'X':
967 base = 16;
968 break;
969 }
970
971 if ((c = in_ch (s, &read_in)) == EOF)
972 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
973 if (c == '+' || c == '-')
974 {
975 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
976 wbuf[wbuf_cur_sz++] = c;
977 if (width > 0)
978 --width;
979 c = in_ch (s, &read_in);
980 }
981 if (width != 0 && c == '0')
982 {
983 if (width > 0)
984 --width;
985
986 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
987 wbuf[wbuf_cur_sz++] = c;
988 c = in_ch (s, &read_in);
989
990 if (width != 0 && tolower (c) == 'x')
991 {
992 if (!base)
993 base = 16;
994 if (base == 16)
995 {
996 if (width > 0)
997 --width;
998 c = in_ch (s, &read_in);
999 }
1000 }
1001 else if (!base)
1002 base = 8;
1003 }
1004
1005 if (!base)
1006 base = 10;
1007
1008 while (c != EOF && width != 0)
1009 {
1010 if (base == 16)
1011 {
1012 if (!isxdigit (c))
1013 break;
1014 }
1015 else if (!isdigit (c) || (int) (c - '0') >= base)
1016 {
1017 const char *p = lc_thousands_sep;
1018 int remain;
1019
1020 if (base != 10 || (flags & USE_GROUP) == 0)
1021 break;
1022 remain = width > 0 ? width : INT_MAX;
1023 while ((unsigned char) *p == c && remain >= 0)
1024 {
1025 /* As our conversion routines aren't supporting thousands
1026 separators, we are filtering them here. */
1027
1028 ++p;
1029 if (*p == 0 || !remain || (c = in_ch (s, &read_in)) == EOF)
1030 break;
1031 --remain;
1032 }
1033
1034 if (*p != 0)
1035 {
1036 if (p > lc_thousands_sep)
1037 {
1038 back_ch (c, s, &read_in, 0);
1039 while (--p > lc_thousands_sep)
1040 back_ch ((unsigned char) *p, s, &read_in, 1);
1041 c = (unsigned char) *p;
1042 }
1043 break;
1044 }
1045
1046 if (width > 0)
1047 width = remain;
1048 --wbuf_cur_sz;
1049 }
1050 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1051 wbuf[wbuf_cur_sz++] = c;
1052 if (width > 0)
1053 --width;
1054
1055 c = in_ch (s, &read_in);
1056 }
1057
1058 if (!wbuf_cur_sz || (wbuf_cur_sz == 1 && (wbuf[0] == '+' || wbuf[0] == '-')))
1059 {
1060 if (!wbuf_cur_sz && (flags & IS_POINTER) != 0
1061 && match_string (s, &read_in, &c, "(nil)"))
1062 {
1063 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1064 wbuf[wbuf_cur_sz++] = '0';
1065 }
1066 else
1067 {
1068 back_ch (c, s, &read_in, 0);
1069 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1070 }
1071 }
1072 else
1073 back_ch (c, s, &read_in, 0);
1074
1075 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1076 wbuf[wbuf_cur_sz++] = 0;
1077
1078 if ((flags & IS_LL))
1079 {
1080 if (flags & IS_SIGNED_NUM)
1081 cv_val.ll = strtoll (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/);
1082 else
1083 cv_val.ull = strtoull (wbuf, &tmp_wbuf_ptr, base);
1084 }
1085 else
1086 {
1087 if (flags & IS_SIGNED_NUM)
1088 cv_val.l = strtol (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/);
1089 else
1090 cv_val.ul = strtoul (wbuf, &tmp_wbuf_ptr, base);
1091 }
1092 if (wbuf == tmp_wbuf_ptr)
1093 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1094
1095 if ((flags & IS_SUPPRESSED) == 0)
1096 {
1097 if ((flags & IS_SIGNED_NUM) != 0)
1098 {
1099 if ((flags & IS_LL) != 0)
1100 *(npos != 0 ? (long long *) get_va_nth (argp, npos) : va_arg (arg, long long *)) = cv_val.ll;
1101 else if ((flags & IS_L) != 0)
1102 *(npos != 0 ? (long *) get_va_nth (argp, npos) : va_arg (arg, long *)) = cv_val.l;
1103 else if ((flags & IS_S) != 0)
1104 *(npos != 0 ? (short *) get_va_nth (argp, npos) : va_arg (arg, short *)) = (short) cv_val.l;
1105 else if ((flags & IS_C) != 0)
1106 *(npos != 0 ? (signed char *) get_va_nth (argp, npos) : va_arg (arg, signed char *)) = (signed char) cv_val.ul;
1107 else
1108 *(npos != 0 ? (int *) get_va_nth (argp, npos) : va_arg (arg, int *)) = (int) cv_val.l;
1109 }
1110 else
1111 {
1112 if ((flags & IS_LL) != 0)
1113 *(npos != 0 ? (unsigned long long *) get_va_nth (argp, npos) : va_arg (arg, unsigned long long *)) = cv_val.ull;
1114 else if ((flags & IS_L) != 0)
1115 *(npos != 0 ? (unsigned long *) get_va_nth (argp, npos) : va_arg (arg, unsigned long *)) = cv_val.ul;
1116 else if ((flags & IS_S) != 0)
1117 *(npos != 0 ? (unsigned short *) get_va_nth (argp, npos) : va_arg (arg, unsigned short *))
1118 = (unsigned short) cv_val.ul;
1119 else if ((flags & IS_C) != 0)
1120 *(npos != 0 ? (unsigned char *) get_va_nth (argp, npos) : va_arg (arg, unsigned char *)) = (unsigned char) cv_val.ul;
1121 else
1122 *(npos != 0 ? (unsigned int *) get_va_nth (argp, npos) : va_arg (arg, unsigned int *)) = (unsigned int) cv_val.ul;
1123 }
1124 ++rval;
1125 }
1126 break;
1127
1128 case 'e': case 'E':
1129 case 'f': case 'F':
1130 case 'g': case 'G':
1131 case 'a': case 'A':
1132 if (width > 0)
1133 --width;
1134 if ((c = in_ch (s, &read_in)) == EOF)
1135 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
1136
1137 seen_dot = seen_exp = 0;
1138 is_neg = (c == '-' ? 1 : 0);
1139
1140 if (c == '-' || c == '+')
1141 {
1142 if (width == 0 || (c = in_ch (s, &read_in)) == EOF)
1143 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1144 if (width > 0)
1145 --width;
1146 }
1147
1148 if (tolower (c) == 'n')
1149 {
1150 const char *match_txt = "nan";
1151
1152 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1153 wbuf[wbuf_cur_sz++] = c;
1154
1155 ++match_txt;
1156 do
1157 {
1158 if (width == 0 || (c = in_ch (s, &read_in)) == EOF || tolower (c) != match_txt[0])
1159 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1160
1161 if (width > 0)
1162 --width;
1163
1164 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1165 wbuf[wbuf_cur_sz++] = c;
1166 ++match_txt;
1167 }
1168 while (*match_txt != 0);
1169 }
1170 else if (tolower (c) == 'i')
1171 {
1172 const char *match_txt = "inf";
1173
1174 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1175 wbuf[wbuf_cur_sz++] = c;
1176
1177 ++match_txt;
1178 do
1179 {
1180 if (width == 0 || (c = in_ch (s, &read_in)) == EOF || tolower (c) != match_txt[0])
1181 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1182 if (width > 0)
1183 --width;
1184
1185 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1186 wbuf[wbuf_cur_sz++] = c;
1187 ++match_txt;
1188 }
1189 while (*match_txt != 0);
1190
1191 if (width != 0 && (c = in_ch (s, &read_in)) != EOF && tolower (c) == 'i')
1192 {
1193 match_txt = "inity";
1194
1195 if (width > 0)
1196 --width;
1197
1198 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1199 wbuf[wbuf_cur_sz++] = c;
1200 ++match_txt;
1201
1202 do
1203 {
1204 if (width == 0 || (c = in_ch (s, &read_in)) == EOF || tolower (c) != match_txt[0])
1205 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1206 if (width > 0)
1207 --width;
1208
1209 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1210 wbuf[wbuf_cur_sz++] = c;
1211 ++match_txt;
1212 }
1213 while (*match_txt != 0);
1214 }
1215 else if (width != 0 && c != EOF)
1216 back_ch (c, s, &read_in, 0);
1217 }
1218 else
1219 {
1220 not_in = 'e';
1221 if (width != 0 && c == '0')
1222 {
1223 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1224 wbuf[wbuf_cur_sz++] = c;
1225
1226 c = in_ch (s, &read_in);
1227 if (width > 0)
1228 --width;
1229 if (width != 0 && tolower (c) == 'x')
1230 {
1231 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1232 wbuf[wbuf_cur_sz++] = c;
1233
1234 flags |= IS_HEX_FLOAT;
1235 not_in = 'p';
1236
1237 flags &= ~USE_GROUP;
1238 c = in_ch (s, &read_in);
1239 if (width > 0)
1240 --width;
1241 }
1242 }
1243
1244 while (1)
1245 {
1246 if (isdigit (c) || (!seen_exp && (flags & IS_HEX_FLOAT) != 0 && isxdigit (c))
1247 || (seen_exp && wbuf[wbuf_cur_sz - 1] == not_in && (c == '-' || c == '+')))
1248 {
1249 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1250 wbuf[wbuf_cur_sz++] = c;
1251 }
1252 else if (wbuf_cur_sz > 0 && !seen_exp && (char) tolower (c) == not_in)
1253 {
1254 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1255 wbuf[wbuf_cur_sz++] = not_in;
1256 seen_exp = seen_dot = 1;
1257 }
1258 else
1259 {
1260 const char *p = lc_decimal_point;
1261 int remain = width > 0 ? width : INT_MAX;
1262
1263 if (! seen_dot)
1264 {
1265 while ((unsigned char) *p == c && remain >= 0)
1266 {
1267 ++p;
1268 if (*p == 0 || !remain || (c = in_ch (s, &read_in)) == EOF)
1269 break;
1270 --remain;
1271 }
1272 }
1273
1274 if (*p == 0)
1275 {
1276 for (p = lc_decimal_point; *p != 0; ++p)
1277 {
1278 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1279 wbuf[wbuf_cur_sz++] = (unsigned char) *p;
1280 }
1281 if (width > 0)
1282 width = remain;
1283 seen_dot = 1;
1284 }
1285 else
1286 {
1287 const char *pp = lc_thousands_sep;
1288
1289 if (!seen_dot && (flags & USE_GROUP) != 0)
1290 {
1291 while ((pp - lc_thousands_sep) < (p - lc_decimal_point)
1292 && *pp == lc_decimal_point[(pp - lc_thousands_sep)])
1293 ++pp;
1294 if ((pp - lc_thousands_sep) == (p - lc_decimal_point))
1295 {
1296 while ((unsigned char) *pp == c && remain >= 0)
1297 {
1298 ++pp;
1299 if (*pp == 0 || !remain || (c = in_ch (s, &read_in)) == EOF)
1300 break;
1301 --remain;
1302 }
1303 }
1304 }
1305
1306 if (pp != NULL && *pp == 0)
1307 {
1308 /* As our conversion routines aren't supporting thousands
1309 separators, we are filtering them here. */
1310 if (width > 0)
1311 width = remain;
1312 }
1313 else
1314 {
1315 back_ch (c, s, &read_in, 0);
1316 break;
1317 }
1318 }
1319 }
1320
1321 if (width == 0 || (c = in_ch (s, &read_in)) == EOF)
1322 break;
1323
1324 if (width > 0)
1325 --width;
1326 }
1327
1328 if (!wbuf_cur_sz || ((flags & IS_HEX_FLOAT) != 0 && wbuf_cur_sz == 2))
1329 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1330 }
1331
1332 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1333 wbuf[wbuf_cur_sz++] = 0;
1334
1335 if ((flags & IS_LL) != 0)
1336 {
1337 long double ld;
1338 ld = __mingw_strtold (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
1339 if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
1340 *(npos != 0 ? (long double *) get_va_nth (argp, npos) : va_arg (arg, long double *)) = is_neg ? -ld : ld;
1341 }
1342 else if ((flags & IS_L) != 0)
1343 {
1344 double d;
1345 d = (double) __mingw_strtold (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
1346 if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
1347 *(npos != 0 ? (double *) get_va_nth (argp, npos) : va_arg (arg, double *)) = is_neg ? -d : d;
1348 }
1349 else
1350 {
1351 float d = __mingw_strtof (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
1352 if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
1353 *(npos != 0 ? (float *) get_va_nth (argp, npos) : va_arg (arg, float *)) = is_neg ? -d : d;
1354 }
1355
1356 if (wbuf == tmp_wbuf_ptr)
1357 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1358
1359 if ((flags & IS_SUPPRESSED) == 0)
1360 ++rval;
1361 break;
1362
1363 case '[':
1364 if ((flags & IS_L) != 0)
1365 {
1366 if ((flags & IS_SUPPRESSED) == 0)
1367 {
1368 if ((flags & IS_ALLOC_USED) != 0)
1369 {
1370 if (npos != 0)
1371 pstr = (char **) get_va_nth (argp, npos);
1372 else
1373 pstr = va_arg (arg, char **);
1374
1375 if (!pstr)
1376 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1377
1378 str_sz = 100;
1379 *pstr = (char *) malloc (100 * sizeof (wchar_t));
1380
1381 if ((wstr = (wchar_t *) *pstr) == NULL)
1382 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
1383 gcollect = resize_gcollect (gcollect);
1384 gcollect->ptrs[gcollect->count++] = pstr;
1385 }
1386 else
1387 {
1388 if (npos != 0)
1389 wstr = (wchar_t *) get_va_nth (argp, npos);
1390 else
1391 wstr = va_arg (arg, wchar_t *);
1392 if (!wstr)
1393 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1394 }
1395 }
1396 }
1397 else if ((flags & IS_SUPPRESSED) == 0)
1398 {
1399 if ((flags & IS_ALLOC_USED) != 0)
1400 {
1401 if (npos != 0)
1402 pstr = (char **) get_va_nth (argp, npos);
1403 else
1404 pstr = va_arg (arg, char **);
1405
1406 if (!pstr)
1407 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1408
1409 str_sz = 100;
1410 if ((str = *pstr = (char *) malloc (100)) == NULL)
1411 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
1412
1413 gcollect = resize_gcollect (gcollect);
1414 gcollect->ptrs[gcollect->count++] = pstr;
1415 }
1416 else
1417 {
1418 if (npos != 0)
1419 str = (char *) get_va_nth (argp, npos);
1420 else
1421 str = va_arg (arg, char *);
1422 if (!str)
1423 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1424 }
1425 }
1426
1427 not_in = (*f == '^' ? 1 : 0);
1428 if (*f == '^')
1429 f++;
1430
1431 if (width < 0)
1432 width = INT_MAX;
1433
1434 if (wbuf_max_sz < 256)
1435 {
1436 wbuf_max_sz = 256;
1437 if (wbuf)
1438 free (wbuf);
1439 wbuf = (char *) malloc (wbuf_max_sz);
1440 }
1441 memset (wbuf, 0, 256);
1442
1443 fc = *f;
1444 if (fc == ']' || fc == '-')
1445 {
1446 wbuf[fc] = 1;
1447 ++f;
1448 }
1449
1450 while ((fc = *f++) != 0 && fc != ']')
1451 {
1452 if (fc == '-' && *f != 0 && *f != ']' && (unsigned char) f[-2] <= (unsigned char) *f)
1453 {
1454 for (fc = (unsigned char) f[-2]; fc < (unsigned char) *f; ++fc)
1455 wbuf[fc] = 1;
1456 }
1457 else
1458 wbuf[fc] = 1;
1459 }
1460
1461 if (!fc)
1462 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1463
1464 if ((flags & IS_L) != 0)
1465 {
1466 read_in_sv = read_in;
1467 cnt = 0;
1468
1469 if ((c = in_ch (s, &read_in)) == EOF)
1470 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
1471
1472 memset (&cstate, 0, sizeof (cstate));
1473
1474 do
1475 {
1476 if (wbuf[c] == not_in)
1477 {
1478 back_ch (c, s, &read_in, 1);
1479 break;
1480 }
1481
1482 if ((flags & IS_SUPPRESSED) == 0)
1483 {
1484 buf[0] = c;
1485 n = mbrtowc (wstr, buf, 1, &cstate);
1486
1487 if (n == (size_t) -2)
1488 {
1489 ++cnt;
1490 continue;
1491 }
1492 cnt = 0;
1493
1494 ++wstr;
1495 if ((flags & IS_ALLOC_USED) != 0 && wstr == ((wchar_t *) *pstr + str_sz))
1496 {
1497 new_sz = str_sz * 2;
1498 while ((wstr = (wchar_t *) realloc (*pstr, new_sz * sizeof (wchar_t))) == NULL
1499 && new_sz > (size_t) (str_sz + 1))
1500 new_sz = str_sz + 1;
1501 if (!wstr)
1502 {
1503 if ((flags & USE_POSIX_ALLOC) == 0)
1504 {
1505 ((wchar_t *) (*pstr))[str_sz - 1] = 0;
1506 pstr = NULL;
1507 ++rval;
1508 }
1509 else
1510 rval = EOF;
1511 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1512 }
1513 *pstr = (char *) wstr;
1514 wstr += str_sz;
1515 str_sz = new_sz;
1516 }
1517 }
1518
1519 if (--width <= 0)
1520 break;
1521 }
1522 while ((c = in_ch (s, &read_in)) != EOF);
1523
1524 if (cnt != 0)
1525 {
1526 errno = EILSEQ;
1527 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1528 }
1529
1530 if (read_in_sv == read_in)
1531 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1532
1533
1534 if ((flags & IS_SUPPRESSED) == 0)
1535 {
1536 *wstr++ = 0;
1537 optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t));
1538 pstr = NULL;
1539 ++rval;
1540 }
1541 }
1542 else
1543 {
1544 read_in_sv = read_in;
1545
1546 if ((c = in_ch (s, &read_in)) == EOF)
1547 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
1548
1549 do
1550 {
1551 if (wbuf[c] == not_in)
1552 {
1553 back_ch (c, s, &read_in, 1);
1554 break;
1555 }
1556
1557 if ((flags & IS_SUPPRESSED) == 0)
1558 {
1559 *str++ = c;
1560 if ((flags & IS_ALLOC_USED) != 0 && str == (*pstr + str_sz))
1561 {
1562 new_sz = str_sz * 2;
1563
1564 while ((str = (char *) realloc (*pstr, new_sz)) == NULL
1565 && new_sz > (size_t) (str_sz + 1))
1566 new_sz = str_sz + 1;
1567 if (!str)
1568 {
1569 if ((flags & USE_POSIX_ALLOC) == 0)
1570 {
1571 (*pstr)[str_sz - 1] = 0;
1572 pstr = NULL;
1573 ++rval;
1574 }
1575 else
1576 rval = EOF;
1577 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1578 }
1579 *pstr = str;
1580 str += str_sz;
1581 str_sz = new_sz;
1582 }
1583 }
1584 }
1585 while (--width > 0 && (c = in_ch (s, &read_in)) != EOF);
1586
1587 if (read_in_sv == read_in)
1588 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1589
1590 if ((flags & IS_SUPPRESSED) == 0)
1591 {
1592 *str++ = 0;
1593 optimize_alloc (pstr, str, str_sz);
1594 pstr = NULL;
1595 ++rval;
1596 }
1597 }
1598 break;
1599
1600 default:
1601 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1602 }
1603 }
1604
1605 if (ignore_ws)
1606 {
1607 while (isspace ((c = in_ch (s, &read_in))));
1608 back_ch (c, s, &read_in, 0);
1609 }
1610
1611 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1612}
1613
1614int
1615__mingw_vfscanf (FILE *s, const char *format, va_list argp)
1616{
1617 _IFP ifp;
1618 memset (&ifp, 0, sizeof (_IFP));
1619 ifp.fp = s;
1620 return __mingw_sformat (&ifp, format, argp);
1621}
1622
1623int
1624__mingw_vsscanf (const char *s, const char *format, va_list argp)
1625{
1626 _IFP ifp;
1627 memset (&ifp, 0, sizeof (_IFP));
1628 ifp.str = s;
1629 ifp.is_string = 1;
1630 return __mingw_sformat (&ifp, format, argp);
1631}
1632
lib/libc/mingw/stdio/mingw_vprintf.c created+58
......@@ -0,0 +1,58 @@
1/* vprintf.c
2 *
3 * $Id: vprintf.c,v 1.1 2008/08/11 22:41:55 keithmarshall Exp $
4 *
5 * Provides an implementation of the "vprintf" function, conforming
6 * generally to C99 and SUSv3/POSIX specifications, with extensions
7 * to support Microsoft's non-standard format specifications. This
8 * is included in libmingwex.a, whence it may replace the Microsoft
9 * function of the same name.
10 *
11 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
12 *
13 * This implementation of "vprintf" will normally be invoked by calling
14 * "__mingw_vprintf()" in preference to a direct reference to "vprintf()"
15 * itself; this leaves the MSVCRT implementation as the default, which
16 * will be deployed when user code invokes "vprint()". Users who then
17 * wish to use this implementation may either call "__mingw_vprintf()"
18 * directly, or may use conditional preprocessor defines, to redirect
19 * references to "vprintf()" to "__mingw_vprintf()".
20 *
21 * Compiling this module with "-D INSTALL_AS_DEFAULT" will change this
22 * recommended convention, such that references to "vprintf()" in user
23 * code will ALWAYS be redirected to "__mingw_vprintf()"; if this option
24 * is adopted, then users wishing to use the MSVCRT implementation of
25 * "vprintf()" will be forced to use a "back-door" mechanism to do so.
26 * Such a "back-door" mechanism is provided with MinGW, allowing the
27 * MSVCRT implementation to be called as "__msvcrt_vprintf()"; however,
28 * since users may not expect this behaviour, a standard libmingwex.a
29 * installation does not employ this option.
30 *
31 *
32 * This is free software. You may redistribute and/or modify it as you
33 * see fit, without restriction of copyright.
34 *
35 * This software is provided "as is", in the hope that it may be useful,
36 * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
37 * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE. At no
38 * time will the author accept any form of liability for any damages,
39 * however caused, resulting from the use of this software.
40 *
41 */
42#include <stdio.h>
43#include <stdarg.h>
44
45#include "mingw_pformat.h"
46
47int __cdecl __vprintf (const APICHAR *, va_list) __MINGW_NOTHROW;
48
49int __cdecl __vprintf(const APICHAR *fmt, va_list argv)
50{
51 register int retval;
52
53 _lock_file( stdout );
54 retval = __pformat( PFORMAT_TO_FILE | PFORMAT_NOLIMIT, stdout, 0, fmt, argv );
55 _unlock_file( stdout );
56
57 return retval;
58}
lib/libc/mingw/stdio/mingw_vprintfw.c created+9
......@@ -0,0 +1,9 @@
1/**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the mingw-w64 runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6#define __BUILD_WIDEAPI 1
7
8#include "mingw_vprintf.c"
9
lib/libc/mingw/stdio/mingw_vsnprintf.c created+52
......@@ -0,0 +1,52 @@
1/* vsnprintf.c
2 *
3 * $Id: vsnprintf.c,v 1.3 2008/07/28 23:24:20 keithmarshall Exp $
4 *
5 * Provides an implementation of the "vsnprintf" function, conforming
6 * generally to C99 and SUSv3/POSIX specifications, with extensions
7 * to support Microsoft's non-standard format specifications. This
8 * is included in libmingwex.a, replacing the redirection through
9 * libmoldnames.a, to the MSVCRT standard "_vsnprintf" function; (the
10 * standard MSVCRT function remains available, and may be invoked
11 * directly, using this fully qualified form of its name).
12 *
13 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
14 *
15 * This is free software. You may redistribute and/or modify it as you
16 * see fit, without restriction of copyright.
17 *
18 * This software is provided "as is", in the hope that it may be useful,
19 * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
20 * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE. At no
21 * time will the author accept any form of liability for any damages,
22 * however caused, resulting from the use of this software.
23 *
24 */
25
26#include <stdio.h>
27#include <stdarg.h>
28
29#include "mingw_pformat.h"
30
31int __cdecl __vsnprintf (APICHAR *, size_t, const APICHAR *fmt, va_list) __MINGW_NOTHROW;
32int __cdecl __vsnprintf(APICHAR *buf, size_t length, const APICHAR *fmt, va_list argv )
33{
34 register int retval;
35
36 if( length == (size_t)(0) )
37 /*
38 * No buffer; simply compute and return the size required,
39 * without actually emitting any data.
40 */
41 return __pformat( 0, buf, 0, fmt, argv);
42
43 /* If we get to here, then we have a buffer...
44 * Emit data up to the limit of buffer length less one,
45 * then add the requisite NUL terminator.
46 */
47 retval = __pformat( 0, buf, --length, fmt, argv );
48 buf[retval < (int) length ? retval : (int)length] = '\0';
49
50 return retval;
51}
52
lib/libc/mingw/stdio/mingw_vsnprintfw.c created+9
......@@ -0,0 +1,9 @@
1/**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the mingw-w64 runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6#define __BUILD_WIDEAPI 1
7
8#include "mingw_vsnprintf.c"
9
lib/libc/mingw/stdio/mingw_vsprintf.c created+54
......@@ -0,0 +1,54 @@
1/* vsprintf.c
2 *
3 * $Id: vsprintf.c,v 1.1 2008/08/11 22:41:55 keithmarshall Exp $
4 *
5 * Provides an implementation of the "vsprintf" function, conforming
6 * generally to C99 and SUSv3/POSIX specifications, with extensions
7 * to support Microsoft's non-standard format specifications. This
8 * is included in libmingwex.a, whence it may replace the Microsoft
9 * function of the same name.
10 *
11 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
12 *
13 * This implementation of "vsprintf" will normally be invoked by calling
14 * "__mingw_vsprintf()" in preference to a direct reference to "vsprintf()"
15 * itself; this leaves the MSVCRT implementation as the default, which
16 * will be deployed when user code invokes "vsprint()". Users who then
17 * wish to use this implementation may either call "__mingw_vsprintf()"
18 * directly, or may use conditional preprocessor defines, to redirect
19 * references to "vsprintf()" to "__mingw_vsprintf()".
20 *
21 * Compiling this module with "-D INSTALL_AS_DEFAULT" will change this
22 * recommended convention, such that references to "vsprintf()" in user
23 * code will ALWAYS be redirected to "__mingw_vsprintf()"; if this option
24 * is adopted, then users wishing to use the MSVCRT implementation of
25 * "vsprintf()" will be forced to use a "back-door" mechanism to do so.
26 * Such a "back-door" mechanism is provided with MinGW, allowing the
27 * MSVCRT implementation to be called as "__msvcrt_vsprintf()"; however,
28 * since users may not expect this behaviour, a standard libmingwex.a
29 * installation does not employ this option.
30 *
31 *
32 * This is free software. You may redistribute and/or modify it as you
33 * see fit, without restriction of copyright.
34 *
35 * This software is provided "as is", in the hope that it may be useful,
36 * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
37 * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE. At no
38 * time will the author accept any form of liability for any damages,
39 * however caused, resulting from the use of this software.
40 *
41 */
42#include <stdio.h>
43#include <stdarg.h>
44
45#include "mingw_pformat.h"
46
47int __cdecl __vsprintf (APICHAR *, const APICHAR *, va_list) __MINGW_NOTHROW;
48
49int __cdecl __vsprintf(APICHAR *buf, const APICHAR *fmt, va_list argv)
50{
51 register int retval;
52 buf[retval = __pformat( PFORMAT_NOLIMIT, buf, 0, fmt, argv )] = '\0';
53 return retval;
54}
lib/libc/mingw/stdio/mingw_vsprintfw.c created+10
......@@ -0,0 +1,10 @@
1/**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the mingw-w64 runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6#define __BUILD_WIDEAPI 1
7#define _CRT_NON_CONFORMING_SWPRINTFS 1
8
9#include "mingw_vsprintf.c"
10
lib/libc/mingw/stdio/mingw_wscanf.c created+28
......@@ -0,0 +1,28 @@
1#include <stdarg.h>
2#include <stdio.h>
3#include <stdlib.h>
4
5extern int __mingw_vfwscanf (FILE *stream, const wchar_t *format, va_list argp);
6
7int __mingw_wscanf (const wchar_t *format, ...);
8int __mingw_vwscanf (const wchar_t *format, va_list argp);
9
10int
11__mingw_wscanf (const wchar_t *format, ...)
12{
13 va_list argp;
14 int r;
15
16 va_start (argp, format);
17 r = __mingw_vfwscanf (stdin, format, argp);
18 va_end (argp);
19
20 return r;
21}
22
23int
24__mingw_vwscanf (const wchar_t *format, va_list argp)
25{
26 return __mingw_vfwscanf (stdin, format, argp);
27}
28
lib/libc/mingw/stdio/mingw_wvfscanf.c created+1631
......@@ -0,0 +1,1631 @@
1/*
2 This Software is provided under the Zope Public License (ZPL) Version 2.1.
3
4 Copyright (c) 2011 by the mingw-w64 project
5
6 See the AUTHORS file for the list of contributors to the mingw-w64 project.
7
8 This license has been certified as open source. It has also been designated
9 as GPL compatible by the Free Software Foundation (FSF).
10
11 Redistribution and use in source and binary forms, with or without
12 modification, are permitted provided that the following conditions are met:
13
14 1. Redistributions in source code must retain the accompanying copyright
15 notice, this list of conditions, and the following disclaimer.
16 2. Redistributions in binary form must reproduce the accompanying
17 copyright notice, this list of conditions, and the following disclaimer
18 in the documentation and/or other materials provided with the
19 distribution.
20 3. Names of the copyright holders must not be used to endorse or promote
21 products derived from this software without prior written permission
22 from the copyright holders.
23 4. The right to distribute this software or to use it for any purpose does
24 not give you the right to use Servicemarks (sm) or Trademarks (tm) of
25 the copyright holders. Use of them is covered by separate agreement
26 with the copyright holders.
27 5. If any files are modified, you must cause the modified files to carry
28 prominent notices stating that you changed the files and the date of
29 any change.
30
31 Disclaimer
32
33 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
34 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
36 EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
37 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
38 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
39 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
40 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
41 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
42 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43*/
44
45#define __LARGE_MBSTATE_T
46
47#include <limits.h>
48#include <stddef.h>
49#include <stdarg.h>
50#include <stdio.h>
51#include <stdint.h>
52#include <stdlib.h>
53#include <string.h>
54#include <wchar.h>
55#include <ctype.h>
56#include <wctype.h>
57#include <locale.h>
58#include <errno.h>
59
60#ifndef CP_UTF8
61#define CP_UTF8 65001
62#endif
63
64#ifndef MB_ERR_INVALID_CHARS
65#define MB_ERR_INVALID_CHARS 0x00000008
66#endif
67
68/* Helper flags for conversion. */
69#define IS_C 0x0001
70#define IS_S 0x0002
71#define IS_L 0x0004
72#define IS_LL 0x0008
73#define IS_SIGNED_NUM 0x0010
74#define IS_POINTER 0x0020
75#define IS_HEX_FLOAT 0x0040
76#define IS_SUPPRESSED 0x0080
77#define USE_GROUP 0x0100
78#define USE_GNU_ALLOC 0x0200
79#define USE_POSIX_ALLOC 0x0400
80
81#define IS_ALLOC_USED (USE_GNU_ALLOC | USE_POSIX_ALLOC)
82
83/* internal stream structure with back-buffer. */
84typedef struct _IFP
85{
86 __extension__ union {
87 void *fp;
88 const wchar_t *str;
89 };
90 int bch[1024];
91 unsigned int is_string : 1;
92 int back_top;
93 unsigned int seen_eof : 1;
94} _IFP;
95
96static void *
97get_va_nth (va_list argp, unsigned int n)
98{
99 va_list ap;
100 if (!n)
101 abort ();
102 va_copy (ap, argp);
103 while (--n > 0)
104 (void) va_arg(ap, void *);
105 return va_arg (ap, void *);
106}
107
108static void
109optimize_alloc (char **p, char *end, size_t alloc_sz)
110{
111 size_t need_sz;
112 char *h;
113
114 if (!p || !*p)
115 return;
116
117 need_sz = end - *p;
118 if (need_sz == alloc_sz)
119 return;
120
121 if ((h = (char *) realloc (*p, need_sz)) != NULL)
122 *p = h;
123}
124
125static void
126back_ch (int c, _IFP *s, size_t *rin, int not_eof)
127{
128 if (!not_eof && c == WEOF)
129 return;
130 if (s->is_string == 0)
131 {
132 FILE *fp = s->fp;
133 ungetwc (c, fp);
134 rin[0] -= 1;
135 return;
136 }
137 rin[0] -= 1;
138 s->bch[s->back_top] = c;
139 s->back_top += 1;
140}
141
142static int
143in_ch (_IFP *s, size_t *rin)
144{
145 int r;
146 if (s->back_top)
147 {
148 s->back_top -= 1;
149 r = s->bch[s->back_top];
150 rin[0] += 1;
151 }
152 else if (s->seen_eof)
153 {
154 return WEOF;
155 }
156 else if (s->is_string)
157 {
158 const wchar_t *ps = s->str;
159 r = ((int) *ps) & 0xffff;
160 ps++;
161 if (r != 0)
162 {
163 rin[0] += 1;
164 s->str = ps;
165 return r;
166 }
167 s->seen_eof = 1;
168 return WEOF;
169 }
170 else
171 {
172 FILE *fp = (FILE *) s->fp;
173 r = getwc (fp);
174 if (r != WEOF)
175 rin[0] += 1;
176 else s->seen_eof = 1;
177 }
178 return r;
179}
180
181static int
182match_string (_IFP *s, size_t *rin, wint_t *c, const wchar_t *str)
183{
184 int ch = *c;
185
186 if (*str == 0)
187 return 1;
188
189 if (*str != (wchar_t) towlower (ch))
190 return 0;
191 ++str;
192 while (*str != 0)
193 {
194 if ((ch = in_ch (s, rin)) == WEOF)
195 {
196 c[0] = ch;
197 return 0;
198 }
199
200 if (*str != (wchar_t) towlower (ch))
201 {
202 c[0] = ch;
203 return 0;
204 }
205 ++str;
206 }
207 c[0] = ch;
208 return 1;
209}
210
211struct gcollect
212{
213 size_t count;
214 struct gcollect *next;
215 char **ptrs[32];
216};
217
218static void
219release_ptrs (struct gcollect **pt, wchar_t **wbuf)
220{
221 struct gcollect *pf;
222 size_t cnt;
223
224 if (wbuf)
225 {
226 free (*wbuf);
227 *wbuf = NULL;
228 }
229 if (!pt || (pf = *pt) == NULL)
230 return;
231 while (pf != NULL)
232 {
233 struct gcollect *pf_sv = pf;
234 for (cnt = 0; cnt < pf->count; ++cnt)
235 {
236 free (*pf->ptrs[cnt]);
237 *pf->ptrs[cnt] = NULL;
238 }
239 pf = pf->next;
240 free (pf_sv);
241 }
242 *pt = NULL;
243}
244
245static int
246cleanup_return (int rval, struct gcollect **pfree, char **strp, wchar_t **wbuf)
247{
248 if (rval == EOF)
249 release_ptrs (pfree, wbuf);
250 else
251 {
252 if (pfree)
253 {
254 struct gcollect *pf = *pfree, *pf_sv;
255 while (pf != NULL)
256 {
257 pf_sv = pf;
258 pf = pf->next;
259 free (pf_sv);
260 }
261 *pfree = NULL;
262 }
263 if (strp != NULL)
264 {
265 free (*strp);
266 *strp = NULL;
267 }
268 if (wbuf)
269 {
270 free (*wbuf);
271 *wbuf = NULL;
272 }
273 }
274 return rval;
275}
276
277static struct gcollect *
278resize_gcollect (struct gcollect *pf)
279{
280 struct gcollect *np;
281 if (pf && pf->count < 32)
282 return pf;
283 np = malloc (sizeof (struct gcollect));
284 np->count = 0;
285 np->next = pf;
286 return np;
287}
288
289static wchar_t *
290resize_wbuf (size_t wpsz, size_t *wbuf_max_sz, wchar_t *old)
291{
292 wchar_t *wbuf;
293 size_t nsz;
294 if (*wbuf_max_sz != wpsz)
295 return old;
296 nsz = (256 > (2 * wbuf_max_sz[0]) ? 256 : (2 * wbuf_max_sz[0]));
297 if (!old)
298 wbuf = (wchar_t *) malloc (nsz * sizeof (wchar_t));
299 else
300 wbuf = (wchar_t *) realloc (old, nsz * sizeof (wchar_t));
301 if (!wbuf)
302 {
303 if (old)
304 free (old);
305 }
306 else
307 *wbuf_max_sz = nsz;
308 return wbuf;
309}
310
311static int
312__mingw_swformat (_IFP *s, const wchar_t *format, va_list argp)
313{
314 const wchar_t *f = format;
315 struct gcollect *gcollect = NULL;
316 size_t read_in = 0, wbuf_max_sz = 0;
317 ssize_t str_sz = 0;
318 char *str = NULL, **pstr = NULL;;
319 wchar_t *wstr = NULL, *wbuf = NULL;
320 wint_t c = 0, rval = 0;
321 int ignore_ws = 0;
322 va_list arg;
323 size_t wbuf_cur_sz, str_len, read_in_sv, new_sz, n;
324 unsigned int fc, npos;
325 int width, flags, base = 0, errno_sv, clen;
326 char seen_dot, seen_exp, is_neg, *nstr, buf[MB_LEN_MAX];
327 wchar_t wc, not_in, *tmp_wbuf_ptr, *temp_wbuf_end, *wbuf_iter;
328 wint_t lc_decimal_point, lc_thousands_sep;
329 mbstate_t state;
330 union {
331 unsigned long long ull;
332 unsigned long ul;
333 long long ll;
334 long l;
335 } cv_val;
336
337 arg = argp;
338
339 if (!s || s->fp == NULL || !format)
340 {
341 errno = EINVAL;
342 return EOF;
343 }
344
345 memset (&state, 0, sizeof(state));
346 clen = mbrtowc( &wc, localeconv()->decimal_point, 16, &state);
347 lc_decimal_point = (clen > 0 ? wc : '.');
348 memset( &state, 0, sizeof( state ) );
349 clen = mbrtowc( &wc, localeconv()->thousands_sep, 16, &state);
350 lc_thousands_sep = (clen > 0 ? wc : 0);
351
352 while (*f != 0)
353 {
354 fc = *f++;
355 if (fc != '%')
356 {
357 if (iswspace (fc))
358 ignore_ws = 1;
359 else
360 {
361 if ((c = in_ch (s, &read_in)) == WEOF)
362 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
363
364 if (ignore_ws)
365 {
366 ignore_ws = 0;
367 if (iswspace (c))
368 {
369 do
370 {
371 if ((c = in_ch (s, &read_in)) == WEOF)
372 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
373 }
374 while (iswspace (c));
375 }
376 }
377
378 if (c != fc)
379 {
380 back_ch (c, s, &read_in, 0);
381 return cleanup_return (rval, &gcollect, pstr, &wbuf);
382 }
383 }
384
385 continue;
386 }
387
388 width = flags = 0;
389 npos = 0;
390 wbuf_cur_sz = 0;
391
392 if (iswdigit ((unsigned int) *f))
393 {
394 const wchar_t *svf = f;
395 npos = (unsigned int) *f++ - '0';
396 while (iswdigit ((unsigned int) *f))
397 npos = npos * 10 + ((unsigned int) *f++ - '0');
398 if (*f != '$')
399 {
400 npos = 0;
401 f = svf;
402 }
403 else
404 f++;
405 }
406
407 do
408 {
409 if (*f == '*')
410 flags |= IS_SUPPRESSED;
411 else if (*f == '\'')
412 {
413 if (lc_thousands_sep)
414 flags |= USE_GROUP;
415 }
416 else if (*f == 'I')
417 {
418 /* we don't support locale's digits (i18N), but ignore it for now silently. */
419 ;
420#ifdef _WIN32
421 if (f[1] == '6' && f[2] == '4')
422 {
423 flags |= IS_LL | IS_L;
424 f += 2;
425 }
426 else if (f[1] == '3' && f[2] == '2')
427 {
428 flags |= IS_L;
429 f += 2;
430 }
431 else
432 {
433#ifdef _WIN64
434 flags |= IS_LL | IS_L;
435#else
436 flags |= IS_L;
437#endif
438 }
439#endif
440 }
441 else
442 break;
443 ++f;
444 }
445 while (1);
446
447 while (iswdigit ((unsigned char) *f))
448 width = width * 10 + ((unsigned char) *f++ - '0');
449
450 if (!width)
451 width = -1;
452
453 switch (*f)
454 {
455 case 'h':
456 ++f;
457 flags |= (*f == 'h' ? IS_C : IS_S);
458 if (*f == 'h')
459 ++f;
460 break;
461 case 'l':
462 ++f;
463 flags |= (*f == 'l' ? IS_LL : 0) | IS_L;
464 if (*f == 'l')
465 ++f;
466 break;
467 case 'q': case 'L':
468 ++f;
469 flags |= IS_LL | IS_L;
470 break;
471 case 'a':
472 if (f[1] != 's' && f[1] != 'S' && f[1] != '[')
473 break;
474 ++f;
475 flags |= USE_GNU_ALLOC;
476 break;
477 case 'm':
478 flags |= USE_POSIX_ALLOC;
479 ++f;
480 if (*f == 'l')
481 {
482 flags |= IS_L;
483 ++f;
484 }
485 break;
486 case 'z':
487#ifdef _WIN64
488 flags |= IS_LL | IS_L;
489#else
490 flags |= IS_L;
491#endif
492 ++f;
493 break;
494 case 'j':
495 if (sizeof (uintmax_t) > sizeof (unsigned long))
496 flags |= IS_LL;
497 else if (sizeof (uintmax_t) > sizeof (unsigned int))
498 flags |= IS_L;
499 ++f;
500 break;
501 case 't':
502#ifdef _WIN64
503 flags |= IS_LL;
504#else
505 flags |= IS_L;
506#endif
507 ++f;
508 break;
509 case 0:
510 return cleanup_return (rval, &gcollect, pstr, &wbuf);
511 default:
512 break;
513 }
514
515 if (*f == 0)
516 return cleanup_return (rval, &gcollect, pstr, &wbuf);
517
518 fc = *f++;
519 if (ignore_ws || (fc != '[' && fc != 'c' && fc != 'C' && fc != 'n'))
520 {
521 errno_sv = errno;
522 errno = 0;
523 do
524 {
525 if ((c == WEOF || (c = in_ch (s, &read_in)) == WEOF) && errno == EINTR)
526 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
527 }
528 while (iswspace (c));
529
530 ignore_ws = 0;
531 errno = errno_sv;
532 back_ch (c, s, &read_in, 0);
533 }
534
535 switch (fc)
536 {
537 case 'c':
538 if ((flags & IS_L) != 0)
539 fc = 'C';
540 break;
541 case 's':
542 if ((flags & IS_L) != 0)
543 fc = 'S';
544 break;
545 }
546
547 switch (fc)
548 {
549 case '%':
550 if ((c = in_ch (s, &read_in)) == WEOF)
551 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
552 if (c != fc)
553 {
554 back_ch (c, s, &read_in, 1);
555 return cleanup_return (rval, &gcollect, pstr, &wbuf);
556 }
557 break;
558
559 case 'n':
560 if ((flags & IS_SUPPRESSED) == 0)
561 {
562 if ((flags & IS_LL) != 0)
563 *(npos != 0 ? (long long *) get_va_nth (argp, npos) : va_arg (arg, long long *)) = read_in;
564 else if ((flags & IS_L) != 0)
565 *(npos != 0 ? (long *) get_va_nth (argp, npos) : va_arg (arg, long *)) = read_in;
566 else if ((flags & IS_S) != 0)
567 *(npos != 0 ? (short *) get_va_nth (argp, npos) : va_arg (arg, short *)) = read_in;
568 else if ((flags & IS_C) != 0)
569 *(npos != 0 ? (char *) get_va_nth (argp, npos) : va_arg (arg, char *)) = read_in;
570 else
571 *(npos != 0 ? (int *) get_va_nth (argp, npos) : va_arg (arg, int *)) = read_in;
572 }
573 break;
574
575 case 'c':
576 if (width == -1)
577 width = 1;
578
579 if ((flags & IS_SUPPRESSED) == 0)
580 {
581 if ((flags & IS_ALLOC_USED) != 0)
582 {
583 if (npos != 0)
584 pstr = (char **) get_va_nth (argp, npos);
585 else
586 pstr = va_arg (arg, char **);
587
588 if (!pstr)
589 return cleanup_return (rval, &gcollect, pstr, &wbuf);
590 str_sz = 100;
591 if ((str = *pstr = (char *) malloc (100)) == NULL)
592 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
593 gcollect = resize_gcollect (gcollect);
594 gcollect->ptrs[gcollect->count++] = pstr;
595 }
596 else
597 {
598 if (npos != 0)
599 str = (char *) get_va_nth (argp, npos);
600 else
601 str = va_arg (arg, char *);
602 if (!str)
603 return cleanup_return (rval, &gcollect, pstr, &wbuf);
604 }
605 }
606 if ((c = in_ch (s, &read_in)) == WEOF)
607 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
608
609 memset (&state, 0, sizeof (state));
610
611 do
612 {
613 if ((flags & IS_SUPPRESSED) == 0 && (flags & USE_POSIX_ALLOC) != 0
614 && (str + MB_CUR_MAX) >= (*pstr + str_sz))
615 {
616 new_sz = str_sz * 2;
617 str_len = (str - *pstr);
618 while ((nstr = (char *) realloc (*pstr, new_sz)) == NULL
619 && new_sz > (str_len + MB_CUR_MAX))
620 new_sz = str_len + MB_CUR_MAX;
621 if (!nstr)
622 {
623 release_ptrs (&gcollect, &wbuf);
624 return EOF;
625 }
626 *pstr = nstr;
627 str = nstr + str_len;
628 str_sz = new_sz;
629 }
630
631 n = wcrtomb ((flags & IS_SUPPRESSED) == 0 ? str : NULL, c, &state);
632 if (n == (size_t) -1LL)
633 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
634 str += n;
635 }
636 while (--width > 0 && (c = in_ch (s, &read_in)) != WEOF);
637
638 if ((flags & IS_SUPPRESSED) == 0)
639 {
640 optimize_alloc (pstr, str, str_sz);
641 pstr = NULL;
642 ++rval;
643 }
644
645 break;
646
647 case 'C':
648 if (width == -1)
649 width = 1;
650
651 if ((flags & IS_SUPPRESSED) == 0)
652 {
653 if ((flags & IS_ALLOC_USED) != 0)
654 {
655 if (npos != 0)
656 pstr = (char **) get_va_nth (argp, npos);
657 else
658 pstr = va_arg (arg, char **);
659
660 if (!pstr)
661 return cleanup_return (rval, &gcollect, pstr, &wbuf);
662 str_sz = (width > 1024 ? 1024 : width);
663 *pstr = (char *) malloc (str_sz * sizeof (wchar_t));
664 if ((wstr = (wchar_t *) *pstr) == NULL)
665 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
666
667 if ((wstr = (wchar_t *) *pstr) != NULL)
668 {
669 gcollect = resize_gcollect (gcollect);
670 gcollect->ptrs[gcollect->count++] = pstr;
671 }
672 }
673 else
674 {
675 if (npos != 0)
676 wstr = (wchar_t *) get_va_nth (argp, npos);
677 else
678 wstr = va_arg (arg, wchar_t *);
679 if (!wstr)
680 return cleanup_return (rval, &gcollect, pstr, &wbuf);
681 }
682 }
683
684 if ((c = in_ch (s, &read_in)) == WEOF)
685 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
686
687 if ((flags & IS_SUPPRESSED) == 0)
688 {
689 do
690 {
691 if ((flags & IS_ALLOC_USED) != 0
692 && wstr == ((wchar_t *) *pstr + str_sz))
693 {
694 new_sz = str_sz + (str_sz > width ? width - 1 : str_sz);
695 while ((wstr = (wchar_t *) realloc (*pstr,
696 new_sz * sizeof (wchar_t))) == NULL
697 && new_sz > (size_t) (str_sz + 1))
698 new_sz = str_sz + 1;
699 if (!wstr)
700 {
701 release_ptrs (&gcollect, &wbuf);
702 return EOF;
703 }
704 *pstr = (char *) wstr;
705 wstr += str_sz;
706 str_sz = new_sz;
707 }
708 *wstr++ = c;
709 }
710 while (--width > 0 && (c = in_ch (s, &read_in)) != WEOF);
711 }
712 else
713 {
714 while (--width > 0 && (c = in_ch (s, &read_in)) != WEOF);
715 }
716
717 if ((flags & IS_SUPPRESSED) == 0)
718 {
719 optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t));
720 pstr = NULL;
721 ++rval;
722 }
723 break;
724
725 case 's':
726 if ((flags & IS_SUPPRESSED) == 0)
727 {
728 if ((flags & IS_ALLOC_USED) != 0)
729 {
730 if (npos != 0)
731 pstr = (char **) get_va_nth (argp, npos);
732 else
733 pstr = va_arg (arg, char **);
734
735 if (!pstr)
736 return cleanup_return (rval, &gcollect, pstr, &wbuf);
737 str_sz = 100;
738 if ((str = *pstr = (char *) malloc (100)) == NULL)
739 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
740 gcollect = resize_gcollect (gcollect);
741 gcollect->ptrs[gcollect->count++] = pstr;
742 }
743 else
744 {
745 if (npos != 0)
746 str = (char *) get_va_nth (argp, npos);
747 else
748 str = va_arg (arg, char *);
749 if (!str)
750 return cleanup_return (rval, &gcollect, pstr, &wbuf);
751 }
752 }
753
754 if ((c = in_ch (s, &read_in)) == WEOF)
755 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
756
757 memset (&state, 0, sizeof (state));
758
759 do
760 {
761 if (iswspace (c))
762 {
763 back_ch (c, s, &read_in, 1);
764 break;
765 }
766
767 {
768 if ((flags & IS_SUPPRESSED) == 0 && (flags & IS_ALLOC_USED) != 0
769 && (str + MB_CUR_MAX) >= (*pstr + str_sz))
770 {
771 new_sz = str_sz * 2;
772 str_len = (str - *pstr);
773
774 while ((nstr = (char *) realloc (*pstr, new_sz)) == NULL
775 && new_sz > (str_len + MB_CUR_MAX))
776 new_sz = str_len + MB_CUR_MAX;
777 if (!nstr)
778 {
779 if ((flags & USE_POSIX_ALLOC) == 0)
780 {
781 (*pstr)[str_len] = 0;
782 pstr = NULL;
783 ++rval;
784 }
785 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
786 }
787 *pstr = nstr;
788 str = nstr + str_len;
789 str_sz = new_sz;
790 }
791
792 n = wcrtomb ((flags & IS_SUPPRESSED) == 0 ? str : NULL, c,
793 &state);
794 if (n == (size_t) -1LL)
795 {
796 errno = EILSEQ;
797 return cleanup_return (rval, &gcollect, pstr, &wbuf);
798 }
799
800 str += n;
801 }
802 }
803 while ((width <= 0 || --width > 0) && (c = in_ch (s, &read_in)) != WEOF);
804
805 if ((flags & IS_SUPPRESSED) == 0)
806 {
807 n = wcrtomb (buf, 0, &state);
808 if (n > 0 && (flags & IS_ALLOC_USED) != 0
809 && (str + n) >= (*pstr + str_sz))
810 {
811 str_len = (str - *pstr);
812
813 if ((nstr = (char *) realloc (*pstr, str_len + n + 1)) == NULL)
814 {
815 if ((flags & USE_POSIX_ALLOC) == 0)
816 {
817 (*pstr)[str_len] = 0;
818 pstr = NULL;
819 ++rval;
820 }
821 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
822 }
823 *pstr = nstr;
824 str = nstr + str_len;
825 str_sz = str_len + n + 1;
826 }
827
828 if (n)
829 {
830 memcpy (str, buf, n);
831 str += n;
832 }
833 *str++ = 0;
834
835 optimize_alloc (pstr, str, str_sz);
836 pstr = NULL;
837 ++rval;
838 }
839 break;
840
841 case 'S':
842 if ((flags & IS_SUPPRESSED) == 0)
843 {
844 if ((flags & IS_ALLOC_USED) != 0)
845 {
846 if (npos != 0)
847 pstr = (char **) get_va_nth (argp, npos);
848 else
849 pstr = va_arg (arg, char **);
850
851 if (!pstr)
852 return cleanup_return (rval, &gcollect, pstr, &wbuf);
853 str_sz = 100;
854 *pstr = (char *) malloc (100 * sizeof (wchar_t));
855 if ((wstr = (wchar_t *) *pstr) == NULL)
856 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
857 gcollect = resize_gcollect (gcollect);
858 gcollect->ptrs[gcollect->count++] = pstr;
859 }
860 else
861 {
862 if (npos != 0)
863 wstr = (wchar_t *) get_va_nth (argp, npos);
864 else
865 wstr = va_arg (arg, wchar_t *);
866 if (!wstr)
867 return cleanup_return (rval, &gcollect, pstr, &wbuf);
868 }
869 }
870 if ((c = in_ch (s, &read_in)) == WEOF)
871 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
872
873 do
874 {
875 if (iswspace (c))
876 {
877 back_ch (c, s, &read_in, 1);
878 break;
879 }
880
881 if ((flags & IS_SUPPRESSED) == 0)
882 {
883 *wstr++ = c;
884 if ((flags & IS_ALLOC_USED) != 0 && wstr == ((wchar_t *) *pstr + str_sz))
885 {
886 new_sz = str_sz * 2;
887
888 while ((wstr = (wchar_t *) realloc (*pstr,
889 new_sz * sizeof (wchar_t))) == NULL
890 && new_sz > (size_t) (str_sz + 1))
891 new_sz = str_sz + 1;
892 if (!wstr)
893 {
894 if ((flags & USE_POSIX_ALLOC) == 0)
895 {
896 ((wchar_t *) (*pstr))[str_sz - 1] = 0;
897 pstr = NULL;
898 ++rval;
899 }
900 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
901 }
902 *pstr = (char *) wstr;
903 wstr += str_sz;
904 str_sz = new_sz;
905 }
906 }
907 }
908 while ((width <= 0 || --width > 0) && (c = in_ch (s, &read_in)) != WEOF);
909
910 if ((flags & IS_SUPPRESSED) == 0)
911 {
912 *wstr++ = 0;
913
914 optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t));
915 pstr = NULL;
916 ++rval;
917 }
918 break;
919
920 case 'd': case 'i':
921 case 'o': case 'p':
922 case 'u':
923 case 'x': case 'X':
924 switch (fc)
925 {
926 case 'd':
927 flags |= IS_SIGNED_NUM;
928 base = 10;
929 break;
930 case 'i':
931 flags |= IS_SIGNED_NUM;
932 base = 0;
933 break;
934 case 'o':
935 base = 8;
936 break;
937 case 'p':
938 base = 16;
939 flags &= ~(IS_S | IS_LL | IS_L);
940 #ifdef _WIN64
941 flags |= IS_LL;
942 #endif
943 flags |= IS_L | IS_POINTER;
944 break;
945 case 'u':
946 base = 10;
947 break;
948 case 'x': case 'X':
949 base = 16;
950 break;
951 }
952
953 if ((c = in_ch (s, &read_in)) == WEOF)
954 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
955
956 if (c == '+' || c == '-')
957 {
958 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
959 wbuf[wbuf_cur_sz++] = c;
960
961 if (width > 0)
962 --width;
963 c = in_ch (s, &read_in);
964 }
965
966 if (width != 0 && c == '0')
967 {
968 if (width > 0)
969 --width;
970
971 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
972 wbuf[wbuf_cur_sz++] = c;
973
974 c = in_ch (s, &read_in);
975
976 if (width != 0 && towlower (c) == 'x')
977 {
978 if (!base)
979 base = 16;
980 if (base == 16)
981 {
982 if (width > 0)
983 --width;
984 c = in_ch (s, &read_in);
985 }
986 }
987 else if (!base)
988 base = 8;
989 }
990
991 if (!base)
992 base = 10;
993
994 while (c != WEOF && width != 0)
995 {
996 if (base == 16)
997 {
998 if (!iswxdigit (c))
999 break;
1000 }
1001 else if (!iswdigit (c) || (int) (c - '0') >= base)
1002 {
1003 if (base != 10 || (flags & USE_GROUP) == 0 || c != lc_thousands_sep)
1004 break;
1005 }
1006 if (c != lc_thousands_sep)
1007 {
1008 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1009 wbuf[wbuf_cur_sz++] = c;
1010 }
1011
1012 if (width > 0)
1013 --width;
1014
1015 c = in_ch (s, &read_in);
1016 }
1017
1018 if (!wbuf_cur_sz || (wbuf_cur_sz == 1 && (wbuf[0] == '+' || wbuf[0] == '-')))
1019 {
1020 if (!wbuf_cur_sz && (flags & IS_POINTER) != 0
1021 && match_string (s, &read_in, &c, L"(nil)"))
1022 {
1023 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1024 wbuf[wbuf_cur_sz++] = '0';
1025 }
1026 else
1027 {
1028 back_ch (c, s, &read_in, 0);
1029 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1030 }
1031 }
1032 else
1033 back_ch (c, s, &read_in, 0);
1034
1035 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1036 wbuf[wbuf_cur_sz++] = 0;
1037
1038 if ((flags & IS_LL) != 0)
1039 {
1040 if ((flags & IS_SIGNED_NUM) != 0)
1041 cv_val.ll = wcstoll (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/);
1042 else
1043 cv_val.ull = wcstoull (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/);
1044 }
1045 else
1046 {
1047 if ((flags & IS_SIGNED_NUM) != 0)
1048 cv_val.l = wcstol (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/);
1049 else
1050 cv_val.ul = wcstoul (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/);
1051 }
1052 if (wbuf == tmp_wbuf_ptr)
1053 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1054
1055 if ((flags & IS_SUPPRESSED) == 0)
1056 {
1057 if ((flags & IS_SIGNED_NUM) != 0)
1058 {
1059 if ((flags & IS_LL) != 0)
1060 *(npos != 0 ? (long long *) get_va_nth (argp, npos) : va_arg (arg, long long *)) = cv_val.ll;
1061 else if ((flags & IS_L) != 0)
1062 *(npos != 0 ? (long *) get_va_nth (argp, npos) : va_arg (arg, long *)) = cv_val.l;
1063 else if ((flags & IS_S) != 0)
1064 *(npos != 0 ? (short *) get_va_nth (argp, npos) : va_arg (arg, short *)) = (short) cv_val.l;
1065 else if ((flags & IS_C) != 0)
1066 *(npos != 0 ? (signed char *) get_va_nth (argp, npos) : va_arg (arg, signed char *)) = (signed char) cv_val.ul;
1067 else
1068 *(npos != 0 ? (int *) get_va_nth (argp, npos) : va_arg (arg, int *)) = (int) cv_val.l;
1069 }
1070 else
1071 {
1072 if ((flags & IS_LL) != 0)
1073 *(npos != 0 ? (unsigned long long *) get_va_nth (argp, npos) : va_arg (arg, unsigned long long *)) = cv_val.ull;
1074 else if ((flags & IS_L) != 0)
1075 *(npos != 0 ? (unsigned long *) get_va_nth (argp, npos) : va_arg (arg, unsigned long *)) = cv_val.ul;
1076 else if ((flags & IS_S) != 0)
1077 *(npos != 0 ? (unsigned short *) get_va_nth (argp, npos) : va_arg (arg, unsigned short *))
1078 = (unsigned short) cv_val.ul;
1079 else if ((flags & IS_C) != 0)
1080 *(npos != 0 ? (unsigned char *) get_va_nth (argp, npos) : va_arg (arg, unsigned char *)) = (unsigned char) cv_val.ul;
1081 else
1082 *(npos != 0 ? (unsigned int *) get_va_nth (argp, npos) : va_arg (arg, unsigned int *)) = (unsigned int) cv_val.ul;
1083 }
1084 ++rval;
1085 }
1086 break;
1087
1088 case 'e': case 'E':
1089 case 'f': case 'F':
1090 case 'g': case 'G':
1091 case 'a': case 'A':
1092 if (width > 0)
1093 --width;
1094 if ((c = in_ch (s, &read_in)) == WEOF)
1095 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
1096
1097 seen_dot = seen_exp = 0;
1098 is_neg = (c == '-' ? 1 : 0);
1099
1100 if (c == '-' || c == '+')
1101 {
1102 if (width == 0 || (c = in_ch (s, &read_in)) == WEOF)
1103 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1104 if (width > 0)
1105 --width;
1106 }
1107
1108 if (towlower (c) == 'n')
1109 {
1110 const wchar_t *match_txt = L"nan";
1111
1112 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1113 wbuf[wbuf_cur_sz++] = c;
1114
1115 ++match_txt;
1116 do
1117 {
1118 if (width == 0 || (c = in_ch (s, &read_in)) == WEOF
1119 || towlower (c) != match_txt[0])
1120 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1121 if (width > 0)
1122 --width;
1123
1124 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1125 wbuf[wbuf_cur_sz++] = c;
1126 ++match_txt;
1127 }
1128 while (*match_txt != 0);
1129 }
1130 else if (towlower (c) == 'i')
1131 {
1132 const wchar_t *match_txt = L"inf";
1133
1134 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1135 wbuf[wbuf_cur_sz++] = c;
1136
1137 ++match_txt;
1138 do
1139 {
1140 if (width == 0 || (c = in_ch (s, &read_in)) == WEOF
1141 || towlower (c) != match_txt[0])
1142 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1143 if (width > 0)
1144 --width;
1145
1146 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1147 wbuf[wbuf_cur_sz++] = c;
1148 ++match_txt;
1149 }
1150 while (*match_txt != 0);
1151
1152 if (width != 0 && (c = in_ch (s, &read_in)) != WEOF && towlower (c) == 'i')
1153 {
1154 match_txt = L"inity";
1155 if (width > 0)
1156 --width;
1157
1158 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1159 wbuf[wbuf_cur_sz++] = c;
1160
1161 ++match_txt;
1162 do
1163 {
1164 if (width == 0 || (c = in_ch (s, &read_in)) == WEOF
1165 || towlower (c) != match_txt[0])
1166 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1167 if (width > 0)
1168 --width;
1169 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1170 wbuf[wbuf_cur_sz++] = c;
1171 ++match_txt;
1172 }
1173 while (*match_txt != 0);
1174 }
1175 else if (width != 0 && c != WEOF)
1176 back_ch (c, s, &read_in, 0);
1177 }
1178 else
1179 {
1180 not_in = 'e';
1181 if (width != 0 && c == '0')
1182 {
1183 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1184 wbuf[wbuf_cur_sz++] = c;
1185
1186 c = in_ch (s, &read_in);
1187 if (width > 0)
1188 --width;
1189 if (width != 0 && towlower (c) == 'x')
1190 {
1191 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1192 wbuf[wbuf_cur_sz++] = c;
1193 flags |= IS_HEX_FLOAT;
1194 not_in = 'p';
1195
1196 flags &= ~USE_GROUP;
1197 c = in_ch (s, &read_in);
1198 if (width > 0)
1199 --width;
1200 }
1201 }
1202
1203 while (1)
1204 {
1205 if (iswdigit (c))
1206 {
1207 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1208 wbuf[wbuf_cur_sz++] = c;
1209 }
1210 else if (!seen_exp && (flags & IS_HEX_FLOAT) != 0 && iswxdigit (c))
1211 {
1212 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1213 wbuf[wbuf_cur_sz++] = c;
1214 }
1215 else if (seen_exp && wbuf[wbuf_cur_sz - 1] == not_in
1216 && (c == '-' || c == '+'))
1217 {
1218 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1219 wbuf[wbuf_cur_sz++] = c;
1220 }
1221 else if (wbuf_cur_sz > 0 && !seen_exp
1222 && (wchar_t) towlower (c) == not_in)
1223 {
1224 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1225 wbuf[wbuf_cur_sz++] = not_in;
1226
1227 seen_exp = seen_dot = 1;
1228 }
1229 else
1230 {
1231 if (!seen_dot && c == lc_decimal_point)
1232 {
1233 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1234 wbuf[wbuf_cur_sz++] = c;
1235
1236 seen_dot = 1;
1237 }
1238 else if ((flags & USE_GROUP) != 0 && !seen_dot && c == lc_thousands_sep)
1239 {
1240 /* As our conversion routines aren't supporting thousands
1241 separators, we are filtering them here. */
1242 }
1243 else
1244 {
1245 back_ch (c, s, &read_in, 0);
1246 break;
1247 }
1248 }
1249
1250 if (width == 0 || (c = in_ch (s, &read_in)) == WEOF)
1251 break;
1252
1253 if (width > 0)
1254 --width;
1255 }
1256
1257 if (wbuf_cur_sz == 0 || ((flags & IS_HEX_FLOAT) != 0 && wbuf_cur_sz == 2))
1258 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1259 }
1260
1261 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1262 wbuf[wbuf_cur_sz++] = 0;
1263
1264 if ((flags & IS_LL) != 0)
1265 {
1266 long double d = __mingw_wcstold (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
1267 if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
1268 *(npos != 0 ? (long double *) get_va_nth (argp, npos) : va_arg (arg, long double *)) = is_neg ? -d : d;
1269 }
1270 else if ((flags & IS_L) != 0)
1271 {
1272 double d = __mingw_wcstod (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
1273 if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
1274 *(npos != 0 ? (double *) get_va_nth (argp, npos) : va_arg (arg, double *)) = is_neg ? -d : d;
1275 }
1276 else
1277 {
1278 float d = __mingw_wcstof (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
1279 if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
1280 *(npos != 0 ? (float *) get_va_nth (argp, npos) : va_arg (arg, float *)) = is_neg ? -d : d;
1281 }
1282
1283 if (wbuf == tmp_wbuf_ptr)
1284 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1285
1286 if ((flags & IS_SUPPRESSED) == 0)
1287 ++rval;
1288 break;
1289
1290 case '[':
1291 if ((flags & IS_L) != 0)
1292 {
1293 if ((flags & IS_SUPPRESSED) == 0)
1294 {
1295 if ((flags & IS_ALLOC_USED) != 0)
1296 {
1297 if (npos != 0)
1298 pstr = (char **) get_va_nth (argp, npos);
1299 else
1300 pstr = va_arg (arg, char **);
1301
1302 if (!pstr)
1303 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1304 str_sz = 100;
1305 *pstr = (char *) malloc (100 * sizeof (wchar_t));
1306 if ((wstr = (wchar_t *) *pstr) == NULL)
1307 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
1308
1309 gcollect = resize_gcollect (gcollect);
1310 gcollect->ptrs[gcollect->count++] = pstr;
1311 }
1312 else
1313 {
1314 if (npos != 0)
1315 wstr = (wchar_t *) get_va_nth (argp, npos);
1316 else
1317 wstr = va_arg (arg, wchar_t *);
1318 if (!wstr)
1319 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1320 }
1321 }
1322
1323 }
1324 else if ((flags & IS_SUPPRESSED) == 0)
1325 {
1326 if ((flags & IS_ALLOC_USED) != 0)
1327 {
1328 if (npos != 0)
1329 pstr = (char **) get_va_nth (argp, npos);
1330 else
1331 pstr = va_arg (arg, char **);
1332
1333 if (!pstr)
1334 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1335 str_sz = 100;
1336 if ((str = *pstr = (char *) malloc (100)) == NULL)
1337 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
1338 gcollect = resize_gcollect (gcollect);
1339 gcollect->ptrs[gcollect->count++] = pstr;
1340 }
1341 else
1342 {
1343 if (npos != 0)
1344 str = (char *) get_va_nth (argp, npos);
1345 else
1346 str = va_arg (arg, char *);
1347 if (!str)
1348 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1349 }
1350 }
1351
1352 not_in = (*f == '^' ? 1 : 0);
1353 if (*f == '^')
1354 f++;
1355
1356 if (width < 0)
1357 width = INT_MAX;
1358
1359 tmp_wbuf_ptr = (wchar_t *) f;
1360
1361 if (*f == L']')
1362 ++f;
1363
1364 while ((fc = *f++) != 0 && fc != L']');
1365
1366 if (fc == 0)
1367 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1368 temp_wbuf_end = (wchar_t *) f - 1;
1369
1370 if ((flags & IS_L) != 0)
1371 {
1372 read_in_sv = read_in;
1373
1374 if ((c = in_ch (s, &read_in)) == WEOF)
1375 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
1376
1377 do
1378 {
1379 int ended = 0;
1380 for (wbuf_iter = tmp_wbuf_ptr; wbuf_iter < temp_wbuf_end;)
1381 {
1382 if (wbuf_iter[0] == '-' && wbuf_iter[1] != 0
1383 && (wbuf_iter + 1) != temp_wbuf_end
1384 && wbuf_iter != tmp_wbuf_ptr
1385 && (unsigned int) wbuf_iter[-1] <= (unsigned int) wbuf_iter[1])
1386 {
1387 for (wc = wbuf_iter[-1] + 1; wc <= wbuf_iter[1] && (wint_t) wc != c; ++wc);
1388
1389 if (wc <= wbuf_iter[1] && !not_in)
1390 break;
1391 if (wc <= wbuf_iter[1] && not_in)
1392 {
1393 back_ch (c, s, &read_in, 0);
1394 ended = 1;
1395 break;
1396 }
1397
1398 wbuf_iter += 2;
1399 }
1400 else
1401 {
1402 if ((wint_t) *wbuf_iter == c && !not_in)
1403 break;
1404 if ((wint_t) *wbuf_iter == c && not_in)
1405 {
1406 back_ch (c, s, &read_in, 0);
1407 ended = 1;
1408 break;
1409 }
1410
1411 ++wbuf_iter;
1412 }
1413 }
1414 if (ended)
1415 break;
1416
1417 if (wbuf_iter == temp_wbuf_end && !not_in)
1418 {
1419 back_ch (c, s, &read_in, 0);
1420 break;
1421 }
1422
1423 if ((flags & IS_SUPPRESSED) == 0)
1424 {
1425 *wstr++ = c;
1426
1427 if ((flags & IS_ALLOC_USED) != 0
1428 && wstr == ((wchar_t *) *pstr + str_sz))
1429 {
1430 new_sz = str_sz * 2;
1431 while ((wstr = (wchar_t *) realloc (*pstr,
1432 new_sz * sizeof (wchar_t))) == NULL
1433 && new_sz > (size_t) (str_sz + 1))
1434 new_sz = str_sz + 1;
1435 if (!wstr)
1436 {
1437 if ((flags & USE_POSIX_ALLOC) == 0)
1438 {
1439 ((wchar_t *) (*pstr))[str_sz - 1] = 0;
1440 pstr = NULL;
1441 ++rval;
1442 }
1443 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
1444 }
1445 *pstr = (char *) wstr;
1446 wstr += str_sz;
1447 str_sz = new_sz;
1448 }
1449 }
1450 }
1451 while (--width > 0 && (c = in_ch (s, &read_in)) != WEOF);
1452
1453 if (read_in_sv == read_in)
1454 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1455
1456 if ((flags & IS_SUPPRESSED) == 0)
1457 {
1458 *wstr++ = 0;
1459
1460 optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t));
1461 pstr = NULL;
1462 ++rval;
1463 }
1464 }
1465 else
1466 {
1467 read_in_sv = read_in;
1468
1469 if ((c = in_ch (s, &read_in)) == WEOF)
1470 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
1471
1472 memset (&state, 0, sizeof (state));
1473
1474 do
1475 {
1476 int ended = 0;
1477 wbuf_iter = tmp_wbuf_ptr;
1478 while (wbuf_iter < temp_wbuf_end)
1479 {
1480 if (wbuf_iter[0] == '-' && wbuf_iter[1] != 0
1481 && (wbuf_iter + 1) != temp_wbuf_end
1482 && wbuf_iter != tmp_wbuf_ptr
1483 && (unsigned int) wbuf_iter[-1] <= (unsigned int) wbuf_iter[1])
1484 {
1485 for (wc = wbuf_iter[-1] + 1; wc <= wbuf_iter[1] && (wint_t) wc != c; ++wc);
1486
1487 if (wc <= wbuf_iter[1] && !not_in)
1488 break;
1489 if (wc <= wbuf_iter[1] && not_in)
1490 {
1491 back_ch (c, s, &read_in, 0);
1492 ended = 1;
1493 break;
1494 }
1495
1496 wbuf_iter += 2;
1497 }
1498 else
1499 {
1500 if ((wint_t) *wbuf_iter == c && !not_in)
1501 break;
1502 if ((wint_t) *wbuf_iter == c && not_in)
1503 {
1504 back_ch (c, s, &read_in, 0);
1505 ended = 1;
1506 break;
1507 }
1508
1509 ++wbuf_iter;
1510 }
1511 }
1512
1513 if (ended)
1514 break;
1515 if (wbuf_iter == temp_wbuf_end && !not_in)
1516 {
1517 back_ch (c, s, &read_in, 0);
1518 break;
1519 }
1520
1521 if ((flags & IS_SUPPRESSED) == 0)
1522 {
1523 if ((flags & IS_ALLOC_USED) != 0
1524 && (str + MB_CUR_MAX) >= (*pstr + str_sz))
1525 {
1526 new_sz = str_sz * 2;
1527 str_len = (str - *pstr);
1528
1529 while ((nstr = (char *) realloc (*pstr, new_sz)) == NULL
1530 && new_sz > (str_len + MB_CUR_MAX))
1531 new_sz = str_len + MB_CUR_MAX;
1532 if (!nstr)
1533 {
1534 if ((flags & USE_POSIX_ALLOC) == 0)
1535 {
1536 ((*pstr))[str_len] = 0;
1537 pstr = NULL;
1538 ++rval;
1539 }
1540 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
1541 }
1542 *pstr = nstr;
1543 str = nstr + str_len;
1544 str_sz = new_sz;
1545 }
1546 }
1547
1548 n = wcrtomb ((flags & IS_SUPPRESSED) == 0 ? str : NULL, c, &state);
1549 if (n == (size_t) -1LL)
1550 {
1551 errno = EILSEQ;
1552 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1553 }
1554
1555 str += n;
1556 }
1557 while (--width > 0 && (c = in_ch (s, &read_in)) != WEOF);
1558
1559 if (read_in_sv == read_in)
1560 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1561
1562 if ((flags & IS_SUPPRESSED) == 0)
1563 {
1564 n = wcrtomb (buf, 0, &state);
1565 if (n > 0 && (flags & IS_ALLOC_USED) != 0
1566 && (str + n) >= (*pstr + str_sz))
1567 {
1568 str_len = (str - *pstr);
1569
1570 if ((nstr = (char *) realloc (*pstr, str_len + n + 1)) == NULL)
1571 {
1572 if ((flags & USE_POSIX_ALLOC) == 0)
1573 {
1574 (*pstr)[str_len] = 0;
1575 pstr = NULL;
1576 ++rval;
1577 }
1578 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
1579 }
1580 *pstr = nstr;
1581 str = nstr + str_len;
1582 str_sz = str_len + n + 1;
1583 }
1584
1585 if (n)
1586 {
1587 memcpy (str, buf, n);
1588 str += n;
1589 }
1590 *str++ = 0;
1591
1592 optimize_alloc (pstr, str, str_sz);
1593 pstr = NULL;
1594 ++rval;
1595 }
1596 }
1597 break;
1598
1599 default:
1600 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1601 }
1602 }
1603
1604 if (ignore_ws)
1605 {
1606 while (iswspace ((c = in_ch (s, &read_in))));
1607 back_ch (c, s, &read_in, 0);
1608 }
1609
1610 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1611}
1612
1613int
1614__mingw_vfwscanf (FILE *s, const wchar_t *format, va_list argp)
1615{
1616 _IFP ifp;
1617 memset (&ifp, 0, sizeof (_IFP));
1618 ifp.fp = s;
1619 return __mingw_swformat (&ifp, format, argp);
1620}
1621
1622int
1623__mingw_vswscanf (const wchar_t *s, const wchar_t *format, va_list argp)
1624{
1625 _IFP ifp;
1626 memset (&ifp, 0, sizeof (_IFP));
1627 ifp.str = s;
1628 ifp.is_string = 1;
1629 return __mingw_swformat (&ifp, format, argp);
1630}
1631