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