~mingw-w64/mingw-w64/experimental

« back to all changes in this revision

Viewing changes to ros-privexp/mingw-w64-crt/stdio/mingw_pformat.c

  • Committer: NightStrike
  • Date: 2010-08-11 22:20:57 UTC
  • Revision ID: svn-v4:4407c894-4637-0410-b4f5-ada5f102cad1:experimental:3266
Branch for adding option for supporting ros

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* FIXME: to be removed one day; for now we explicitly are not
 
2
 * prepared to support the POSIX-XSI additions to the C99 standard.
 
3
 */
 
4
#undef   WITH_XSI_FEATURES
 
5
 
 
6
/* pformat.c
 
7
 *
 
8
 * $Id: pformat.c,v 1.4 2008/12/31 15:34:09 keithmarshall Exp $
 
9
 *
 
10
 * Provides a core implementation of the formatting capabilities
 
11
 * common to the entire `printf()' family of functions; it conforms
 
12
 * generally to C99 and SUSv3/POSIX specifications, with extensions
 
13
 * to support Microsoft's non-standard format specifications.
 
14
 *
 
15
 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
 
16
 *
 
17
 * This is free software.  You may redistribute and/or modify it as you
 
18
 * see fit, without restriction of copyright.
 
19
 *
 
20
 * This software is provided "as is", in the hope that it may be useful,
 
21
 * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
 
22
 * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE.  At no
 
23
 * time will the author accept any form of liability for any damages,
 
24
 * however caused, resulting from the use of this software.
 
25
 *
 
26
 * The elements of this implementation which deal with the formatting
 
27
 * of floating point numbers, (i.e. the `%e', `%E', `%f', `%F', `%g'
 
28
 * and `%G' format specifiers, but excluding the hexadecimal floating
 
29
 * point `%a' and `%A' specifiers), make use of the `__gdtoa' function
 
30
 * written by David M. Gay, and are modelled on his sample code, which
 
31
 * has been deployed under its accompanying terms of use:--
 
32
 *
 
33
 ******************************************************************
 
34
 * Copyright (C) 1997, 1999, 2001 Lucent Technologies
 
35
 * All Rights Reserved
 
36
 *
 
37
 * Permission to use, copy, modify, and distribute this software and
 
38
 * its documentation for any purpose and without fee is hereby
 
39
 * granted, provided that the above copyright notice appear in all
 
40
 * copies and that both that the copyright notice and this
 
41
 * permission notice and warranty disclaimer appear in supporting
 
42
 * documentation, and that the name of Lucent or any of its entities
 
43
 * not be used in advertising or publicity pertaining to
 
44
 * distribution of the software without specific, written prior
 
45
 * permission.
 
46
 *
 
47
 * LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 
48
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
 
49
 * IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
 
50
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
51
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 
52
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 
53
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 
54
 * THIS SOFTWARE.
 
55
 ******************************************************************
 
56
 *
 
57
 */
 
58
#include <stdio.h>
 
59
#include <stdarg.h>
 
60
#include <stddef.h>
 
61
#include <stdint.h>
 
62
#include <stdlib.h>
 
63
#include <string.h>
 
64
#include <limits.h>
 
65
#include <locale.h>
 
66
#include <wchar.h>
 
67
#include <math.h>
 
68
 
 
69
/* FIXME: The following belongs in values.h, but current MinGW
 
70
 * has nothing useful there!  OTOH, values.h is not a standard
 
71
 * header, and it's use may be considered obsolete; perhaps it
 
72
 * is better to just keep these definitions here.
 
73
 */
 
74
#ifndef _VALUES_H
 
75
/*
 
76
 * values.h
 
77
 *
 
78
 */
 
79
#define _VALUES_H
 
80
 
 
81
#include <limits.h>
 
82
 
 
83
#define _TYPEBITS(type)     (sizeof(type) * CHAR_BIT)
 
84
 
 
85
#define LLONGBITS           _TYPEBITS(long long)
 
86
 
 
87
#endif /* !defined _VALUES_H -- end of file */
 
88
 
 
89
#include "mingw_pformat.h"
 
90
 
 
91
/* Bit-map constants, defining the internal format control
 
92
 * states, which propagate through the flags.
 
93
 */
 
94
#define PFORMAT_HASHED      0x0800
 
95
#define PFORMAT_LJUSTIFY    0x0400
 
96
#define PFORMAT_ZEROFILL    0x0200
 
97
 
 
98
#define PFORMAT_JUSTIFY    (PFORMAT_LJUSTIFY | PFORMAT_ZEROFILL)
 
99
#define PFORMAT_IGNORE      -1
 
100
 
 
101
#define PFORMAT_SIGNED      0x01C0
 
102
#define PFORMAT_POSITIVE    0x0100
 
103
#define PFORMAT_NEGATIVE    0x0080
 
104
#define PFORMAT_ADDSPACE    0x0040
 
105
 
 
106
#define PFORMAT_XCASE       0x0020
 
107
 
 
108
#define PFORMAT_LDOUBLE     0x0004
 
109
 
 
110
/* `%o' format digit extraction mask, and shift count...
 
111
 * (These are constant, and do not propagate through the flags).
 
112
 */
 
113
#define PFORMAT_OMASK       0x0007
 
114
#define PFORMAT_OSHIFT      0x0003
 
115
 
 
116
/* `%x' and `%X' format digit extraction mask, and shift count...
 
117
 * (These are constant, and do not propagate through the flags).
 
118
 */
 
119
#define PFORMAT_XMASK       0x000F
 
120
#define PFORMAT_XSHIFT      0x0004
 
121
 
 
122
/* The radix point character, used in floating point formats, is
 
123
 * localised on the basis of the active LC_NUMERIC locale category.
 
124
 * It is stored locally, as a `wchar_t' entity, which is converted
 
125
 * to a (possibly multibyte) character on output.  Initialisation
 
126
 * of the stored `wchar_t' entity, together with a record of its
 
127
 * effective multibyte character length, is required each time
 
128
 * `__pformat()' is entered, (static storage would not be thread
 
129
 * safe), but this initialisation is deferred until it is actually
 
130
 * needed; on entry, the effective character length is first set to
 
131
 * the following value, (and the `wchar_t' entity is zeroed), to
 
132
 * indicate that a call of `localeconv()' is needed, to complete
 
133
 * the initialisation.
 
134
 */
 
135
#define PFORMAT_RPINIT      -3
 
136
 
 
137
/* The floating point format handlers return the following value
 
138
 * for the radix point position index, when the argument value is
 
139
 * infinite, or not a number.
 
140
 */
 
141
#define PFORMAT_INFNAN      -32768
 
142
 
 
143
#ifdef _WIN32
 
144
/*
 
145
 * The Microsoft standard for printing `%e' format exponents is
 
146
 * with a minimum of three digits, unless explicitly set otherwise,
 
147
 * by a prior invocation of the `_set_output_format()' function.
 
148
 *
 
149
 * The following macro allows us to replicate this behaviour.
 
150
 */
 
151
# define PFORMAT_MINEXP    __pformat_exponent_digits()
 
152
 /*
 
153
  * However, this feature is unsupported for versions of the
 
154
  * MSVC runtime library prior to msvcr80.dll, and by default,
 
155
  * MinGW uses an earlier version, (equivalent to msvcr60.dll),
 
156
  * for which `_TWO_DIGIT_EXPONENT' will be undefined.
 
157
  */
 
158
# ifndef _TWO_DIGIT_EXPONENT
 
159
#  define _TWO_DIGIT_EXPONENT   1
 
160
# endif
 
161
/*
 
162
 * Irrespective of the MSVCRT version supported, *we* will add
 
163
 * an additional capability, through the following inline function,
 
164
 * which will allow the user to choose his own preferred default
 
165
 * for `PRINTF_EXPONENT_DIGITS', through the simple expedient
 
166
 * of defining it as an environment variable.
 
167
 */
 
168
static __inline__ __attribute__((__always_inline__))
 
169
int __pformat_exponent_digits( void )
 
170
{
 
171
  char *exponent_digits = getenv( "PRINTF_EXPONENT_DIGITS" );
 
172
  return ((exponent_digits != NULL) && ((unsigned)(*exponent_digits - '0') < 3))
 
173
    || (_get_output_format() & _TWO_DIGIT_EXPONENT)
 
174
    ? 2
 
175
    : 3
 
176
    ;
 
177
}
 
178
#else
 
179
/*
 
180
 * When we don't care to mimic Microsoft's standard behaviour,
 
181
 * we adopt the C99/POSIX standard of two digit exponents.
 
182
 */
 
183
# define PFORMAT_MINEXP         2
 
184
#endif
 
185
 
 
186
typedef union
 
187
{
 
188
  /* A data type agnostic representation,
 
189
   * for printf arguments of any integral data type...
 
190
   */
 
191
  signed long             __pformat_long_t;
 
192
  signed long long        __pformat_llong_t;
 
193
  unsigned long           __pformat_ulong_t;
 
194
  unsigned long long      __pformat_ullong_t;
 
195
  unsigned short          __pformat_ushort_t;
 
196
  unsigned char           __pformat_uchar_t;
 
197
  signed short            __pformat_short_t;
 
198
  signed char             __pformat_char_t;
 
199
  void *                  __pformat_ptr_t;
 
200
} __pformat_intarg_t;
 
201
 
 
202
typedef enum
 
203
{
 
204
  /* Format interpreter state indices...
 
205
   * (used to identify the active phase of format string parsing).
 
206
   */
 
207
  PFORMAT_INIT = 0,
 
208
  PFORMAT_SET_WIDTH,
 
209
  PFORMAT_GET_PRECISION,
 
210
  PFORMAT_SET_PRECISION,
 
211
  PFORMAT_END
 
212
} __pformat_state_t;
 
213
      
 
214
typedef enum
 
215
{
 
216
  /* Argument length classification indices...
 
217
   * (used for arguments representing integer data types).
 
218
   */
 
219
  PFORMAT_LENGTH_INT = 0,
 
220
  PFORMAT_LENGTH_SHORT,
 
221
  PFORMAT_LENGTH_LONG,
 
222
  PFORMAT_LENGTH_LLONG,
 
223
  PFORMAT_LENGTH_CHAR
 
224
} __pformat_length_t;
 
225
/*
 
226
 * And a macro to map any arbitrary data type to an appropriate
 
227
 * matching index, selected from those above; the compiler should
 
228
 * collapse this to a simple assignment.
 
229
 */
 
230
#define __pformat_arg_length( type )    \
 
231
  sizeof( type ) == sizeof( long long ) ? PFORMAT_LENGTH_LLONG : \
 
232
  sizeof( type ) == sizeof( long )      ? PFORMAT_LENGTH_LONG  : \
 
233
  sizeof( type ) == sizeof( short )     ? PFORMAT_LENGTH_SHORT : \
 
234
  sizeof( type ) == sizeof( char )      ? PFORMAT_LENGTH_CHAR  : \
 
235
  /* should never need this default */    PFORMAT_LENGTH_INT
 
236
 
 
237
typedef struct
 
238
{
 
239
  /* Formatting and output control data...
 
240
   * An instance of this control block is created, (on the stack),
 
241
   * for each call to `__pformat()', and is passed by reference to
 
242
   * each of the output handlers, as required.
 
243
   */
 
244
  void *         dest;
 
245
  int            flags;
 
246
  int            width;
 
247
  int            precision;
 
248
  int            rplen;
 
249
  wchar_t        rpchr;
 
250
  int            count;
 
251
  int            quota;
 
252
  int            expmin;
 
253
} __pformat_t;
 
254
 
 
255
static
 
256
void __pformat_putc( int c, __pformat_t *stream )
 
257
{
 
258
  /* Place a single character into the `__pformat()' output queue,
 
259
   * provided any specified output quota has not been exceeded.
 
260
   */
 
261
  if( (stream->flags & PFORMAT_NOLIMIT) || (stream->quota > stream->count) )
 
262
  {
 
263
    /* Either there was no quota specified,
 
264
     * or the active quota has not yet been reached.
 
265
     */
 
266
    if( stream->flags & PFORMAT_TO_FILE )
 
267
      /*
 
268
       * This is single character output to a FILE stream...
 
269
       */
 
270
      fputc( c, (FILE *)(stream->dest) );
 
271
 
 
272
    else
 
273
      /* Whereas, this is to an internal memory buffer...
 
274
       */
 
275
      ((char *)(stream->dest))[stream->count] = c;
 
276
  }
 
277
  ++stream->count;
 
278
}
 
279
 
 
280
static
 
281
void __pformat_putchars( const char *s, int count, __pformat_t *stream )
 
282
{
 
283
  /* Handler for `%c' and (indirectly) `%s' conversion specifications.
 
284
   *
 
285
   * Transfer characters from the string buffer at `s', character by
 
286
   * character, up to the number of characters specified by `count', or
 
287
   * if `precision' has been explicitly set to a value less than `count',
 
288
   * stopping after the number of characters specified for `precision',
 
289
   * to the `__pformat()' output stream.
 
290
   *
 
291
   * Characters to be emitted are passed through `__pformat_putc()', to
 
292
   * ensure that any specified output quota is honoured.
 
293
   */
 
294
  if( (stream->precision >= 0) && (count > stream->precision) )
 
295
    /*
 
296
     * Ensure that the maximum number of characters transferred doesn't
 
297
     * exceed any explicitly set `precision' specification.
 
298
     */
 
299
    count = stream->precision;
 
300
 
 
301
  /* Establish the width of any field padding required...
 
302
   */
 
303
  if( stream->width > count )
 
304
    /*
 
305
     * as the number of spaces equivalent to the number of characters
 
306
     * by which those to be emitted is fewer than the field width...
 
307
     */
 
308
    stream->width -= count;
 
309
 
 
310
  else
 
311
    /* ignoring any width specification which is insufficient.
 
312
     */
 
313
    stream->width = PFORMAT_IGNORE;
 
314
 
 
315
  if( (stream->width > 0) && ((stream->flags & PFORMAT_LJUSTIFY) == 0) )
 
316
    /*
 
317
     * When not doing flush left justification, (i.e. the `-' flag
 
318
     * is not set), any residual unreserved field width must appear
 
319
     * as blank padding, to the left of the output string.
 
320
     */
 
321
    while( stream->width-- )
 
322
      __pformat_putc( '\x20', stream );
 
323
 
 
324
  /* Emit the data...
 
325
   */
 
326
  while( count-- )
 
327
    /*
 
328
     * copying the requisite number of characters from the input.
 
329
     */
 
330
    __pformat_putc( *s++, stream );
 
331
 
 
332
  /* If we still haven't consumed the entire specified field width,
 
333
   * we must be doing flush left justification; any residual width
 
334
   * must be filled with blanks, to the right of the output value.
 
335
   */
 
336
  while( stream->width-- > 0 )
 
337
    __pformat_putc( '\x20', stream );
 
338
}
 
339
 
 
340
static __inline__
 
341
void __pformat_puts( const char *s, __pformat_t *stream )
 
342
{
 
343
  /* Handler for `%s' conversion specifications.
 
344
   *
 
345
   * Transfer a NUL terminated character string, character by character,
 
346
   * stopping when the end of the string is encountered, or if `precision'
 
347
   * has been explicitly set, when the specified number of characters has
 
348
   * been emitted, if that is less than the length of the input string,
 
349
   * to the `__pformat()' output stream.
 
350
   *
 
351
   * This is implemented as a trivial call to `__pformat_putchars()',
 
352
   * passing the length of the input string as the character count,
 
353
   * (after first verifying that the input pointer is not NULL).
 
354
   */
 
355
  if( s == NULL ) s = "(null)";
 
356
  __pformat_putchars( s, strlen( s ), stream );
 
357
}
 
358
 
 
359
static
 
360
void __pformat_wputchars( const wchar_t *s, int count, __pformat_t *stream )
 
361
{
 
362
  /* Handler for `%C'(`%lc') and `%S'(`%ls') conversion specifications;
 
363
   * (this is a wide character variant of `__pformat_putchars()').
 
364
   *
 
365
   * Each multibyte character sequence to be emitted is passed, byte
 
366
   * by byte, through `__pformat_putc()', to ensure that any specified
 
367
   * output quota is honoured.
 
368
   */
 
369
  char buf[16]; mbstate_t state; int len = wcrtomb( buf, L'\0', &state );
 
370
 
 
371
  if( (stream->precision >= 0) && (count > stream->precision) )
 
372
    /*
 
373
     * Ensure that the maximum number of characters transferred doesn't
 
374
     * exceed any explicitly set `precision' specification.
 
375
     */
 
376
    count = stream->precision;
 
377
 
 
378
  /* Establish the width of any field padding required...
 
379
   */
 
380
  if( stream->width > count )
 
381
    /*
 
382
     * as the number of spaces equivalent to the number of characters
 
383
     * by which those to be emitted is fewer than the field width...
 
384
     */
 
385
    stream->width -= count;
 
386
 
 
387
  else
 
388
    /* ignoring any width specification which is insufficient.
 
389
     */
 
390
    stream->width = PFORMAT_IGNORE;
 
391
 
 
392
  if( (stream->width > 0) && ((stream->flags & PFORMAT_LJUSTIFY) == 0) )
 
393
    /*
 
394
     * When not doing flush left justification, (i.e. the `-' flag
 
395
     * is not set), any residual unreserved field width must appear
 
396
     * as blank padding, to the left of the output string.
 
397
     */
 
398
    while( stream->width-- )
 
399
      __pformat_putc( '\x20', stream );
 
400
 
 
401
  /* Emit the data, converting each character from the wide
 
402
   * to the multibyte domain as we go...
 
403
   */
 
404
  while( (count-- > 0) && ((len = wcrtomb( buf, *s++, &state )) > 0) )
 
405
  {
 
406
    char *p = buf;
 
407
    while( len-- > 0 )
 
408
      __pformat_putc( *p++, stream );
 
409
  }
 
410
 
 
411
  /* If we still haven't consumed the entire specified field width,
 
412
   * we must be doing flush left justification; any residual width
 
413
   * must be filled with blanks, to the right of the output value.
 
414
   */
 
415
  while( stream->width-- > 0 )
 
416
    __pformat_putc( '\x20', stream );
 
417
}
 
418
 
 
419
static __inline__ __attribute__((__always_inline__))
 
420
void __pformat_wcputs( const wchar_t *s, __pformat_t *stream )
 
421
{
 
422
  /* Handler for `%S' (`%ls') conversion specifications.
 
423
   *
 
424
   * Transfer a NUL terminated wide character string, character by
 
425
   * character, converting to its equivalent multibyte representation
 
426
   * on output, and stopping when the end of the string is encountered,
 
427
   * or if `precision' has been explicitly set, when the specified number
 
428
   * of characters has been emitted, if that is less than the length of
 
429
   * the input string, to the `__pformat()' output stream.
 
430
   *
 
431
   * This is implemented as a trivial call to `__pformat_wputchars()',
 
432
   * passing the length of the input string as the character count,
 
433
   * (after first verifying that the input pointer is not NULL).
 
434
   */
 
435
  if( s == NULL ) s = L"(null)";
 
436
  __pformat_wputchars( s, wcslen( s ), stream );
 
437
}
 
438
 
 
439
static __inline__
 
440
int __pformat_int_bufsiz( int bias, int size, __pformat_t *stream )
 
441
{
 
442
  /* Helper to establish the size of the internal buffer, which
 
443
   * is required to queue the ASCII decomposition of an integral
 
444
   * data value, prior to transfer to the output stream.
 
445
   */
 
446
  size = ((size - 1 + LLONGBITS) / size) + bias;
 
447
  size += (stream->precision > 0) ? stream->precision : 0;
 
448
  return (size > stream->width) ? size : stream->width;
 
449
}
 
450
 
 
451
static
 
452
void __pformat_int( __pformat_intarg_t value, __pformat_t *stream )
 
453
{
 
454
  /* Handler for `%d', `%i' and `%u' conversion specifications.
 
455
   *
 
456
   * Transfer the ASCII representation of an integer value parameter,
 
457
   * formatted as a decimal number, to the `__pformat()' output queue;
 
458
   * output will be truncated, if any specified quota is exceeded.
 
459
   */
 
460
  char buf[__pformat_int_bufsiz(1, PFORMAT_OSHIFT, stream)];
 
461
  char *p = buf; int precision;
 
462
 
 
463
  if( stream->flags & PFORMAT_NEGATIVE )
 
464
  {
 
465
    /* The input value might be negative, (i.e. it is a signed value)...
 
466
     */
 
467
    if( value.__pformat_llong_t < 0LL )
 
468
      /*
 
469
       * It IS negative, but we want to encode it as unsigned,
 
470
       * displayed with a leading minus sign, so convert it...
 
471
       */
 
472
      value.__pformat_llong_t = -value.__pformat_llong_t;
 
473
 
 
474
    else
 
475
      /* It is unequivocally a POSITIVE value, so turn off the
 
476
       * request to prefix it with a minus sign...
 
477
       */
 
478
      stream->flags &= ~PFORMAT_NEGATIVE;
 
479
  }
 
480
 
 
481
  /* Encode the input value for display...
 
482
   */
 
483
  while( value.__pformat_ullong_t )
 
484
  {
 
485
    /* decomposing it into its constituent decimal digits,
 
486
     * in order from least significant to most significant, using
 
487
     * the local buffer as a LIFO queue in which to store them. 
 
488
     */
 
489
    *p++ = '0' + (unsigned char)(value.__pformat_ullong_t % 10LL);
 
490
    value.__pformat_ullong_t /= 10LL;
 
491
  }
 
492
 
 
493
  if(  (stream->precision > 0)
 
494
  &&  ((precision = stream->precision - (p - buf)) > 0)  )
 
495
    /*
 
496
     * We have not yet queued sufficient digits to fill the field width
 
497
     * specified for minimum `precision'; pad with zeros to achieve this.
 
498
     */
 
499
    while( precision-- > 0 )
 
500
      *p++ = '0';
 
501
 
 
502
  if( (p == buf) && (stream->precision != 0) )
 
503
    /*
 
504
     * Input value was zero; make sure we print at least one digit,
 
505
     * unless the precision is also explicitly zero.
 
506
     */
 
507
    *p++ = '0';
 
508
 
 
509
  if( (stream->width > 0) && ((stream->width -= p - buf) > 0) )
 
510
  {
 
511
    /* We have now queued sufficient characters to display the input value,
 
512
     * at the desired precision, but this will not fill the output field...
 
513
     */
 
514
    if( stream->flags & PFORMAT_SIGNED )
 
515
      /*
 
516
       * We will fill one additional space with a sign...
 
517
       */
 
518
      stream->width--;
 
519
 
 
520
    if(  (stream->precision < 0)
 
521
    &&  ((stream->flags & PFORMAT_JUSTIFY) == PFORMAT_ZEROFILL)  )
 
522
      /*
 
523
       * and the `0' flag is in effect, so we pad the remaining spaces,
 
524
       * to the left of the displayed value, with zeros.
 
525
       */
 
526
      while( stream->width-- > 0 )
 
527
        *p++ = '0';
 
528
 
 
529
    else if( (stream->flags & PFORMAT_LJUSTIFY) == 0 )
 
530
      /*
 
531
       * the `0' flag is not in effect, and neither is the `-' flag,
 
532
       * so we pad to the left of the displayed value with spaces, so that
 
533
       * the value appears right justified within the output field.
 
534
       */
 
535
      while( stream->width-- > 0 )
 
536
        __pformat_putc( '\x20', stream );
 
537
  }
 
538
 
 
539
  if( stream->flags & PFORMAT_NEGATIVE )
 
540
    /*
 
541
     * A negative value needs a sign...
 
542
     */
 
543
    *p++ = '-';
 
544
 
 
545
  else if( stream->flags & PFORMAT_POSITIVE )
 
546
    /*
 
547
     * A positive value may have an optionally displayed sign...
 
548
     */
 
549
    *p++ = '+';
 
550
 
 
551
  else if( stream->flags & PFORMAT_ADDSPACE )
 
552
    /*
 
553
     * Space was reserved for displaying a sign, but none was emitted...
 
554
     */
 
555
    *p++ = '\x20';
 
556
 
 
557
  while( p > buf )
 
558
    /*
 
559
     * Emit the accumulated constituent digits,
 
560
     * in order from most significant to least significant...
 
561
     */
 
562
    __pformat_putc( *--p, stream );
 
563
 
 
564
  while( stream->width-- > 0 )
 
565
    /*
 
566
     * The specified output field has not yet been completely filled;
 
567
     * the `-' flag must be in effect, resulting in a displayed value which
 
568
     * appears left justified within the output field; we must pad the field
 
569
     * to the right of the displayed value, by emitting additional spaces,
 
570
     * until we reach the rightmost field boundary.
 
571
     */
 
572
    __pformat_putc( '\x20', stream );
 
573
}
 
574
 
 
575
static
 
576
void __pformat_xint( int fmt, __pformat_intarg_t value, __pformat_t *stream )
 
577
{
 
578
  /* Handler for `%o', `%p', `%x' and `%X' conversions.
 
579
   *
 
580
   * These can be implemented using a simple `mask and shift' strategy;
 
581
   * set up the mask and shift values appropriate to the conversion format,
 
582
   * and allocate a suitably sized local buffer, in which to queue encoded
 
583
   * digits of the formatted value, in preparation for output.
 
584
   */
 
585
  int width;
 
586
  int mask = (fmt == 'o') ? PFORMAT_OMASK : PFORMAT_XMASK;
 
587
  int shift = (fmt == 'o') ? PFORMAT_OSHIFT : PFORMAT_XSHIFT;
 
588
  char buf[__pformat_int_bufsiz(2, shift, stream)];
 
589
  char *p = buf;
 
590
 
 
591
  while( value.__pformat_ullong_t )
 
592
  {
 
593
    /* Encode the specified non-zero input value as a sequence of digits,
 
594
     * in the appropriate `base' encoding and in reverse digit order, each
 
595
     * encoded in its printable ASCII form, with no leading zeros, using
 
596
     * the local buffer as a LIFO queue in which to store them.
 
597
     */
 
598
    char *q;
 
599
    if( (*(q = p++) = '0' + (value.__pformat_ullong_t & mask)) > '9' )
 
600
      *q = (*q + 'A' - '9' - 1) | (fmt & PFORMAT_XCASE);
 
601
    value.__pformat_ullong_t >>= shift;
 
602
  }
 
603
 
 
604
  if( p == buf )
 
605
    /*
 
606
     * Nothing was queued; input value must be zero, which should never be
 
607
     * emitted in the `alternative' PFORMAT_HASHED style.
 
608
     */
 
609
    stream->flags &= ~PFORMAT_HASHED;
 
610
 
 
611
  if( ((width = stream->precision) > 0) && ((width -= p - buf) > 0) )
 
612
    /*
 
613
     * We have not yet queued sufficient digits to fill the field width
 
614
     * specified for minimum `precision'; pad with zeros to achieve this.
 
615
     */
 
616
    while( width-- > 0 )
 
617
      *p++ = '0';
 
618
  
 
619
  else if( (fmt == 'o') && (stream->flags & PFORMAT_HASHED) )
 
620
    /*
 
621
     * The field width specified for minimum `precision' has already
 
622
     * been filled, but the `alternative' PFORMAT_HASHED style for octal
 
623
     * output requires at least one initial zero; that will not have
 
624
     * been queued, so add it now.
 
625
     */
 
626
    *p++ = '0';
 
627
 
 
628
  if( (p == buf) && (stream->precision != 0) )
 
629
    /*
 
630
     * Still nothing queued for output, but the `precision' has not been
 
631
     * explicitly specified as zero, (which is necessary if no output for
 
632
     * an input value of zero is desired); queue exactly one zero digit.
 
633
     */
 
634
    *p++ = '0';
 
635
 
 
636
  if( stream->width > (width = p - buf) )
 
637
    /*
 
638
     * Specified field width exceeds the minimum required...
 
639
     * Adjust so that we retain only the additional padding width.
 
640
     */
 
641
    stream->width -= width;
 
642
 
 
643
  else
 
644
    /* Ignore any width specification which is insufficient.
 
645
     */
 
646
    stream->width = PFORMAT_IGNORE;
 
647
 
 
648
  if( ((width = stream->width) > 0)
 
649
  &&  (fmt != 'o') && (stream->flags & PFORMAT_HASHED)  )
 
650
    /*
 
651
     * For `%#x' or `%#X' formats, (which have the `#' flag set),
 
652
     * further reduce the padding width to accommodate the radix
 
653
     * indicating prefix.
 
654
     */
 
655
    width -= 2;
 
656
 
 
657
  if(  (width > 0) && (stream->precision < 0)
 
658
  &&  ((stream->flags & PFORMAT_JUSTIFY) == PFORMAT_ZEROFILL)  )
 
659
    /*
 
660
     * When the `0' flag is set, and not overridden by the `-' flag,
 
661
     * or by a specified precision, add sufficient leading zeros to
 
662
     * consume the remaining field width.
 
663
     */
 
664
    while( width-- > 0 )
 
665
      *p++ = '0';
 
666
 
 
667
  if( (fmt != 'o') && (stream->flags & PFORMAT_HASHED) )
 
668
  {
 
669
    /* For formats other than octal, the PFORMAT_HASHED output style
 
670
     * requires the addition of a two character radix indicator, as a
 
671
     * prefix to the actual encoded numeric value.
 
672
     */
 
673
    *p++ = fmt;
 
674
    *p++ = '0';
 
675
  }
 
676
 
 
677
  if( (width > 0) && ((stream->flags & PFORMAT_LJUSTIFY) == 0) )
 
678
    /*
 
679
     * When not doing flush left justification, (i.e. the `-' flag
 
680
     * is not set), any residual unreserved field width must appear
 
681
     * as blank padding, to the left of the output value.
 
682
     */
 
683
    while( width-- > 0 )
 
684
      __pformat_putc( '\x20', stream );
 
685
 
 
686
  while( p > buf )
 
687
    /*
 
688
     * Move the queued output from the local buffer to the ultimate
 
689
     * destination, in LIFO order.
 
690
     */
 
691
    __pformat_putc( *--p, stream );
 
692
 
 
693
  /* If we still haven't consumed the entire specified field width,
 
694
   * we must be doing flush left justification; any residual width
 
695
   * must be filled with blanks, to the right of the output value.
 
696
   */
 
697
  while( width-- > 0 )
 
698
    __pformat_putc( '\x20', stream );
 
699
}
 
700
 
 
701
typedef union
 
702
{
 
703
  /* A multifaceted representation of an IEEE extended precision,
 
704
   * (80-bit), floating point number, facilitating access to its
 
705
   * component parts.
 
706
   */
 
707
  double                 __pformat_fpreg_double_t;
 
708
  long double            __pformat_fpreg_ldouble_t;
 
709
  struct
 
710
  { unsigned long long   __pformat_fpreg_mantissa;
 
711
    signed short         __pformat_fpreg_exponent;
 
712
  };
 
713
  unsigned short         __pformat_fpreg_bitmap[5];
 
714
  unsigned long          __pformat_fpreg_bits;
 
715
} __pformat_fpreg_t;
 
716
 
 
717
#ifdef _WIN32
 
718
/* TODO: make this unconditional in final release...
 
719
 * (see note at head of associated `#else' block.
 
720
 */
 
721
#include "../gdtoa/gdtoa.h"
 
722
 
 
723
static
 
724
char *__pformat_cvt( int mode, __pformat_fpreg_t x, int nd, int *dp, int *sign )
 
725
{
 
726
  /* Helper function, derived from David M. Gay's `g_xfmt()', calling
 
727
   * his `__gdtoa()' function in a manner to provide extended precision
 
728
   * replacements for `ecvt()' and `fcvt()'.
 
729
   */
 
730
  unsigned int k, e = 0; char *ep;
 
731
  static FPI fpi = { 64, 1-16383-64+1, 32766-16383-64+1, FPI_Round_near, 0 };
 
732
 
 
733
  /* Classify the argument into an appropriate `__gdtoa()' category...
 
734
   */
 
735
  if( (k = __fpclassifyl( x.__pformat_fpreg_ldouble_t )) & FP_NAN )
 
736
    /*
 
737
     * identifying infinities or not-a-number...
 
738
     */
 
739
    k = (k & FP_NORMAL) ? STRTOG_Infinite : STRTOG_NaN;
 
740
 
 
741
  else if( k & FP_NORMAL )
 
742
  {
 
743
    /* normal and near-zero `denormals'...
 
744
     */
 
745
    if( k & FP_ZERO )
 
746
    {
 
747
      /* with appropriate exponent adjustment for a `denormal'...
 
748
       */
 
749
      k = STRTOG_Denormal;
 
750
      e = 1 - 0x3FFF - 63;
 
751
    }
 
752
    else
 
753
    {
 
754
      /* or with `normal' exponent adjustment...
 
755
       */
 
756
      k = STRTOG_Normal;
 
757
      e = (x.__pformat_fpreg_exponent & 0x7FFF) - 0x3FFF - 63;
 
758
    }
 
759
  }
 
760
 
 
761
  else
 
762
    /* or, if none of the above, it's a zero, (positive or negative).
 
763
     */
 
764
    k = STRTOG_Zero;
 
765
 
 
766
  /* Check for negative values, always treating NaN as unsigned...
 
767
   * (return value is zero for positive/unsigned; non-zero for negative).
 
768
   */
 
769
  *sign = (k == STRTOG_NaN) ? 0 : x.__pformat_fpreg_exponent & 0x8000;
 
770
 
 
771
  /* Finally, get the raw digit string, and radix point position index.
 
772
   */
 
773
  return __gdtoa( &fpi, e, &x.__pformat_fpreg_bits, (int *) &k, mode, nd, dp, &ep );
 
774
}
 
775
 
 
776
static __inline__ __attribute__((__always_inline__))
 
777
char *__pformat_ecvt( long double x, int precision, int *dp, int *sign )
 
778
{
 
779
  /* A convenience wrapper for the above...
 
780
   * it emulates `ecvt()', but takes a `long double' argument.
 
781
   */
 
782
  __pformat_fpreg_t z; z.__pformat_fpreg_ldouble_t = x;
 
783
  return __pformat_cvt( 2, z, precision, dp, sign );
 
784
}
 
785
 
 
786
static __inline__ __attribute__((__always_inline__))
 
787
char *__pformat_fcvt( long double x, int precision, int *dp, int *sign )
 
788
{
 
789
  /* A convenience wrapper for the above...
 
790
   * it emulates `fcvt()', but takes a `long double' argument.
 
791
   */
 
792
  __pformat_fpreg_t z; z.__pformat_fpreg_ldouble_t = x;
 
793
  return __pformat_cvt( 3, z, precision, dp, sign );
 
794
}
 
795
 
 
796
/* The following are required, to clean up the `__gdtoa()' memory pool,
 
797
 * after processing the data returned by the above.
 
798
 */
 
799
#define __pformat_ecvt_release( value ) __freedtoa( value )
 
800
#define __pformat_fcvt_release( value ) __freedtoa( value )
 
801
 
 
802
#else
 
803
/*
 
804
 * TODO: remove this before final release; it is included here as a
 
805
 * convenience for testing, without requiring a working `__gdtoa()'.
 
806
 */
 
807
static __inline__
 
808
char *__pformat_ecvt( long double x, int precision, int *dp, int *sign )
 
809
{
 
810
  /* Define in terms of `ecvt()'...
 
811
   */
 
812
  char *retval = ecvt( (double)(x), precision, dp, sign );
 
813
  if( isinf( x ) || isnan( x ) )
 
814
  {
 
815
    /* emulating `__gdtoa()' reporting for infinities and NaN.
 
816
     */
 
817
    *dp = PFORMAT_INFNAN;
 
818
    if( *retval == '-' )
 
819
    {
 
820
      /* Need to force the `sign' flag, (particularly for NaN).
 
821
       */
 
822
      ++retval; *sign = 1;
 
823
    }
 
824
  }
 
825
  return retval;
 
826
}
 
827
 
 
828
static __inline__
 
829
char *__pformat_fcvt( long double x, int precision, int *dp, int *sign )
 
830
{
 
831
  /* Define in terms of `fcvt()'...
 
832
   */
 
833
  char *retval = fcvt( (double)(x), precision, dp, sign );
 
834
  if( isinf( x ) || isnan( x ) )
 
835
  {
 
836
    /* emulating `__gdtoa()' reporting for infinities and NaN.
 
837
     */
 
838
    *dp = PFORMAT_INFNAN;
 
839
    if( *retval == '-' )
 
840
    {
 
841
      /* Need to force the `sign' flag, (particularly for NaN).
 
842
       */
 
843
      ++retval; *sign = 1;
 
844
    }
 
845
  }
 
846
  return retval;
 
847
}
 
848
 
 
849
/* No memory pool clean up needed, for these emulated cases...
 
850
 */
 
851
#define __pformat_ecvt_release( value ) /* nothing to be done */
 
852
#define __pformat_fcvt_release( value ) /* nothing to be done */
 
853
 
 
854
/* TODO: end of conditional to be removed. */
 
855
#endif
 
856
 
 
857
/* Can't be inlined, as it uses alloca.  */
 
858
static
 
859
void __pformat_emit_radix_point( __pformat_t *stream )
 
860
{
 
861
  /* Helper to place a localised representation of the radix point
 
862
   * character at the ultimate destination, when formatting fixed or
 
863
   * floating point numbers.
 
864
   */
 
865
  if( stream->rplen == PFORMAT_RPINIT )
 
866
  {
 
867
    /* Radix point initialisation not yet completed;
 
868
     * establish a multibyte to `wchar_t' converter...
 
869
     */
 
870
    int len; wchar_t rpchr; mbstate_t state;
 
871
    
 
872
    /* Initialise the conversion state...
 
873
     */
 
874
    memset( &state, 0, sizeof( state ) );
 
875
 
 
876
    /* Fetch and convert the localised radix point representation...
 
877
     */
 
878
    if( (len = mbrtowc( &rpchr, localeconv()->decimal_point, 16, &state )) > 0 )
 
879
      /*
 
880
       * and store it, if valid.
 
881
       */
 
882
      stream->rpchr = rpchr;
 
883
 
 
884
    /* In any case, store the reported effective multibyte length,
 
885
     * (or the error flag), marking initialisation as `done'.
 
886
     */
 
887
    stream->rplen = len;
 
888
  }
 
889
 
 
890
  if( stream->rpchr != (wchar_t)(0) )
 
891
  {
 
892
    /* We have a localised radix point mark;
 
893
     * establish a converter to make it a multibyte character...
 
894
     */
 
895
    int len; char buf[len = stream->rplen]; mbstate_t state;
 
896
 
 
897
    /* Initialise the conversion state...
 
898
     */
 
899
    memset( &state, 0, sizeof( state ) );
 
900
 
 
901
    /* Convert the `wchar_t' representation to multibyte...
 
902
     */
 
903
    if( (len = wcrtomb( buf, stream->rpchr, &state )) > 0 )
 
904
    {
 
905
      /* and copy to the output destination, when valid...
 
906
       */
 
907
      char *p = buf;
 
908
      while( len-- > 0 )
 
909
        __pformat_putc( *p++, stream );
 
910
    }
 
911
 
 
912
    else
 
913
      /* otherwise fall back to plain ASCII '.'...
 
914
       */
 
915
      __pformat_putc( '.', stream );
 
916
  }
 
917
 
 
918
  else
 
919
    /* No localisation: just use ASCII '.'...
 
920
     */
 
921
    __pformat_putc( '.', stream );
 
922
}
 
923
 
 
924
static __inline__ __attribute__((__always_inline__))
 
925
void __pformat_emit_numeric_value( int c, __pformat_t *stream )
 
926
{
 
927
  /* Convenience helper to transfer numeric data from an internal
 
928
   * formatting buffer to the ultimate destination...
 
929
   */
 
930
  if( c == '.' )
 
931
    /*
 
932
     * converting this internal representation of the the radix
 
933
     * point to the appropriately localised representation...
 
934
     */
 
935
    __pformat_emit_radix_point( stream );
 
936
 
 
937
  else
 
938
    /* and passing all other characters through, unmodified.
 
939
     */
 
940
    __pformat_putc( c, stream );
 
941
}
 
942
 
 
943
static
 
944
void __pformat_emit_inf_or_nan( int sign, char *value, __pformat_t *stream )
 
945
{
 
946
  /* Helper to emit INF or NAN where a floating point value
 
947
   * resolves to one of these special states.
 
948
   */
 
949
  int i;
 
950
  char buf[4];
 
951
  char *p = buf;
 
952
 
 
953
  /* We use the string formatting helper to display INF/NAN,
 
954
   * but we don't want truncation if the precision set for the
 
955
   * original floating point output request was insufficient;
 
956
   * ignore it!
 
957
   */
 
958
  stream->precision = PFORMAT_IGNORE;
 
959
 
 
960
  if( sign )
 
961
    /*
 
962
     * Negative infinity: emit the sign...
 
963
     */
 
964
    *p++ = '-';
 
965
 
 
966
  else if( stream->flags & PFORMAT_POSITIVE )
 
967
    /*
 
968
     * Not negative infinity, but '+' flag is in effect;
 
969
     * thus, we emit a positive sign...
 
970
     */
 
971
    *p++ = '+';
 
972
 
 
973
  else if( stream->flags & PFORMAT_ADDSPACE )
 
974
    /*
 
975
     * No sign required, but space was reserved for it...
 
976
     */
 
977
    *p++ = '\x20';
 
978
 
 
979
  /* Copy the appropriate status indicator, up to a maximum of
 
980
   * three characters, transforming to the case corresponding to
 
981
   * the format specification...
 
982
   */
 
983
  for( i = 3; i > 0; --i )
 
984
    *p++ = (*value++ & ~PFORMAT_XCASE) | (stream->flags & PFORMAT_XCASE);
 
985
 
 
986
  /* and emit the result.
 
987
   */
 
988
  __pformat_putchars( buf, p - buf, stream );
 
989
}
 
990
 
 
991
static
 
992
void __pformat_emit_float( int sign, char *value, int len, __pformat_t *stream )
 
993
{
 
994
  /* Helper to emit a fixed point representation of numeric data,
 
995
   * as encoded by a prior call to `ecvt()' or `fcvt()'; (this does
 
996
   * NOT include the exponent, for floating point format).
 
997
   */
 
998
  if( len > 0 )
 
999
  {
 
1000
    /* The magnitude of `x' is greater than or equal to 1.0...
 
1001
     * reserve space in the output field, for the required number of
 
1002
     * decimal digits to be placed before the decimal point...
 
1003
     */
 
1004
    if( stream->width > len )
 
1005
      /*
 
1006
       * adjusting as appropriate, when width is sufficient...
 
1007
       */
 
1008
      stream->width -= len;
 
1009
 
 
1010
    else
 
1011
      /* or simply ignoring the width specification, if not.
 
1012
       */
 
1013
      stream->width = PFORMAT_IGNORE;
 
1014
  }
 
1015
 
 
1016
  else if( stream->width > 0 )
 
1017
    /*
 
1018
     * The magnitude of `x' is less than 1.0...
 
1019
     * reserve space for exactly one zero before the decimal point.
 
1020
     */
 
1021
    stream->width--;
 
1022
 
 
1023
  /* Reserve additional space for the digits which will follow the
 
1024
   * decimal point...
 
1025
   */
 
1026
  if( (stream->width >= 0) && (stream->width > stream->precision) )
 
1027
    /*
 
1028
     * adjusting appropriately, when sufficient width remains...
 
1029
     * (note that we must check both of these conditions, because
 
1030
     * precision may be more negative than width, as a result of
 
1031
     * adjustment to provide extra padding when trailing zeros
 
1032
     * are to be discarded from "%g" format conversion with a
 
1033
     * specified field width, but if width itself is negative,
 
1034
     * then there is explicitly to be no padding anyway).
 
1035
     */
 
1036
    stream->width -= stream->precision;
 
1037
 
 
1038
  else
 
1039
    /* or again, ignoring the width specification, if not.
 
1040
     */
 
1041
    stream->width = PFORMAT_IGNORE;
 
1042
 
 
1043
  /* Reserve space in the output field, for display of the decimal point,
 
1044
   * unless the precision is explicity zero, with the `#' flag not set.
 
1045
   */
 
1046
  if(  (stream->width > 0)
 
1047
  &&  ((stream->precision > 0) || (stream->flags & PFORMAT_HASHED))  )
 
1048
    stream->width--;
 
1049
 
 
1050
  /* Reserve space in the output field, for display of the sign of the
 
1051
   * formatted value, if required; (i.e. if the value is negative, or if
 
1052
   * either the `space' or `+' formatting flags are set).
 
1053
   */
 
1054
  if( (stream->width > 0) && (sign || (stream->flags & PFORMAT_SIGNED)) )
 
1055
    stream->width--;
 
1056
 
 
1057
  /* Emit any padding space, as required to correctly right justify
 
1058
   * the output within the alloted field width.
 
1059
   */
 
1060
  if( (stream->width > 0) && ((stream->flags & PFORMAT_JUSTIFY) == 0) )
 
1061
    while( stream->width-- > 0 )
 
1062
      __pformat_putc( '\x20', stream );
 
1063
 
 
1064
  /* Emit the sign indicator, as appropriate...
 
1065
   */
 
1066
  if( sign )
 
1067
    /*
 
1068
     * mandatory, for negative values...
 
1069
     */
 
1070
    __pformat_putc( '-', stream );
 
1071
 
 
1072
  else if( stream->flags & PFORMAT_POSITIVE )
 
1073
    /*
 
1074
     * optional, for positive values...
 
1075
     */
 
1076
    __pformat_putc( '+', stream );
 
1077
 
 
1078
  else if( stream->flags & PFORMAT_ADDSPACE )
 
1079
    /*
 
1080
     * or just fill reserved space, when the space flag is in effect.
 
1081
     */
 
1082
    __pformat_putc( '\x20', stream );
 
1083
 
 
1084
  /* If the `0' flag is in effect, and not overridden by the `-' flag,
 
1085
   * then zero padding, to fill out the field, goes here...
 
1086
   */
 
1087
  if(  (stream->width > 0)
 
1088
  &&  ((stream->flags & PFORMAT_JUSTIFY) == PFORMAT_ZEROFILL)  )
 
1089
    while( stream->width-- > 0 )
 
1090
      __pformat_putc( '0', stream );
 
1091
 
 
1092
  /* Emit the digits of the encoded numeric value...
 
1093
   */
 
1094
  if( len > 0 )
 
1095
    /*
 
1096
     * ...beginning with those which precede the radix point,
 
1097
     * and appending any necessary significant trailing zeros.
 
1098
     */
 
1099
    do __pformat_putc( *value ? *value++ : '0', stream );
 
1100
       while( --len > 0 );
 
1101
 
 
1102
  else
 
1103
    /* The magnitude of the encoded value is less than 1.0, so no
 
1104
     * digits precede the radix point; we emit a mandatory initial
 
1105
     * zero, followed immediately by the radix point.
 
1106
     */
 
1107
    __pformat_putc( '0', stream );
 
1108
 
 
1109
  /* Unless the encoded value is integral, AND the radix point
 
1110
   * is not expressly demanded by the `#' flag, we must insert
 
1111
   * the appropriately localised radix point mark here...
 
1112
   */
 
1113
  if( (stream->precision > 0) || (stream->flags & PFORMAT_HASHED) )
 
1114
    __pformat_emit_radix_point( stream );
 
1115
 
 
1116
  /* When the radix point offset, `len', is negative, this implies
 
1117
   * that additional zeros must appear, following the radix point,
 
1118
   * and preceding the first significant digit...
 
1119
   */
 
1120
  if( len < 0 )
 
1121
  {
 
1122
    /* To accommodate these, we adjust the precision, (reducing it
 
1123
     * by adding a negative value), and then we emit as many zeros
 
1124
     * as are required.
 
1125
     */
 
1126
    stream->precision += len;
 
1127
    do __pformat_putc( '0', stream );
 
1128
       while( ++len < 0 );
 
1129
  }
 
1130
 
 
1131
  /* Now we emit any remaining significant digits, or trailing zeros,
 
1132
   * until the required precision has been achieved.
 
1133
   */
 
1134
  while( stream->precision-- > 0 )
 
1135
    __pformat_putc( *value ? *value++ : '0', stream );
 
1136
}
 
1137
 
 
1138
static
 
1139
void __pformat_emit_efloat( int sign, char *value, int e, __pformat_t *stream )
 
1140
{
 
1141
  /* Helper to emit a floating point representation of numeric data,
 
1142
   * as encoded by a prior call to `ecvt()' or `fcvt()'; (this DOES
 
1143
   * include the following exponent).
 
1144
   */
 
1145
  int exp_width = 1;
 
1146
  __pformat_intarg_t exponent; exponent.__pformat_llong_t = e -= 1;
 
1147
 
 
1148
  /* Determine how many digit positions are required for the exponent.
 
1149
   */
 
1150
  while( (e /= 10) != 0 )
 
1151
    exp_width++;
 
1152
 
 
1153
  /* Ensure that this is at least as many as the standard requirement.
 
1154
   */
 
1155
  if( exp_width < stream->expmin )
 
1156
    exp_width = stream->expmin;
 
1157
 
 
1158
  /* Adjust the residual field width allocation, to allow for the
 
1159
   * number of exponent digits to be emitted, together with a sign
 
1160
   * and exponent separator...
 
1161
   */
 
1162
  if( stream->width > (exp_width += 2) )
 
1163
    stream->width -= exp_width;
 
1164
  
 
1165
  else
 
1166
    /* ignoring the field width specification, if insufficient.
 
1167
     */
 
1168
    stream->width = PFORMAT_IGNORE;
 
1169
 
 
1170
  /* Emit the significand, as a fixed point value with one digit
 
1171
   * preceding the radix point.
 
1172
   */
 
1173
  __pformat_emit_float( sign, value, 1, stream );
 
1174
 
 
1175
  /* Reset precision, to ensure the mandatory minimum number of
 
1176
   * exponent digits will be emitted, and set the flags to ensure
 
1177
   * the sign is displayed.
 
1178
   */
 
1179
  stream->precision = stream->expmin;
 
1180
  stream->flags |= PFORMAT_SIGNED;
 
1181
 
 
1182
  /* Emit the exponent separator.
 
1183
   */
 
1184
  __pformat_putc( ('E' | (stream->flags & PFORMAT_XCASE)), stream );
 
1185
 
 
1186
  /* Readjust the field width setting, such that it again allows
 
1187
   * for the digits of the exponent, (which had been discounted when
 
1188
   * computing any left side padding requirement), so that they are
 
1189
   * correctly included in the computation of any right side padding
 
1190
   * requirement, (but here we exclude the exponent separator, which
 
1191
   * has been emitted, and so counted already).
 
1192
   */
 
1193
  stream->width += exp_width - 1;
 
1194
 
 
1195
  /* And finally, emit the exponent itself, as a signed integer,
 
1196
   * with any padding required to achieve flush left justification,
 
1197
   * (which will be added automatically, by `__pformat_int()').
 
1198
   */
 
1199
  __pformat_int( exponent, stream );
 
1200
}
 
1201
 
 
1202
static
 
1203
void __pformat_float( long double x, __pformat_t *stream )
 
1204
{
 
1205
  /* Handler for `%f' and `%F' format specifiers.
 
1206
   *
 
1207
   * This wraps calls to `__pformat_cvt()', `__pformat_emit_float()'
 
1208
   * and `__pformat_emit_inf_or_nan()', as appropriate, to achieve
 
1209
   * output in fixed point format.
 
1210
   */
 
1211
  int sign, intlen; char *value;
 
1212
 
 
1213
  /* Establish the precision for the displayed value, defaulting to six
 
1214
   * digits following the decimal point, if not explicitly specified.
 
1215
   */
 
1216
  if( stream->precision < 0 )
 
1217
    stream->precision = 6;
 
1218
 
 
1219
  /* Encode the input value as ASCII, for display...
 
1220
   */
 
1221
  value = __pformat_fcvt( x, stream->precision, &intlen, &sign );
 
1222
 
 
1223
  if( intlen == PFORMAT_INFNAN )
 
1224
    /*
 
1225
     * handle cases of `infinity' or `not-a-number'...
 
1226
     */
 
1227
    __pformat_emit_inf_or_nan( sign, value, stream );
 
1228
 
 
1229
  else
 
1230
  { /* or otherwise, emit the formatted result.
 
1231
     */
 
1232
    __pformat_emit_float( sign, value, intlen, stream );
 
1233
 
 
1234
    /* and, if there is any residual field width as yet unfilled,
 
1235
     * then we must be doing flush left justification, so pad out to
 
1236
     * the right hand field boundary.
 
1237
     */
 
1238
    while( stream->width-- > 0 )
 
1239
      __pformat_putc( '\x20', stream );
 
1240
  }
 
1241
 
 
1242
  /* Clean up `__pformat_fcvt()' memory allocation for `value'...
 
1243
   */
 
1244
  __pformat_fcvt_release( value );
 
1245
}
 
1246
 
 
1247
static
 
1248
void __pformat_efloat( long double x, __pformat_t *stream )
 
1249
{
 
1250
  /* Handler for `%e' and `%E' format specifiers.
 
1251
   *
 
1252
   * This wraps calls to `__pformat_cvt()', `__pformat_emit_efloat()'
 
1253
   * and `__pformat_emit_inf_or_nan()', as appropriate, to achieve
 
1254
   * output in floating point format.
 
1255
   */
 
1256
  int sign, intlen; char *value;
 
1257
 
 
1258
  /* Establish the precision for the displayed value, defaulting to six
 
1259
   * digits following the decimal point, if not explicitly specified.
 
1260
   */
 
1261
  if( stream->precision < 0 )
 
1262
    stream->precision = 6;
 
1263
 
 
1264
  /* Encode the input value as ASCII, for display...
 
1265
   */
 
1266
  value = __pformat_ecvt( x, stream->precision + 1, &intlen, &sign );
 
1267
 
 
1268
  if( intlen == PFORMAT_INFNAN )
 
1269
    /*
 
1270
     * handle cases of `infinity' or `not-a-number'...
 
1271
     */
 
1272
    __pformat_emit_inf_or_nan( sign, value, stream );
 
1273
 
 
1274
  else
 
1275
    /* or otherwise, emit the formatted result.
 
1276
     */
 
1277
    __pformat_emit_efloat( sign, value, intlen, stream );
 
1278
 
 
1279
  /* Clean up `__pformat_ecvt()' memory allocation for `value'...
 
1280
   */
 
1281
  __pformat_ecvt_release( value );
 
1282
}
 
1283
 
 
1284
static
 
1285
void __pformat_gfloat( long double x, __pformat_t *stream )
 
1286
{
 
1287
  /* Handler for `%g' and `%G' format specifiers.
 
1288
   *
 
1289
   * This wraps calls to `__pformat_cvt()', `__pformat_emit_float()',
 
1290
   * `__pformat_emit_efloat()' and `__pformat_emit_inf_or_nan()', as
 
1291
   * appropriate, to achieve output in the more suitable of either
 
1292
   * fixed or floating point format.
 
1293
   */
 
1294
  int sign, intlen; char *value;
 
1295
 
 
1296
  /* Establish the precision for the displayed value, defaulting to
 
1297
   * six significant digits, if not explicitly specified...
 
1298
   */
 
1299
  if( stream->precision < 0 )
 
1300
    stream->precision = 6;
 
1301
 
 
1302
  /* or to a minimum of one digit, otherwise...
 
1303
   */
 
1304
  else if( stream->precision == 0 )
 
1305
    stream->precision = 1;
 
1306
 
 
1307
  /* Encode the input value as ASCII, for display.
 
1308
   */
 
1309
  value = __pformat_ecvt( x, stream->precision, &intlen, &sign );
 
1310
 
 
1311
  if( intlen == PFORMAT_INFNAN )
 
1312
    /*
 
1313
     * Handle cases of `infinity' or `not-a-number'.
 
1314
     */
 
1315
    __pformat_emit_inf_or_nan( sign, value, stream );
 
1316
 
 
1317
  else if( (-4 < intlen) && (intlen <= stream->precision) )
 
1318
  {
 
1319
    /* Value lies in the acceptable range for fixed point output,
 
1320
     * (i.e. the exponent is no less than minus four, and the number
 
1321
     * of significant digits which precede the radix point is fewer
 
1322
     * than the least number which would overflow the field width,
 
1323
     * specified or implied by the established precision).
 
1324
     */
 
1325
    if( (stream->flags & PFORMAT_HASHED) == PFORMAT_HASHED )
 
1326
      /*
 
1327
       * The `#' flag is in effect...
 
1328
       * Adjust precision to retain the specified number of significant
 
1329
       * digits, with the proper number preceding the radix point, and
 
1330
       * the balance following it...
 
1331
       */
 
1332
      stream->precision -= intlen;
 
1333
    
 
1334
    else
 
1335
      /* The `#' flag is not in effect...
 
1336
       * Here we adjust the precision to accommodate all digits which
 
1337
       * precede the radix point, but we truncate any balance following
 
1338
       * it, to suppress output of non-significant trailing zeros...
 
1339
       */
 
1340
      if( ((stream->precision = strlen( value ) - intlen) < 0)
 
1341
        /*
 
1342
         * This may require a compensating adjustment to the field
 
1343
         * width, to accommodate significant trailing zeros, which
 
1344
         * precede the radix point...
 
1345
         */
 
1346
      && (stream->width > 0)  )
 
1347
        stream->width += stream->precision;
 
1348
 
 
1349
    /* Now, we format the result as any other fixed point value.
 
1350
     */
 
1351
    __pformat_emit_float( sign, value, intlen, stream );
 
1352
 
 
1353
    /* If there is any residual field width as yet unfilled, then
 
1354
     * we must be doing flush left justification, so pad out to the
 
1355
     * right hand field boundary.
 
1356
     */
 
1357
    while( stream->width-- > 0 )
 
1358
      __pformat_putc( '\x20', stream );
 
1359
  }
 
1360
 
 
1361
  else
 
1362
  { /* Value lies outside the acceptable range for fixed point;
 
1363
     * one significant digit will precede the radix point, so we
 
1364
     * decrement the precision to retain only the appropriate number
 
1365
     * of additional digits following it, when we emit the result
 
1366
     * in floating point format.
 
1367
     */
 
1368
    if( (stream->flags & PFORMAT_HASHED) == PFORMAT_HASHED )
 
1369
      /*
 
1370
       * The `#' flag is in effect...
 
1371
       * Adjust precision to emit the specified number of significant
 
1372
       * digits, with one preceding the radix point, and the balance
 
1373
       * following it, retaining any non-significant trailing zeros
 
1374
       * which are required to exactly match the requested precision...
 
1375
       */
 
1376
      stream->precision--;
 
1377
 
 
1378
    else
 
1379
      /* The `#' flag is not in effect...
 
1380
       * Adjust precision to emit only significant digits, with one
 
1381
       * preceding the radix point, and any others following it, but
 
1382
       * suppressing non-significant trailing zeros...
 
1383
       */
 
1384
      stream->precision = strlen( value ) - 1;
 
1385
 
 
1386
    /* Now, we format the result as any other floating point value.
 
1387
     */
 
1388
    __pformat_emit_efloat( sign, value, intlen, stream );
 
1389
  }
 
1390
 
 
1391
  /* Clean up `__pformat_ecvt()' memory allocation for `value'.
 
1392
   */
 
1393
  __pformat_ecvt_release( value );
 
1394
}
 
1395
 
 
1396
static
 
1397
void __pformat_emit_xfloat( __pformat_fpreg_t value, __pformat_t *stream )
 
1398
{
 
1399
  /* Helper for emitting floating point data, originating as
 
1400
   * either `double' or `long double' type, as a hexadecimal
 
1401
   * representation of the argument value.
 
1402
   */
 
1403
  char buf[18], *p = buf;
 
1404
  __pformat_intarg_t exponent; short exp_width = 2;
 
1405
 
 
1406
  /* The mantissa field of the argument value representation can
 
1407
   * accommodate at most 16 hexadecimal digits, of which one will
 
1408
   * be placed before the radix point, leaving at most 15 digits
 
1409
   * to satisfy any requested precision; thus...
 
1410
   */
 
1411
  if( (stream->precision >= 0) && (stream->precision < 15) )
 
1412
  {
 
1413
    /* When the user specifies a precision within this range,
 
1414
     * we want to adjust the mantissa, to retain just the number
 
1415
     * of digits required, rounding up when the high bit of the
 
1416
     * leftmost discarded digit is set; (mask of 0x08 accounts
 
1417
     * for exactly one digit discarded, shifting 4 bits per
 
1418
     * digit, with up to 14 additional digits, to consume the
 
1419
     * full availability of 15 precision digits).
 
1420
     *
 
1421
     * However, before we perform the rounding operation, we
 
1422
     * normalise the mantissa, shifting it to the left by as many
 
1423
     * bit positions may be necessary, until its highest order bit
 
1424
     * is set, thus preserving the maximum number of bits in the
 
1425
     * rounded result as possible.
 
1426
     */
 
1427
    while( value.__pformat_fpreg_mantissa < (LLONG_MAX + 1ULL) )
 
1428
      value.__pformat_fpreg_mantissa <<= 1;
 
1429
 
 
1430
    /* We then shift the mantissa one bit position back to the
 
1431
     * right, to guard against possible overflow when the rounding
 
1432
     * adjustment is added.
 
1433
     */
 
1434
    value.__pformat_fpreg_mantissa >>= 1;
 
1435
 
 
1436
    /* We now add the rounding adjustment, noting that to keep the
 
1437
     * 0x08 mask aligned with the shifted mantissa, we also need to
 
1438
     * shift it right by one bit initially, changing its starting
 
1439
     * value to 0x04...
 
1440
     */
 
1441
    value.__pformat_fpreg_mantissa += 0x04LL << (4 * (14 - stream->precision));
 
1442
    if( (value.__pformat_fpreg_mantissa & (LLONG_MAX + 1ULL)) == 0ULL )
 
1443
      /*
 
1444
       * When the rounding adjustment would not have overflowed,
 
1445
       * then we shift back to the left again, to fill the vacated
 
1446
       * bit we reserved to accommodate the carry.
 
1447
       */
 
1448
      value.__pformat_fpreg_mantissa <<= 1;
 
1449
 
 
1450
    else
 
1451
      /* Otherwise the rounding adjustment would have overflowed,
 
1452
       * so the carry has already filled the vacated bit; the effect
 
1453
       * of this is equivalent to an increment of the exponent.
 
1454
       */
 
1455
      value.__pformat_fpreg_exponent++;
 
1456
 
 
1457
    /* We now complete the rounding to the required precision, by
 
1458
     * shifting the unwanted digits out, from the right hand end of
 
1459
     * the mantissa.
 
1460
     */
 
1461
    value.__pformat_fpreg_mantissa >>= 4 * (15 - stream->precision);
 
1462
  }
 
1463
 
 
1464
  /* Encode the significant digits of the mantissa in hexadecimal
 
1465
   * ASCII notation, ready for transfer to the output stream...
 
1466
   */
 
1467
  while( value.__pformat_fpreg_mantissa )
 
1468
  {
 
1469
    /* taking the rightmost digit in each pass...
 
1470
     */
 
1471
    int c = value.__pformat_fpreg_mantissa & 0xF;
 
1472
    if( c == (int) value.__pformat_fpreg_mantissa )
 
1473
    {
 
1474
      /* inserting the radix point, when we reach the last,
 
1475
       * (i.e. the most significant digit), unless we found no
 
1476
       * less significant digits, with no mandatory radix point
 
1477
       * inclusion, and no additional required precision...
 
1478
       */
 
1479
      if( (p > buf)
 
1480
      ||  (stream->flags & PFORMAT_HASHED) || (stream->precision > 0)  )
 
1481
        /*
 
1482
         * Internally, we represent the radix point as an ASCII '.';
 
1483
         * we will replace it with any locale specific alternative,
 
1484
         * at the time of transfer to the ultimate destination.
 
1485
         */
 
1486
        *p++ = '.';
 
1487
 
 
1488
      /* If the most significant hexadecimal digit of the encoded
 
1489
       * output value is greater than one, then the indicated value
 
1490
       * will appear too large, by an additional binary exponent
 
1491
       * corresponding to the number of higher order bit positions
 
1492
       * which it occupies...
 
1493
       */
 
1494
      while( value.__pformat_fpreg_mantissa > 1 )
 
1495
      {
 
1496
        /* so reduce the exponent value to compensate...
 
1497
         */
 
1498
        value.__pformat_fpreg_exponent--;
 
1499
        value.__pformat_fpreg_mantissa >>= 1;
 
1500
      }
 
1501
    }
 
1502
 
 
1503
    else if( stream->precision > 0 )
 
1504
      /*
 
1505
       * we have not yet fulfilled the desired precision,
 
1506
       * and we have not yet found the most significant digit,
 
1507
       * so account for the current digit, within the field
 
1508
       * width required to meet the specified precision.
 
1509
       */
 
1510
      stream->precision--;
 
1511
 
 
1512
    if( (c > 0) || (p > buf) || (stream->precision >= 0) )
 
1513
      /*
 
1514
       * Ignoring insignificant trailing zeros, (unless required to
 
1515
       * satisfy specified precision), store the current encoded digit
 
1516
       * into the pending output buffer, in LIFO order, and using the
 
1517
       * appropriate case for digits in the `A'..`F' range.
 
1518
       */
 
1519
      *p++ = c > 9 ? (c - 10 + 'A') | (stream->flags & PFORMAT_XCASE) : c + '0';
 
1520
 
 
1521
    /* Shift out the current digit, (4-bit logical shift right),
 
1522
     * to align the next more significant digit to be extracted,
 
1523
     * and encoded in the next pass.
 
1524
     */
 
1525
    value.__pformat_fpreg_mantissa >>= 4;
 
1526
  }
 
1527
 
 
1528
  if( p == buf )
 
1529
  {
 
1530
    /* Nothing has been queued for output...
 
1531
     * We need at least one zero, and possibly a radix point.
 
1532
     */
 
1533
    if( (stream->precision > 0) || (stream->flags & PFORMAT_HASHED) )
 
1534
      *p++ = '.';
 
1535
 
 
1536
    *p++ = '0';
 
1537
  }
 
1538
 
 
1539
  if( stream->width > 0 )
 
1540
  {
 
1541
  /* Adjust the user specified field width, to account for the
 
1542
   * number of digits minimally required, to display the encoded
 
1543
   * value, at the requested precision.
 
1544
   *
 
1545
   * FIXME: this uses the minimum number of digits possible for
 
1546
   * representation of the binary exponent, in strict conformance
 
1547
   * with C99 and POSIX specifications.  Although there appears to
 
1548
   * be no Microsoft precedent for doing otherwise, we may wish to
 
1549
   * relate this to the `_get_output_format()' result, to maintain
 
1550
   * consistency with `%e', `%f' and `%g' styles.
 
1551
   */
 
1552
    int min_width = p - buf;
 
1553
    int expo = value.__pformat_fpreg_exponent;
 
1554
 
 
1555
    /* If we have not yet queued sufficient digits to fulfil the
 
1556
     * requested precision, then we must adjust the minimum width
 
1557
     * specification, to accommodate the additional digits which
 
1558
     * are required to do so.
 
1559
     */
 
1560
    if( stream->precision > 0 )
 
1561
      min_width += stream->precision;
 
1562
 
 
1563
    /* Adjust the minimum width requirement, to accomodate the
 
1564
     * sign, radix indicator and at least one exponent digit...
 
1565
     */
 
1566
    min_width += stream->flags & PFORMAT_SIGNED ? 6 : 5;
 
1567
    while( (expo = expo / 10) != 0 )
 
1568
    {
 
1569
      /* and increase as required, if additional exponent digits
 
1570
       * are needed, also saving the exponent field width adjustment,
 
1571
       * for later use when that is emitted.
 
1572
       */
 
1573
      min_width++;
 
1574
      exp_width++;
 
1575
    }
 
1576
  
 
1577
    if( stream->width > min_width )
 
1578
    {
 
1579
      /* When specified field width exceeds the minimum required,
 
1580
       * adjust to retain only the excess...
 
1581
       */
 
1582
      stream->width -= min_width;
 
1583
 
 
1584
      /* and then emit any required left side padding spaces.
 
1585
       */
 
1586
      if( (stream->flags & PFORMAT_JUSTIFY) == 0 )
 
1587
        while( stream->width-- > 0 )
 
1588
          __pformat_putc( '\x20', stream );
 
1589
    }
 
1590
 
 
1591
    else
 
1592
      /* Specified field width is insufficient; just ignore it!
 
1593
       */
 
1594
      stream->width = PFORMAT_IGNORE;
 
1595
  }
 
1596
 
 
1597
  /* Emit the sign of the encoded value, as required...
 
1598
   */
 
1599
  if( stream->flags & PFORMAT_NEGATIVE )
 
1600
    /*
 
1601
     * this is mandatory, to indicate a negative value...
 
1602
     */
 
1603
    __pformat_putc( '-', stream );
 
1604
 
 
1605
  else if( stream->flags & PFORMAT_POSITIVE )
 
1606
    /*
 
1607
     * but this is optional, for a positive value...
 
1608
     */
 
1609
    __pformat_putc( '+', stream );
 
1610
 
 
1611
  else if( stream->flags & PFORMAT_ADDSPACE )
 
1612
    /*
 
1613
     * with this optional alternative.
 
1614
     */
 
1615
    __pformat_putc( '\x20', stream );
 
1616
 
 
1617
  /* Prefix a `0x' or `0X' radix indicator to the encoded value,
 
1618
   * with case appropriate to the format specification.
 
1619
   */
 
1620
  __pformat_putc( '0', stream );
 
1621
  __pformat_putc( 'X' | (stream->flags & PFORMAT_XCASE), stream );
 
1622
 
 
1623
  /* If the `0' flag is in effect...
 
1624
   * Zero padding, to fill out the field, goes here...
 
1625
   */
 
1626
  if( (stream->width > 0) && (stream->flags & PFORMAT_ZEROFILL) )
 
1627
    while( stream->width-- > 0 )
 
1628
      __pformat_putc( '0', stream );
 
1629
 
 
1630
  /* Next, we emit the encoded value, without its exponent...
 
1631
   */
 
1632
  while( p > buf )
 
1633
    __pformat_emit_numeric_value( *--p, stream );
 
1634
 
 
1635
  /* followed by any additional zeros needed to satisfy the
 
1636
   * precision specification...
 
1637
   */
 
1638
  while( stream->precision-- > 0 )
 
1639
    __pformat_putc( '0', stream );
 
1640
 
 
1641
  /* then the exponent prefix, (C99 and POSIX specify `p'),
 
1642
   * in the case appropriate to the format specification...
 
1643
   */
 
1644
  __pformat_putc( 'P' | (stream->flags & PFORMAT_XCASE), stream );
 
1645
 
 
1646
  /* and finally, the decimal representation of the binary exponent,
 
1647
   * as a signed value with mandatory sign displayed, in a field width
 
1648
   * adjusted to accommodate it, LEFT justified, with any additional
 
1649
   * right side padding remaining from the original field width.
 
1650
   */
 
1651
  stream->width += exp_width;
 
1652
  stream->flags |= PFORMAT_SIGNED;
 
1653
  exponent.__pformat_llong_t = value.__pformat_fpreg_exponent;
 
1654
  __pformat_int( exponent, stream );
 
1655
}
 
1656
 
 
1657
static
 
1658
void __pformat_xdouble( double x, __pformat_t *stream )
 
1659
{
 
1660
  /* Handler for `%a' and `%A' format specifiers, (with argument
 
1661
   * value specified as `double' type).
 
1662
   */
 
1663
  unsigned sign_bit = 0;
 
1664
  __pformat_fpreg_t z; z.__pformat_fpreg_double_t = x;
 
1665
 
 
1666
  /* First check for NaN; it is emitted unsigned...
 
1667
   */
 
1668
  if( isnan( x ) )
 
1669
    __pformat_emit_inf_or_nan( sign_bit, "NaN", stream );
 
1670
 
 
1671
  else
 
1672
  { /* Capture the sign bit up-front, so we can show it correctly
 
1673
     * even when the argument value is zero or infinite.
 
1674
     */
 
1675
    if( (sign_bit = (z.__pformat_fpreg_bitmap[3] & 0x8000)) != 0 )
 
1676
      stream->flags |= PFORMAT_NEGATIVE;
 
1677
 
 
1678
    /* Check for infinity, (positive or negative)...
 
1679
     */
 
1680
    if( isinf( x ) )
 
1681
      /*
 
1682
       * displaying the appropriately signed indicator,
 
1683
       * when appropriate.
 
1684
       */
 
1685
      __pformat_emit_inf_or_nan( sign_bit, "Inf", stream );
 
1686
 
 
1687
    else
 
1688
    { /* The argument value is a representable number...
 
1689
       * first move its exponent into the appropriate field...
 
1690
       */
 
1691
      z.__pformat_fpreg_bitmap[4] = (z.__pformat_fpreg_bitmap[3] >> 4) & 0x7FF;
 
1692
 
 
1693
      /* Realign the mantissa, leaving space for a
 
1694
       * normalised most significant digit...
 
1695
       */
 
1696
      z.__pformat_fpreg_mantissa <<= 8;
 
1697
      z.__pformat_fpreg_bitmap[3] = (z.__pformat_fpreg_bitmap[3] & 0x0FFF);
 
1698
 
 
1699
      /* Check for zero value...
 
1700
       */
 
1701
      if( z.__pformat_fpreg_exponent || z.__pformat_fpreg_mantissa )
 
1702
      {
 
1703
        /* and only when the value is non-zero,
 
1704
         * eliminate the bias from the exponent...
 
1705
         */
 
1706
        z.__pformat_fpreg_exponent -= 0x3FF;
 
1707
 
 
1708
        /* Check for a possible denormalised value...
 
1709
         */
 
1710
        if( z.__pformat_fpreg_exponent > -126 )
 
1711
          /*
 
1712
           * and normalise when it isn't.
 
1713
           */
 
1714
          z.__pformat_fpreg_bitmap[3] += 0x1000;
 
1715
      }
 
1716
 
 
1717
      /* Finally, hand the adjusted representation off to the generalised
 
1718
       * hexadecimal floating point format handler...
 
1719
       */
 
1720
      __pformat_emit_xfloat( z, stream );
 
1721
    }
 
1722
  }
 
1723
}
 
1724
 
 
1725
static
 
1726
void __pformat_xldouble( long double x, __pformat_t *stream )
 
1727
{
 
1728
  /* Handler for `%La' and `%LA' format specifiers, (with argument
 
1729
   * value specified as `long double' type).
 
1730
   */
 
1731
  unsigned sign_bit = 0;
 
1732
  __pformat_fpreg_t z; z.__pformat_fpreg_ldouble_t = x;
 
1733
 
 
1734
  /* First check for NaN; it is emitted unsigned...
 
1735
   */
 
1736
  if( isnan( x ) )
 
1737
    __pformat_emit_inf_or_nan( sign_bit, "NaN", stream );
 
1738
 
 
1739
  else
 
1740
  { /* Capture the sign bit up-front, so we can show it correctly
 
1741
     * even when the argument value is zero or infinite.
 
1742
     */
 
1743
    if( (sign_bit = (z.__pformat_fpreg_exponent & 0x8000)) != 0 )
 
1744
      stream->flags |= PFORMAT_NEGATIVE;
 
1745
 
 
1746
    /* Check for infinity, (positive or negative)...
 
1747
     */
 
1748
    if( isinf( x ) )
 
1749
      /*
 
1750
       * displaying the appropriately signed indicator,
 
1751
       * when appropriate.
 
1752
       */
 
1753
      __pformat_emit_inf_or_nan( sign_bit, "Inf", stream );
 
1754
 
 
1755
    else
 
1756
    { /* The argument value is a representable number...
 
1757
       * extract the effective value of the biased exponent...
 
1758
       */
 
1759
      z.__pformat_fpreg_exponent &= 0x7FFF;
 
1760
      if( z.__pformat_fpreg_exponent || z.__pformat_fpreg_mantissa )
 
1761
        /*
 
1762
         * and if the argument value itself is non-zero,
 
1763
         * eliminate the bias from the exponent...
 
1764
         */
 
1765
        z.__pformat_fpreg_exponent -= 0x3FFF;
 
1766
 
 
1767
      /* Finally, hand the adjusted representation off to the
 
1768
       * generalised hexadecimal floating point format handler...
 
1769
       */
 
1770
      __pformat_emit_xfloat( z, stream );
 
1771
    }
 
1772
  }
 
1773
}
 
1774
 
 
1775
int __pformat( int flags, void *dest, int max, const char *fmt, va_list argv )
 
1776
{
 
1777
  int c;
 
1778
 
 
1779
  __pformat_t stream =
 
1780
  {
 
1781
    /* Create and initialise a format control block
 
1782
     * for this output request.
 
1783
     */
 
1784
    dest,                                       /* output goes to here        */
 
1785
    flags &= PFORMAT_TO_FILE | PFORMAT_NOLIMIT, /* only these valid initially */
 
1786
    PFORMAT_IGNORE,                             /* no field width yet         */
 
1787
    PFORMAT_IGNORE,                             /* nor any precision spec     */
 
1788
    PFORMAT_RPINIT,                             /* radix point uninitialised  */
 
1789
    (wchar_t)(0),                               /* leave it unspecified       */
 
1790
    0,                                          /* zero output char count     */
 
1791
    max,                                        /* establish output limit     */
 
1792
    PFORMAT_MINEXP                              /* exponent chars preferred   */
 
1793
  };
 
1794
 
 
1795
  format_scan: while( (c = *fmt++) != 0 )
 
1796
  {
 
1797
    /* Format string parsing loop...
 
1798
     * The entry point is labelled, so that we can return to the start state
 
1799
     * from within the inner `conversion specification' interpretation loop,
 
1800
     * as soon as a conversion specification has been resolved.
 
1801
     */
 
1802
    if( c == '%' )
 
1803
    {
 
1804
      /* Initiate parsing of a `conversion specification'...
 
1805
       */
 
1806
      __pformat_intarg_t argval;
 
1807
      __pformat_state_t  state = PFORMAT_INIT;
 
1808
      __pformat_length_t length = PFORMAT_LENGTH_INT;
 
1809
 
 
1810
      /* Save the current format scan position, so that we can backtrack
 
1811
       * in the event of encountering an invalid format specification...
 
1812
       */
 
1813
      const char *backtrack = fmt;
 
1814
 
 
1815
      /* Restart capture for dynamic field width and precision specs...
 
1816
       */
 
1817
      int *width_spec = &stream.width;
 
1818
 
 
1819
      /* Reset initial state for flags, width and precision specs...
 
1820
       */
 
1821
      stream.flags = flags;
 
1822
      stream.width = stream.precision = PFORMAT_IGNORE;
 
1823
 
 
1824
      while( *fmt )
 
1825
      {
 
1826
        switch( c = *fmt++ )
 
1827
        {
 
1828
          /* Data type specifiers...
 
1829
           * All are terminal, so exit the conversion spec parsing loop
 
1830
           * with a `goto format_scan', thus resuming at the outer level
 
1831
           * in the regular format string parser.
 
1832
           */
 
1833
          case '%':
 
1834
            /*
 
1835
             * Not strictly a data type specifier...
 
1836
             * it simply converts as a literal `%' character.
 
1837
             *
 
1838
             * FIXME: should we require this to IMMEDIATELY follow the
 
1839
             * initial `%' of the "conversion spec"?  (glibc `printf()'
 
1840
             * on GNU/Linux does NOT appear to require this, but POSIX
 
1841
             * and SUSv3 do seem to demand it).
 
1842
             */
 
1843
            __pformat_putc( c, &stream );
 
1844
            goto format_scan;
 
1845
 
 
1846
          case 'C':
 
1847
            /*
 
1848
             * Equivalent to `%lc'; set `length' accordingly,
 
1849
             * and simply fall through.
 
1850
             */
 
1851
            length = PFORMAT_LENGTH_LONG;
 
1852
 
 
1853
          case 'c':
 
1854
            /*
 
1855
             * Single, (or single multibyte), character output...
 
1856
             *
 
1857
             * We handle these by copying the argument into our local
 
1858
             * `argval' buffer, and then we pass the address of that to
 
1859
             * either `__pformat_putchars()' or `__pformat_wputchars()',
 
1860
             * as appropriate, effectively formatting it as a string of
 
1861
             * the appropriate type, with a length of one.
 
1862
             *
 
1863
             * A side effect of this method of handling character data
 
1864
             * is that, if the user sets a precision of zero, then no
 
1865
             * character is actually emitted; we don't want that, so we
 
1866
             * forcibly override any user specified precision.
 
1867
             */
 
1868
            stream.precision = PFORMAT_IGNORE;
 
1869
 
 
1870
            /* Now we invoke the appropriate format handler...
 
1871
             */
 
1872
            if( (length == PFORMAT_LENGTH_LONG)
 
1873
            ||  (length == PFORMAT_LENGTH_LLONG)  )
 
1874
            {
 
1875
              /* considering any `long' type modifier as a reference to
 
1876
               * `wchar_t' data, (which is promoted to an `int' argument)...
 
1877
               */
 
1878
              argval.__pformat_ullong_t = (wchar_t)(va_arg( argv, int ));
 
1879
              __pformat_wputchars( (wchar_t *)(&argval), 1, &stream );
 
1880
            }
 
1881
 
 
1882
            else
 
1883
            { /* while anything else is simply taken as `char', (which
 
1884
               * is also promoted to an `int' argument)...
 
1885
               */
 
1886
              argval.__pformat_uchar_t = (unsigned char)(va_arg( argv, int ));
 
1887
              __pformat_putchars( (char *)(&argval), 1, &stream );
 
1888
            }
 
1889
            goto format_scan;
 
1890
 
 
1891
          case 'S':
 
1892
            /*
 
1893
             * Equivalent to `%ls'; set `length' accordingly,
 
1894
             * and simply fall through.
 
1895
             */
 
1896
            length = PFORMAT_LENGTH_LONG;
 
1897
 
 
1898
          case 's':
 
1899
            if( (length == PFORMAT_LENGTH_LONG)
 
1900
            ||  (length == PFORMAT_LENGTH_LLONG)  )
 
1901
            {
 
1902
              /* considering any `long' type modifier as a reference to
 
1903
               * a `wchar_t' string...
 
1904
               */
 
1905
              __pformat_wcputs( va_arg( argv, wchar_t * ), &stream );
 
1906
            }
 
1907
 
 
1908
            else
 
1909
              /* This is normal string output;
 
1910
               * we simply invoke the appropriate handler...
 
1911
               */
 
1912
              __pformat_puts( va_arg( argv, char * ), &stream );
 
1913
 
 
1914
            goto format_scan;
 
1915
 
 
1916
          case 'o':
 
1917
          case 'u':
 
1918
          case 'x':
 
1919
          case 'X':
 
1920
            /*
 
1921
             * Unsigned integer values; octal, decimal or hexadecimal format...
 
1922
             */
 
1923
            if( length == PFORMAT_LENGTH_LLONG )
 
1924
              /*
 
1925
               * with an `unsigned long long' argument, which we
 
1926
               * process `as is'...
 
1927
               */
 
1928
              argval.__pformat_ullong_t = va_arg( argv, unsigned long long );
 
1929
 
 
1930
            else if( length == PFORMAT_LENGTH_LONG )
 
1931
              /*
 
1932
               * or with an `unsigned long', which we promote to
 
1933
               * `unsigned long long'...
 
1934
               */
 
1935
              argval.__pformat_ullong_t = va_arg( argv, unsigned long );
 
1936
 
 
1937
            else
 
1938
            { /* or for any other size, which will have been promoted
 
1939
               * to `unsigned int', we select only the appropriately sized
 
1940
               * least significant segment, and again promote to the same
 
1941
               * size as `unsigned long long'...
 
1942
               */ 
 
1943
              argval.__pformat_ullong_t = va_arg( argv, unsigned int );
 
1944
              if( length == PFORMAT_LENGTH_SHORT )
 
1945
                /*
 
1946
                 * from `unsigned short'...
 
1947
                 */
 
1948
                argval.__pformat_ullong_t = argval.__pformat_ushort_t;
 
1949
 
 
1950
              else if( length == PFORMAT_LENGTH_CHAR )
 
1951
                /*
 
1952
                 * or even from `unsigned char'...
 
1953
                 */
 
1954
                argval.__pformat_ullong_t = argval.__pformat_uchar_t;
 
1955
            }
 
1956
 
 
1957
            /* so we can pass any size of argument to either of two
 
1958
             * common format handlers...
 
1959
             */
 
1960
            if( c == 'u' )
 
1961
              /*
 
1962
               * depending on whether output is to be encoded in
 
1963
               * decimal format...
 
1964
               */
 
1965
              __pformat_int( argval, &stream );
 
1966
 
 
1967
            else
 
1968
              /* or in octal or hexadecimal format...
 
1969
               */
 
1970
              __pformat_xint( c, argval, &stream );
 
1971
 
 
1972
            goto format_scan;
 
1973
 
 
1974
          case 'd':
 
1975
          case 'i':
 
1976
            /*
 
1977
             * Signed integer values; decimal format...
 
1978
             * This is similar to `u', but must process `argval' as signed,
 
1979
             * and be prepared to handle negative numbers.
 
1980
             */
 
1981
            stream.flags |= PFORMAT_NEGATIVE;
 
1982
 
 
1983
            if( length == PFORMAT_LENGTH_LLONG )
 
1984
              /*
 
1985
               * The argument is a `long long' type...
 
1986
               */
 
1987
              argval.__pformat_llong_t = va_arg( argv, long long );
 
1988
 
 
1989
            else if( length == PFORMAT_LENGTH_LONG )
 
1990
              /*
 
1991
               * or here, a `long' type...
 
1992
               */
 
1993
              argval.__pformat_llong_t = va_arg( argv, long );
 
1994
 
 
1995
            else
 
1996
            { /* otherwise, it's an `int' type...
 
1997
               */
 
1998
              argval.__pformat_llong_t = va_arg( argv, int );
 
1999
              if( length == PFORMAT_LENGTH_SHORT )
 
2000
                /*
 
2001
                 * but it was promoted from a `short' type...
 
2002
                 */
 
2003
                argval.__pformat_llong_t = argval.__pformat_short_t;
 
2004
              else if( length == PFORMAT_LENGTH_CHAR )
 
2005
                /*
 
2006
                 * or even from a `char' type...
 
2007
                 */
 
2008
                argval.__pformat_llong_t = argval.__pformat_char_t;
 
2009
            }
 
2010
            
 
2011
            /* In any case, all share a common handler...
 
2012
             */
 
2013
            __pformat_int( argval, &stream );
 
2014
            goto format_scan;
 
2015
 
 
2016
          case 'p':
 
2017
            /*
 
2018
             * Pointer argument; format as hexadecimal, with `0x' prefix...
 
2019
             */
 
2020
            stream.flags |= PFORMAT_HASHED;
 
2021
            argval.__pformat_ullong_t = va_arg( argv, uintptr_t );
 
2022
            __pformat_xint( 'x', argval, &stream );
 
2023
            goto format_scan;
 
2024
 
 
2025
          case 'e':
 
2026
            /*
 
2027
             * Floating point format, with lower case exponent indicator
 
2028
             * and lower case `inf' or `nan' representation when required;
 
2029
             * select lower case mode, and simply fall through...
 
2030
             */
 
2031
            stream.flags |= PFORMAT_XCASE;
 
2032
 
 
2033
          case 'E':
 
2034
            /*
 
2035
             * Floating point format, with upper case exponent indicator
 
2036
             * and upper case `INF' or `NAN' representation when required,
 
2037
             * (or lower case for all of these, on fall through from above);
 
2038
             * select lower case mode, and simply fall through...
 
2039
             */
 
2040
            if( stream.flags & PFORMAT_LDOUBLE )
 
2041
              /*
 
2042
               * for a `long double' argument...
 
2043
               */
 
2044
              __pformat_efloat( va_arg( argv, long double ), &stream );
 
2045
 
 
2046
            else
 
2047
              /* or just a `double', which we promote to `long double',
 
2048
               * so the two may share a common format handler.
 
2049
               */
 
2050
              __pformat_efloat( (long double)(va_arg( argv, double )), &stream );
 
2051
 
 
2052
            goto format_scan;
 
2053
 
 
2054
          case 'f':
 
2055
            /*
 
2056
             * Fixed point format, using lower case for `inf' and
 
2057
             * `nan', when appropriate; select lower case mode, and
 
2058
             * simply fall through...
 
2059
             */
 
2060
            stream.flags |= PFORMAT_XCASE;
 
2061
 
 
2062
          case 'F':
 
2063
            /*
 
2064
             * Fixed case format using upper case, or lower case on
 
2065
             * fall through from above, for `INF' and `NAN'...
 
2066
             */
 
2067
            if( stream.flags & PFORMAT_LDOUBLE )
 
2068
              /*
 
2069
               * for a `long double' argument...
 
2070
               */
 
2071
              __pformat_float( va_arg( argv, long double ), &stream );
 
2072
 
 
2073
            else
 
2074
              /* or just a `double', which we promote to `long double',
 
2075
               * so the two may share a common format handler.
 
2076
               */
 
2077
              __pformat_float( (long double)(va_arg( argv, double )), &stream );
 
2078
 
 
2079
            goto format_scan;
 
2080
 
 
2081
          case 'g':
 
2082
            /*
 
2083
             * Generalised floating point format, with lower case
 
2084
             * exponent indicator when required; select lower case
 
2085
             * mode, and simply fall through...
 
2086
             */
 
2087
            stream.flags |= PFORMAT_XCASE;
 
2088
 
 
2089
          case 'G':
 
2090
            /*
 
2091
             * Generalised floating point format, with upper case,
 
2092
             * or on fall through from above, with lower case exponent
 
2093
             * indicator when required...
 
2094
             */
 
2095
            if( stream.flags & PFORMAT_LDOUBLE )
 
2096
              /*
 
2097
               * for a `long double' argument...
 
2098
               */
 
2099
              __pformat_gfloat( va_arg( argv, long double ), &stream );
 
2100
 
 
2101
            else
 
2102
              /* or just a `double', which we promote to `long double',
 
2103
               * so the two may share a common format handler.
 
2104
               */
 
2105
              __pformat_gfloat( (long double)(va_arg( argv, double )), &stream );
 
2106
 
 
2107
            goto format_scan;
 
2108
 
 
2109
          case 'a':
 
2110
            /*
 
2111
             * Hexadecimal floating point format, with lower case radix
 
2112
             * and exponent indicators; select the lower case mode, and
 
2113
             * fall through...
 
2114
             */
 
2115
            stream.flags |= PFORMAT_XCASE;
 
2116
 
 
2117
          case 'A':
 
2118
            /*
 
2119
             * Hexadecimal floating point format; handles radix and
 
2120
             * exponent indicators in either upper or lower case...
 
2121
             */
 
2122
            if( stream.flags & PFORMAT_LDOUBLE )
 
2123
              /*
 
2124
               * with a `long double' argument...
 
2125
               */
 
2126
              __pformat_xldouble( va_arg( argv, long double ), &stream );
 
2127
 
 
2128
            else
 
2129
              /* or just a `double'.
 
2130
               */
 
2131
              __pformat_xdouble( va_arg( argv, double ), &stream );
 
2132
 
 
2133
            goto format_scan;
 
2134
 
 
2135
          case 'n':
 
2136
            /*
 
2137
             * Save current output character count...
 
2138
             */
 
2139
            if( length == PFORMAT_LENGTH_CHAR )
 
2140
              /*
 
2141
               * to a signed `char' destination...
 
2142
               */
 
2143
              *va_arg( argv, char * ) = stream.count;
 
2144
 
 
2145
            else if( length == PFORMAT_LENGTH_SHORT )
 
2146
              /*
 
2147
               * or to a signed `short'...
 
2148
               */
 
2149
              *va_arg( argv, short * ) = stream.count;
 
2150
 
 
2151
            else if( length == PFORMAT_LENGTH_LONG )
 
2152
              /*
 
2153
               * or to a signed `long'...
 
2154
               */
 
2155
              *va_arg( argv, long * ) = stream.count;
 
2156
 
 
2157
            else if( length == PFORMAT_LENGTH_LLONG )
 
2158
              /*
 
2159
               * or to a signed `long long'...
 
2160
               */
 
2161
              *va_arg( argv, long long * ) = stream.count;
 
2162
 
 
2163
            else
 
2164
              /*
 
2165
               * or, by default, to a signed `int'.
 
2166
               */
 
2167
              *va_arg( argv, int * ) = stream.count;
 
2168
 
 
2169
            goto format_scan;
 
2170
 
 
2171
          /* Argument length modifiers...
 
2172
           * These are non-terminal; each sets the format parser
 
2173
           * into the PFORMAT_END state, and ends with a `break'.
 
2174
           */
 
2175
          case 'h':
 
2176
            /*
 
2177
             * Interpret the argument as explicitly of a `short'
 
2178
             * or `char' data type, truncated from the standard
 
2179
             * length defined for integer promotion.
 
2180
             */
 
2181
            if( *fmt == 'h' )
 
2182
            {
 
2183
              /* Modifier is `hh'; data type is `char' sized...
 
2184
               * Skip the second `h', and set length accordingly.
 
2185
               */
 
2186
              ++fmt;
 
2187
              length = PFORMAT_LENGTH_CHAR;
 
2188
            }
 
2189
 
 
2190
            else
 
2191
              /* Modifier is `h'; data type is `short' sized...
 
2192
               */
 
2193
              length = PFORMAT_LENGTH_SHORT;
 
2194
 
 
2195
            state = PFORMAT_END;
 
2196
            break;
 
2197
 
 
2198
          case 'j':
 
2199
            /*
 
2200
             * Interpret the argument as being of the same size as
 
2201
             * a `intmax_t' entity...
 
2202
             */
 
2203
            length = __pformat_arg_length( intmax_t );
 
2204
            state = PFORMAT_END;
 
2205
            break;
 
2206
          
 
2207
#         ifdef _WIN32
 
2208
 
 
2209
            case 'I':
 
2210
              /*
 
2211
               * The MSVCRT implementation of the printf() family of
 
2212
               * functions explicitly uses...
 
2213
               */
 
2214
              if( (fmt[0] == '6') && (fmt[1] == '4') )
 
2215
              {
 
2216
                /* I64' instead of `ll',
 
2217
                 * when referring to `long long' integer types...
 
2218
                 */
 
2219
                length = PFORMAT_LENGTH_LLONG;
 
2220
                fmt += 2;
 
2221
              }
 
2222
 
 
2223
              else if( (fmt[0] == '3') && (fmt[1] == '2') )
 
2224
              {
 
2225
                /* and `I32' instead of `l',
 
2226
                 * when referring to `long' integer types...
 
2227
                 */
 
2228
                length = PFORMAT_LENGTH_LONG;
 
2229
                fmt += 2;
 
2230
              }
 
2231
 
 
2232
              else
 
2233
                /* or unqualified `I' instead of `t' or `z',
 
2234
                 * when referring to `ptrdiff_t' or `size_t' entities;
 
2235
                 * (we will choose to map it to `ptrdiff_t').
 
2236
                 */
 
2237
                length = __pformat_arg_length( ptrdiff_t );
 
2238
 
 
2239
              state = PFORMAT_END;
 
2240
              break;
 
2241
 
 
2242
#         endif
 
2243
          
 
2244
          case 'l':
 
2245
            /*
 
2246
             * Interpret the argument as explicitly of a
 
2247
             * `long' or `long long' data type.
 
2248
             */
 
2249
            if( *fmt == 'l' )
 
2250
            {
 
2251
              /* Modifier is `ll'; data type is `long long' sized...
 
2252
               * Skip the second `l', and set length accordingly.
 
2253
               */
 
2254
              ++fmt;
 
2255
              length = PFORMAT_LENGTH_LLONG;
 
2256
            }
 
2257
 
 
2258
            else
 
2259
              /* Modifier is `l'; data type is `long' sized...
 
2260
               */
 
2261
              length = PFORMAT_LENGTH_LONG;
 
2262
 
 
2263
#           ifndef _WIN32
 
2264
              /*
 
2265
               * Microsoft's MSVCRT implementation also uses `l'
 
2266
               * as a modifier for `long double'; if we don't want
 
2267
               * to support that, we end this case here...
 
2268
               */
 
2269
              state = PFORMAT_END;
 
2270
              break;
 
2271
 
 
2272
              /* otherwise, we simply fall through...
 
2273
               */
 
2274
#           endif
 
2275
 
 
2276
          case 'L':
 
2277
            /*
 
2278
             * Identify the appropriate argument as a `long double',
 
2279
             * when associated with `%a', `%A', `%e', `%E', `%f', `%F',
 
2280
             * `%g' or `%G' format specifications.
 
2281
             */
 
2282
            stream.flags |= PFORMAT_LDOUBLE;
 
2283
            state = PFORMAT_END;
 
2284
            break;
 
2285
          
 
2286
          case 't':
 
2287
            /*
 
2288
             * Interpret the argument as being of the same size as
 
2289
             * a `ptrdiff_t' entity...
 
2290
             */
 
2291
            length = __pformat_arg_length( ptrdiff_t );
 
2292
            state = PFORMAT_END;
 
2293
            break;
 
2294
          
 
2295
          case 'z':
 
2296
            /*
 
2297
             * Interpret the argument as being of the same size as
 
2298
             * a `size_t' entity...
 
2299
             */
 
2300
            length = __pformat_arg_length( size_t );
 
2301
            state = PFORMAT_END;
 
2302
            break;
 
2303
          
 
2304
          /* Precision indicator...
 
2305
           * May appear once only; it must precede any modifier
 
2306
           * for argument length, or any data type specifier.
 
2307
           */
 
2308
          case '.':
 
2309
            if( state < PFORMAT_GET_PRECISION )
 
2310
            {
 
2311
              /* We haven't seen a precision specification yet,
 
2312
               * so initialise it to zero, (in case no digits follow),
 
2313
               * and accept any following digits as the precision.
 
2314
               */
 
2315
              stream.precision = 0;
 
2316
              width_spec = &stream.precision;
 
2317
              state = PFORMAT_GET_PRECISION;
 
2318
            }
 
2319
 
 
2320
            else
 
2321
              /* We've already seen a precision specification,
 
2322
               * so this is just junk; proceed to end game.
 
2323
               */
 
2324
              state = PFORMAT_END;
 
2325
 
 
2326
            /* Either way, we must not fall through here.
 
2327
             */
 
2328
            break;
 
2329
 
 
2330
          /* Variable field width, or precision specification,
 
2331
           * derived from the argument list...
 
2332
           */
 
2333
          case '*':
 
2334
            /*
 
2335
             * When this appears...
 
2336
             */
 
2337
            if(   width_spec
 
2338
            &&  ((state == PFORMAT_INIT) || (state == PFORMAT_GET_PRECISION)) )
 
2339
            {
 
2340
              /* in proper context; assign to field width
 
2341
               * or precision, as appropriate.
 
2342
               */
 
2343
              if( (*width_spec = va_arg( argv, int )) < 0 )
 
2344
              {
 
2345
                /* Assigned value was negative...
 
2346
                 */
 
2347
                if( state == PFORMAT_INIT )
 
2348
                {
 
2349
                  /* For field width, this is equivalent to
 
2350
                   * a positive value with the `-' flag...
 
2351
                   */
 
2352
                  stream.flags |= PFORMAT_LJUSTIFY;
 
2353
                  stream.width = -stream.width;
 
2354
                }
 
2355
 
 
2356
                else
 
2357
                  /* while as a precision specification,
 
2358
                   * it should simply be ignored.
 
2359
                   */
 
2360
                  stream.precision = PFORMAT_IGNORE;
 
2361
              }
 
2362
            }
 
2363
 
 
2364
            else
 
2365
              /* out of context; give up on width and precision
 
2366
               * specifications for this conversion.
 
2367
               */
 
2368
              state = PFORMAT_END;
 
2369
 
 
2370
            /* Mark as processed...
 
2371
             * we must not see `*' again, in this context.
 
2372
             */
 
2373
            width_spec = NULL;
 
2374
            break;
 
2375
 
 
2376
          /* Formatting flags...
 
2377
           * Must appear while in the PFORMAT_INIT state,
 
2378
           * and are non-terminal, so again, end with `break'.
 
2379
           */
 
2380
          case '#':
 
2381
            /*
 
2382
             * Select alternate PFORMAT_HASHED output style.
 
2383
             */
 
2384
            if( state == PFORMAT_INIT )
 
2385
              stream.flags |= PFORMAT_HASHED;
 
2386
            break;
 
2387
 
 
2388
          case '+':
 
2389
            /*
 
2390
             * Print a leading sign with numeric output,
 
2391
             * for both positive and negative values.
 
2392
             */
 
2393
            if( state == PFORMAT_INIT )
 
2394
              stream.flags |= PFORMAT_POSITIVE;
 
2395
            break;
 
2396
 
 
2397
          case '-':
 
2398
            /*
 
2399
             * Select left justification of displayed output
 
2400
             * data, within the output field width, instead of
 
2401
             * the default flush right justification.
 
2402
             */
 
2403
            if( state == PFORMAT_INIT )
 
2404
              stream.flags |= PFORMAT_LJUSTIFY;
 
2405
            break;
 
2406
 
 
2407
#         ifdef WITH_XSI_FEATURES
 
2408
 
 
2409
            case '\'':
 
2410
              /*
 
2411
               * This is an XSI extension to the POSIX standard,
 
2412
               * which we do not support, at present.
 
2413
               */
 
2414
              if( state == PFORMAT_INIT )
 
2415
                stream.flags |= PFORMAT_GROUPED;
 
2416
              break;
 
2417
 
 
2418
#         endif
 
2419
 
 
2420
          case '\x20':
 
2421
            /*
 
2422
             * Reserve a single space, within the output field,
 
2423
             * for display of the sign of signed data; this will
 
2424
             * be occupied by the minus sign, if the data value
 
2425
             * is negative, or by a plus sign if the data value
 
2426
             * is positive AND the `+' flag is also present, or
 
2427
             * by a space otherwise.  (Technically, this flag
 
2428
             * is redundant, if the `+' flag is present).
 
2429
             */
 
2430
            if( state == PFORMAT_INIT )
 
2431
              stream.flags |= PFORMAT_ADDSPACE;
 
2432
            break;
 
2433
 
 
2434
          case '0':
 
2435
            /*
 
2436
             * May represent a flag, to activate the `pad with zeros'
 
2437
             * option, or it may simply be a digit in a width or in a
 
2438
             * precision specification...
 
2439
             */
 
2440
            if( state == PFORMAT_INIT )
 
2441
            {
 
2442
              /* This is the flag usage...
 
2443
               */
 
2444
              stream.flags |= PFORMAT_ZEROFILL;
 
2445
              break;
 
2446
            }
 
2447
 
 
2448
          default:
 
2449
            /*
 
2450
             * If we didn't match anything above, then we will check
 
2451
             * for digits, which we may accumulate to generate field
 
2452
             * width or precision specifications...
 
2453
             */
 
2454
            if( (state < PFORMAT_END) && ('9' >= c) && (c >= '0') )
 
2455
            {
 
2456
              if( state == PFORMAT_INIT )
 
2457
                /*
 
2458
                 * Initial digits explicitly relate to field width...
 
2459
                 */
 
2460
                state = PFORMAT_SET_WIDTH;
 
2461
 
 
2462
              else if( state == PFORMAT_GET_PRECISION )
 
2463
                /*
 
2464
                 * while those following a precision indicator
 
2465
                 * explicitly relate to precision.
 
2466
                 */
 
2467
                state = PFORMAT_SET_PRECISION;
 
2468
 
 
2469
              if( width_spec )
 
2470
              {
 
2471
                /* We are accepting a width or precision specification...
 
2472
                 */
 
2473
                if( *width_spec < 0 )
 
2474
                  /*
 
2475
                   * and accumulation hasn't started yet; we simply
 
2476
                   * initialise the accumulator with the current digit
 
2477
                   * value, converting from ASCII to decimal.
 
2478
                   */
 
2479
                  *width_spec = c - '0';
 
2480
 
 
2481
                else
 
2482
                  /* Accumulation has already started; we perform a
 
2483
                   * `leftwise decimal digit shift' on the accumulator,
 
2484
                   * (i.e. multiply it by ten), then add the decimal
 
2485
                   * equivalent value of the current digit.
 
2486
                   */ 
 
2487
                  *width_spec = *width_spec * 10 + c - '0';
 
2488
              }
 
2489
            }
 
2490
 
 
2491
            else
 
2492
            {
 
2493
              /* We found a digit out of context, or some other character
 
2494
               * with no designated meaning; reject this format specification,
 
2495
               * backtrack, and emit it as literal text...
 
2496
               */
 
2497
              fmt = backtrack;
 
2498
              __pformat_putc( '%', &stream );
 
2499
              goto format_scan;
 
2500
            }
 
2501
        }
 
2502
      }
 
2503
    }
 
2504
 
 
2505
    else
 
2506
      /* We just parsed a character which is not included within any format
 
2507
       * specification; we simply emit it as a literal.
 
2508
       */
 
2509
      __pformat_putc( c, &stream );
 
2510
  }
 
2511
 
 
2512
  /* When we have fully dispatched the format string, the return value is the
 
2513
   * total number of bytes we transferred to the output destination.
 
2514
   */
 
2515
  return stream.count;
 
2516
}
 
2517