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