/ libxml2 / trio.c
trio.c
   1  /*************************************************************************
   2   *
   3   * $Id$
   4   *
   5   * Copyright (C) 1998 Bjorn Reese and Daniel Stenberg.
   6   *
   7   * Permission to use, copy, modify, and distribute this software for any
   8   * purpose with or without fee is hereby granted, provided that the above
   9   * copyright notice and this permission notice appear in all copies.
  10   *
  11   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  12   * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  13   * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
  14   * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
  15   *
  16   *************************************************************************
  17   *
  18   * A note to trio contributors:
  19   *
  20   * Avoid heap allocation at all costs to ensure that the trio functions
  21   * are async-safe. The exceptions are the printf/fprintf functions, which
  22   * uses fputc, and the asprintf functions and the <alloc> modifier, which
  23   * by design are required to allocate form the heap.
  24   *
  25   ************************************************************************/
  26  
  27  /*
  28   * TODO:
  29   *  - Scan is probably too permissive about its modifiers.
  30   *  - C escapes in %#[] ?
  31   *  - Multibyte characters (done for format parsing, except scan groups)
  32   *  - Complex numbers? (C99 _Complex)
  33   *  - Boolean values? (C99 _Bool)
  34   *  - C99 NaN(n-char-sequence) missing. The n-char-sequence can be used
  35   *    to print the mantissa, e.g. NaN(0xc000000000000000)
  36   *  - Should we support the GNU %a alloc modifier? GNU has an ugly hack
  37   *    for %a, because C99 used %a for other purposes. If specified as
  38   *    %as or %a[ it is interpreted as the alloc modifier, otherwise as
  39   *    the C99 hex-float. This means that you cannot scan %as as a hex-float
  40   *    immediately followed by an 's'.
  41   *  - Scanning of collating symbols.
  42   */
  43  
  44  /*************************************************************************
  45   * Trio include files
  46   */
  47  #include "triodef.h"
  48  #include "trio.h"
  49  #include "triop.h"
  50  #include "trionan.h"
  51  #if !defined(TRIO_MINIMAL)
  52  # include "triostr.h"
  53  #endif
  54  
  55  /**************************************************************************
  56   *
  57   * Definitions
  58   *
  59   *************************************************************************/
  60  
  61  #include <math.h>
  62  #include <limits.h>
  63  #include <float.h>
  64  
  65  #if (defined(__STDC_ISO_10646__) || defined(MB_LEN_MAX) \
  66       || defined(USE_MULTIBYTE) || TRIO_WIDECHAR) \
  67      && !defined(_WIN32_WCE)
  68  # define TRIO_COMPILER_SUPPORTS_MULTIBYTE
  69  # if !defined(MB_LEN_MAX)
  70  #  define MB_LEN_MAX 6
  71  # endif
  72  #endif
  73  
  74  #if (defined(TRIO_COMPILER_MSVC) && (_MSC_VER >= 1100)) || defined(TRIO_COMPILER_BCB)
  75  # define TRIO_COMPILER_SUPPORTS_MSVC_INT
  76  #endif
  77  
  78  #if defined(_WIN32_WCE)
  79  #include <wincecompat.h>
  80  #endif
  81  
  82  /*************************************************************************
  83   * Generic definitions
  84   */
  85  
  86  #if !(defined(DEBUG) || defined(NDEBUG))
  87  # define NDEBUG
  88  #endif
  89  
  90  #include <assert.h>
  91  #include <ctype.h>
  92  #if !defined(TRIO_COMPILER_SUPPORTS_C99)
  93  # define isblank(x) (((x)==32) || ((x)==9))
  94  #endif
  95  #if defined(TRIO_COMPILER_ANCIENT)
  96  # include <varargs.h>
  97  #else
  98  # include <stdarg.h>
  99  #endif
 100  #include <stddef.h>
 101  
 102  #if defined( HAVE_ERRNO_H ) || defined( __VMS )
 103  #include <errno.h>
 104  #endif
 105  
 106  #ifndef NULL
 107  # define NULL 0
 108  #endif
 109  #define NIL ((char)0)
 110  #ifndef FALSE
 111  # define FALSE (1 == 0)
 112  # define TRUE (! FALSE)
 113  #endif
 114  #define BOOLEAN_T int
 115  
 116  /* mincore() can be used for debugging purposes */
 117  #define VALID(x) (NULL != (x))
 118  
 119  #if TRIO_ERRORS
 120    /*
 121     * Encode the error code and the position. This is decoded
 122     * with TRIO_ERROR_CODE and TRIO_ERROR_POSITION.
 123     */
 124  # define TRIO_ERROR_RETURN(x,y) (- ((x) + ((y) << 8)))
 125  #else
 126  # define TRIO_ERROR_RETURN(x,y) (-1)
 127  #endif
 128  
 129  #ifndef VA_LIST_IS_ARRAY
 130  #define TRIO_VA_LIST_PTR	va_list *
 131  #define TRIO_VA_LIST_ADDR(l)	(&(l))
 132  #define TRIO_VA_LIST_DEREF(l)	(*(l))
 133  #else
 134  #define TRIO_VA_LIST_PTR	va_list
 135  #define TRIO_VA_LIST_ADDR(l)	(l)
 136  #define TRIO_VA_LIST_DEREF(l)	(l)
 137  #endif
 138  
 139  typedef unsigned long trio_flags_t;
 140  
 141  
 142  /*************************************************************************
 143   * Platform specific definitions
 144   */
 145  #if defined(TRIO_PLATFORM_UNIX) || defined(TRIO_PLATFORM_OS400)
 146  # include <unistd.h>
 147  # include <signal.h>
 148  # include <locale.h>
 149  # define USE_LOCALE
 150  #endif /* TRIO_PLATFORM_UNIX */
 151  #if defined(TRIO_PLATFORM_VMS)
 152  # include <unistd.h>
 153  #endif
 154  #if defined(TRIO_PLATFORM_WIN32)
 155  # if defined(_WIN32_WCE)
 156  #  include <wincecompat.h>
 157  # else
 158  #  include <io.h>
 159  #  define read _read
 160  #  define write _write
 161  # endif
 162  #endif /* TRIO_PLATFORM_WIN32 */
 163  
 164  #if TRIO_WIDECHAR
 165  # if defined(TRIO_COMPILER_SUPPORTS_ISO94)
 166  #  include <wchar.h>
 167  #  include <wctype.h>
 168  typedef wchar_t trio_wchar_t;
 169  typedef wint_t trio_wint_t;
 170  # else
 171  typedef char trio_wchar_t;
 172  typedef int trio_wint_t;
 173  #  define WCONST(x) L ## x
 174  #  define WEOF EOF
 175  #  define iswalnum(x) isalnum(x)
 176  #  define iswalpha(x) isalpha(x)
 177  #  define iswblank(x) isblank(x)
 178  #  define iswcntrl(x) iscntrl(x)
 179  #  define iswdigit(x) isdigit(x)
 180  #  define iswgraph(x) isgraph(x)
 181  #  define iswlower(x) islower(x)
 182  #  define iswprint(x) isprint(x)
 183  #  define iswpunct(x) ispunct(x)
 184  #  define iswspace(x) isspace(x)
 185  #  define iswupper(x) isupper(x)
 186  #  define iswxdigit(x) isxdigit(x)
 187  # endif
 188  #endif
 189  
 190  
 191  /*************************************************************************
 192   * Compiler dependent definitions
 193   */
 194  
 195  /* Support for long long */
 196  #ifndef __cplusplus
 197  # if !defined(USE_LONGLONG)
 198  #  if defined(TRIO_COMPILER_GCC) && !defined(__STRICT_ANSI__)
 199  #   define USE_LONGLONG
 200  #  elif defined(TRIO_COMPILER_SUNPRO)
 201  #   define USE_LONGLONG
 202  #  elif defined(_LONG_LONG) || defined(_LONGLONG)
 203  #   define USE_LONGLONG
 204  #  endif
 205  # endif
 206  #endif
 207  
 208  /* The extra long numbers */
 209  #if defined(USE_LONGLONG)
 210  typedef signed long long int trio_longlong_t;
 211  typedef unsigned long long int trio_ulonglong_t;
 212  #elif defined(TRIO_COMPILER_SUPPORTS_MSVC_INT)
 213  typedef signed __int64 trio_longlong_t;
 214  typedef unsigned __int64 trio_ulonglong_t;
 215  #else
 216  typedef TRIO_SIGNED long int trio_longlong_t;
 217  typedef unsigned long int trio_ulonglong_t;
 218  #endif
 219  
 220  /* Maximal and fixed integer types */
 221  #if defined(TRIO_COMPILER_SUPPORTS_C99) && !defined( __VMS )
 222  # include <stdint.h>
 223  typedef intmax_t trio_intmax_t;
 224  typedef uintmax_t trio_uintmax_t;
 225  typedef int8_t trio_int8_t;
 226  typedef int16_t trio_int16_t;
 227  typedef int32_t trio_int32_t;
 228  typedef int64_t trio_int64_t;
 229  #elif defined(TRIO_COMPILER_SUPPORTS_UNIX98) || defined( __VMS )
 230  # include <inttypes.h>
 231  #ifdef __VMS
 232  typedef long long int          intmax_t;
 233  typedef unsigned long long int uintmax_t;
 234  #endif
 235  typedef intmax_t trio_intmax_t;
 236  typedef uintmax_t trio_uintmax_t;
 237  typedef int8_t trio_int8_t;
 238  typedef int16_t trio_int16_t;
 239  typedef int32_t trio_int32_t;
 240  typedef int64_t trio_int64_t;
 241  #elif defined(TRIO_COMPILER_SUPPORTS_MSVC_INT)
 242  typedef trio_longlong_t trio_intmax_t;
 243  typedef trio_ulonglong_t trio_uintmax_t;
 244  typedef __int8 trio_int8_t;
 245  typedef __int16 trio_int16_t;
 246  typedef __int32 trio_int32_t;
 247  typedef __int64 trio_int64_t;
 248  #else
 249  typedef trio_longlong_t trio_intmax_t;
 250  typedef trio_ulonglong_t trio_uintmax_t;
 251  # if defined(TRIO_INT8_T)
 252  typedef TRIO_INT8_T trio_int8_t;
 253  # else
 254  typedef TRIO_SIGNED char trio_int8_t;
 255  # endif
 256  # if defined(TRIO_INT16_T)
 257  typedef TRIO_INT16_T trio_int16_t;
 258  # else
 259  typedef TRIO_SIGNED short trio_int16_t;
 260  # endif
 261  # if defined(TRIO_INT32_T)
 262  typedef TRIO_INT32_T trio_int32_t;
 263  # else
 264  typedef TRIO_SIGNED int trio_int32_t;
 265  # endif
 266  # if defined(TRIO_INT64_T)
 267  typedef TRIO_INT64_T trio_int64_t;
 268  # else
 269  typedef trio_longlong_t trio_int64_t;
 270  # endif
 271  #endif
 272  
 273  #if (!(defined(TRIO_COMPILER_SUPPORTS_C99) \
 274   || defined(TRIO_COMPILER_SUPPORTS_UNIX01))) \
 275   && !defined(_WIN32_WCE)
 276  # define floorl(x) floor((double)(x))
 277  # define fmodl(x,y) fmod((double)(x),(double)(y))
 278  # define powl(x,y) pow((double)(x),(double)(y))
 279  #endif
 280  
 281  #define TRIO_FABS(x) (((x) < 0.0) ? -(x) : (x))
 282  
 283  /*************************************************************************
 284   * Internal Definitions
 285   */
 286  
 287  #ifndef DECIMAL_DIG
 288  # define DECIMAL_DIG DBL_DIG
 289  #endif
 290  
 291  /* Long double sizes */
 292  #ifdef LDBL_DIG
 293  # define MAX_MANTISSA_DIGITS LDBL_DIG
 294  # define MAX_EXPONENT_DIGITS 4
 295  # define MAX_DOUBLE_DIGITS LDBL_MAX_10_EXP
 296  #else
 297  # define MAX_MANTISSA_DIGITS DECIMAL_DIG
 298  # define MAX_EXPONENT_DIGITS 3
 299  # define MAX_DOUBLE_DIGITS DBL_MAX_10_EXP
 300  #endif
 301  
 302  #if defined(TRIO_COMPILER_ANCIENT) || !defined(LDBL_DIG)
 303  # undef LDBL_DIG
 304  # undef LDBL_MANT_DIG
 305  # undef LDBL_EPSILON
 306  # define LDBL_DIG DBL_DIG
 307  # define LDBL_MANT_DIG DBL_MANT_DIG
 308  # define LDBL_EPSILON DBL_EPSILON
 309  #endif
 310  
 311  /* The maximal number of digits is for base 2 */
 312  #define MAX_CHARS_IN(x) (sizeof(x) * CHAR_BIT)
 313  /* The width of a pointer. The number of bits in a hex digit is 4 */
 314  #define POINTER_WIDTH ((sizeof("0x") - 1) + sizeof(trio_pointer_t) * CHAR_BIT / 4)
 315  
 316  /* Infinite and Not-A-Number for floating-point */
 317  #define INFINITE_LOWER "inf"
 318  #define INFINITE_UPPER "INF"
 319  #define LONG_INFINITE_LOWER "infinite"
 320  #define LONG_INFINITE_UPPER "INFINITE"
 321  #define NAN_LOWER "nan"
 322  #define NAN_UPPER "NAN"
 323  
 324  #if !defined(HAVE_ISASCII) && !defined(isascii)
 325  #ifndef __VMS
 326  # define isascii(x) ((unsigned int)(x) < 128)
 327  #endif
 328  #endif
 329  
 330  /* Various constants */
 331  enum {
 332    TYPE_PRINT = 1,
 333    TYPE_SCAN  = 2,
 334  
 335    /* Flags. FLAGS_LAST must be less than ULONG_MAX */
 336    FLAGS_NEW                 = 0,
 337    FLAGS_STICKY              = 1,
 338    FLAGS_SPACE               = 2 * FLAGS_STICKY,
 339    FLAGS_SHOWSIGN            = 2 * FLAGS_SPACE,
 340    FLAGS_LEFTADJUST          = 2 * FLAGS_SHOWSIGN,
 341    FLAGS_ALTERNATIVE         = 2 * FLAGS_LEFTADJUST,
 342    FLAGS_SHORT               = 2 * FLAGS_ALTERNATIVE,
 343    FLAGS_SHORTSHORT          = 2 * FLAGS_SHORT,
 344    FLAGS_LONG                = 2 * FLAGS_SHORTSHORT,
 345    FLAGS_QUAD                = 2 * FLAGS_LONG,
 346    FLAGS_LONGDOUBLE          = 2 * FLAGS_QUAD,
 347    FLAGS_SIZE_T              = 2 * FLAGS_LONGDOUBLE,
 348    FLAGS_PTRDIFF_T           = 2 * FLAGS_SIZE_T,
 349    FLAGS_INTMAX_T            = 2 * FLAGS_PTRDIFF_T,
 350    FLAGS_NILPADDING          = 2 * FLAGS_INTMAX_T,
 351    FLAGS_UNSIGNED            = 2 * FLAGS_NILPADDING,
 352    FLAGS_UPPER               = 2 * FLAGS_UNSIGNED,
 353    FLAGS_WIDTH               = 2 * FLAGS_UPPER,
 354    FLAGS_WIDTH_PARAMETER     = 2 * FLAGS_WIDTH,
 355    FLAGS_PRECISION           = 2 * FLAGS_WIDTH_PARAMETER,
 356    FLAGS_PRECISION_PARAMETER = 2 * FLAGS_PRECISION,
 357    FLAGS_BASE                = 2 * FLAGS_PRECISION_PARAMETER,
 358    FLAGS_BASE_PARAMETER      = 2 * FLAGS_BASE,
 359    FLAGS_FLOAT_E             = 2 * FLAGS_BASE_PARAMETER,
 360    FLAGS_FLOAT_G             = 2 * FLAGS_FLOAT_E,
 361    FLAGS_QUOTE               = 2 * FLAGS_FLOAT_G,
 362    FLAGS_WIDECHAR            = 2 * FLAGS_QUOTE,
 363    FLAGS_ALLOC               = 2 * FLAGS_WIDECHAR,
 364    FLAGS_IGNORE              = 2 * FLAGS_ALLOC,
 365    FLAGS_IGNORE_PARAMETER    = 2 * FLAGS_IGNORE,
 366    FLAGS_VARSIZE_PARAMETER   = 2 * FLAGS_IGNORE_PARAMETER,
 367    FLAGS_FIXED_SIZE          = 2 * FLAGS_VARSIZE_PARAMETER,
 368    FLAGS_LAST                = FLAGS_FIXED_SIZE,
 369    /* Reused flags */
 370    FLAGS_EXCLUDE             = FLAGS_SHORT,
 371    FLAGS_USER_DEFINED        = FLAGS_IGNORE,
 372    FLAGS_ROUNDING            = FLAGS_INTMAX_T,
 373    /* Compounded flags */
 374    FLAGS_ALL_VARSIZES        = FLAGS_LONG | FLAGS_QUAD | FLAGS_INTMAX_T | FLAGS_PTRDIFF_T | FLAGS_SIZE_T,
 375    FLAGS_ALL_SIZES           = FLAGS_ALL_VARSIZES | FLAGS_SHORTSHORT | FLAGS_SHORT,
 376  
 377    NO_POSITION  = -1,
 378    NO_WIDTH     =  0,
 379    NO_PRECISION = -1,
 380    NO_SIZE      = -1,
 381  
 382    /* Do not change these */
 383    NO_BASE      = -1,
 384    MIN_BASE     =  2,
 385    MAX_BASE     = 36,
 386    BASE_BINARY  =  2,
 387    BASE_OCTAL   =  8,
 388    BASE_DECIMAL = 10,
 389    BASE_HEX     = 16,
 390  
 391    /* Maximal number of allowed parameters */
 392    MAX_PARAMETERS = 64,
 393    /* Maximal number of characters in class */
 394    MAX_CHARACTER_CLASS = UCHAR_MAX + 1,
 395  
 396    /* Maximal string lengths for user-defined specifiers */
 397    MAX_USER_NAME = 64,
 398    MAX_USER_DATA = 256,
 399  
 400    /* Maximal length of locale separator strings */
 401    MAX_LOCALE_SEPARATOR_LENGTH = MB_LEN_MAX,
 402    /* Maximal number of integers in grouping */
 403    MAX_LOCALE_GROUPS = 64,
 404  
 405    /* Initial size of asprintf buffer */
 406    DYNAMIC_START_SIZE = 32
 407  };
 408  
 409  #define NO_GROUPING ((int)CHAR_MAX)
 410  
 411  /* Fundamental formatting parameter types */
 412  #define FORMAT_UNKNOWN   0
 413  #define FORMAT_INT       1
 414  #define FORMAT_DOUBLE    2
 415  #define FORMAT_CHAR      3
 416  #define FORMAT_STRING    4
 417  #define FORMAT_POINTER   5
 418  #define FORMAT_COUNT     6
 419  #define FORMAT_PARAMETER 7
 420  #define FORMAT_GROUP     8
 421  #if TRIO_GNU
 422  # define FORMAT_ERRNO    9
 423  #endif
 424  #if TRIO_EXTENSION
 425  # define FORMAT_USER_DEFINED 10
 426  #endif
 427  
 428  /* Character constants */
 429  #define CHAR_IDENTIFIER '%'
 430  #define CHAR_BACKSLASH '\\'
 431  #define CHAR_QUOTE '\"'
 432  #define CHAR_ADJUST ' '
 433  
 434  /* Character class expressions */
 435  #define CLASS_ALNUM "[:alnum:]"
 436  #define CLASS_ALPHA "[:alpha:]"
 437  #define CLASS_BLANK "[:blank:]"
 438  #define CLASS_CNTRL "[:cntrl:]"
 439  #define CLASS_DIGIT "[:digit:]"
 440  #define CLASS_GRAPH "[:graph:]"
 441  #define CLASS_LOWER "[:lower:]"
 442  #define CLASS_PRINT "[:print:]"
 443  #define CLASS_PUNCT "[:punct:]"
 444  #define CLASS_SPACE "[:space:]"
 445  #define CLASS_UPPER "[:upper:]"
 446  #define CLASS_XDIGIT "[:xdigit:]"
 447  
 448  /*
 449   * SPECIFIERS:
 450   *
 451   *
 452   * a  Hex-float
 453   * A  Hex-float
 454   * c  Character
 455   * C  Widechar character (wint_t)
 456   * d  Decimal
 457   * e  Float
 458   * E  Float
 459   * F  Float
 460   * F  Float
 461   * g  Float
 462   * G  Float
 463   * i  Integer
 464   * m  Error message
 465   * n  Count
 466   * o  Octal
 467   * p  Pointer
 468   * s  String
 469   * S  Widechar string (wchar_t *)
 470   * u  Unsigned
 471   * x  Hex
 472   * X  Hex
 473   * [] Group
 474   * <> User-defined
 475   *
 476   * Reserved:
 477   *
 478   * D  Binary Coded Decimal %D(length,precision) (OS/390)
 479   */
 480  #define SPECIFIER_CHAR 'c'
 481  #define SPECIFIER_STRING 's'
 482  #define SPECIFIER_DECIMAL 'd'
 483  #define SPECIFIER_INTEGER 'i'
 484  #define SPECIFIER_UNSIGNED 'u'
 485  #define SPECIFIER_OCTAL 'o'
 486  #define SPECIFIER_HEX 'x'
 487  #define SPECIFIER_HEX_UPPER 'X'
 488  #define SPECIFIER_FLOAT_E 'e'
 489  #define SPECIFIER_FLOAT_E_UPPER 'E'
 490  #define SPECIFIER_FLOAT_F 'f'
 491  #define SPECIFIER_FLOAT_F_UPPER 'F'
 492  #define SPECIFIER_FLOAT_G 'g'
 493  #define SPECIFIER_FLOAT_G_UPPER 'G'
 494  #define SPECIFIER_POINTER 'p'
 495  #define SPECIFIER_GROUP '['
 496  #define SPECIFIER_UNGROUP ']'
 497  #define SPECIFIER_COUNT 'n'
 498  #if TRIO_UNIX98
 499  # define SPECIFIER_CHAR_UPPER 'C'
 500  # define SPECIFIER_STRING_UPPER 'S'
 501  #endif
 502  #if TRIO_C99
 503  # define SPECIFIER_HEXFLOAT 'a'
 504  # define SPECIFIER_HEXFLOAT_UPPER 'A'
 505  #endif
 506  #if TRIO_GNU
 507  # define SPECIFIER_ERRNO 'm'
 508  #endif
 509  #if TRIO_EXTENSION
 510  # define SPECIFIER_BINARY 'b'
 511  # define SPECIFIER_BINARY_UPPER 'B'
 512  # define SPECIFIER_USER_DEFINED_BEGIN '<'
 513  # define SPECIFIER_USER_DEFINED_END '>'
 514  # define SPECIFIER_USER_DEFINED_SEPARATOR ':'
 515  #endif
 516  
 517  /*
 518   * QUALIFIERS:
 519   *
 520   *
 521   * Numbers = d,i,o,u,x,X
 522   * Float = a,A,e,E,f,F,g,G
 523   * String = s
 524   * Char = c
 525   *
 526   *
 527   * 9$ Position
 528   *      Use the 9th parameter. 9 can be any number between 1 and
 529   *      the maximal argument
 530   *
 531   * 9 Width
 532   *      Set width to 9. 9 can be any number, but must not be postfixed
 533   *      by '$'
 534   *
 535   * h  Short
 536   *    Numbers:
 537   *      (unsigned) short int
 538   *
 539   * hh Short short
 540   *    Numbers:
 541   *      (unsigned) char
 542   *
 543   * l  Long
 544   *    Numbers:
 545   *      (unsigned) long int
 546   *    String:
 547   *      as the S specifier
 548   *    Char:
 549   *      as the C specifier
 550   *
 551   * ll Long Long
 552   *    Numbers:
 553   *      (unsigned) long long int
 554   *
 555   * L  Long Double
 556   *    Float
 557   *      long double
 558   *
 559   * #  Alternative
 560   *    Float:
 561   *      Decimal-point is always present
 562   *    String:
 563   *      non-printable characters are handled as \number
 564   *
 565   *    Spacing
 566   *
 567   * +  Sign
 568   *
 569   * -  Alignment
 570   *
 571   * .  Precision
 572   *
 573   * *  Parameter
 574   *    print: use parameter
 575   *    scan: no parameter (ignore)
 576   *
 577   * q  Quad
 578   *
 579   * Z  size_t
 580   *
 581   * w  Widechar
 582   *
 583   * '  Thousands/quote
 584   *    Numbers:
 585   *      Integer part grouped in thousands
 586   *    Binary numbers:
 587   *      Number grouped in nibbles (4 bits)
 588   *    String:
 589   *      Quoted string
 590   *
 591   * j  intmax_t
 592   * t  prtdiff_t
 593   * z  size_t
 594   *
 595   * !  Sticky
 596   * @  Parameter (for both print and scan)
 597   *
 598   * I  n-bit Integer
 599   *    Numbers:
 600   *      The following options exists
 601   *        I8  = 8-bit integer
 602   *        I16 = 16-bit integer
 603   *        I32 = 32-bit integer
 604   *        I64 = 64-bit integer
 605   */
 606  #define QUALIFIER_POSITION '$'
 607  #define QUALIFIER_SHORT 'h'
 608  #define QUALIFIER_LONG 'l'
 609  #define QUALIFIER_LONG_UPPER 'L'
 610  #define QUALIFIER_ALTERNATIVE '#'
 611  #define QUALIFIER_SPACE ' '
 612  #define QUALIFIER_PLUS '+'
 613  #define QUALIFIER_MINUS '-'
 614  #define QUALIFIER_DOT '.'
 615  #define QUALIFIER_STAR '*'
 616  #define QUALIFIER_CIRCUMFLEX '^' /* For scanlists */
 617  #if TRIO_C99
 618  # define QUALIFIER_SIZE_T 'z'
 619  # define QUALIFIER_PTRDIFF_T 't'
 620  # define QUALIFIER_INTMAX_T 'j'
 621  #endif
 622  #if TRIO_BSD || TRIO_GNU
 623  # define QUALIFIER_QUAD 'q'
 624  #endif
 625  #if TRIO_GNU
 626  # define QUALIFIER_SIZE_T_UPPER 'Z'
 627  #endif
 628  #if TRIO_MISC
 629  # define QUALIFIER_WIDECHAR 'w'
 630  #endif
 631  #if TRIO_MICROSOFT
 632  # define QUALIFIER_FIXED_SIZE 'I'
 633  #endif
 634  #if TRIO_EXTENSION
 635  # define QUALIFIER_QUOTE '\''
 636  # define QUALIFIER_STICKY '!'
 637  # define QUALIFIER_VARSIZE '&' /* This should remain undocumented */
 638  # define QUALIFIER_PARAM '@' /* Experimental */
 639  # define QUALIFIER_COLON ':' /* For scanlists */
 640  # define QUALIFIER_EQUAL '=' /* For scanlists */
 641  # define QUALIFIER_ROUNDING_UPPER 'R'
 642  #endif
 643  
 644  
 645  /*************************************************************************
 646   *
 647   * Internal Structures
 648   *
 649   *************************************************************************/
 650  
 651  /* Parameters */
 652  typedef struct {
 653    /* An indication of which entry in the data union is used */
 654    int type;
 655    /* The flags */
 656    trio_flags_t flags;
 657    /* The width qualifier */
 658    int width;
 659    /* The precision qualifier */
 660    int precision;
 661    /* The base qualifier */
 662    int base;
 663    /* The size for the variable size qualifier */
 664    int varsize;
 665    /* The marker of the end of the specifier */
 666    int indexAfterSpecifier;
 667    /* The data from the argument list */
 668    union {
 669      char *string;
 670  #if TRIO_WIDECHAR
 671      trio_wchar_t *wstring;
 672  #endif
 673      trio_pointer_t pointer;
 674      union {
 675        trio_intmax_t as_signed;
 676        trio_uintmax_t as_unsigned;
 677      } number;
 678      double doubleNumber;
 679      double *doublePointer;
 680      trio_long_double_t longdoubleNumber;
 681      trio_long_double_t *longdoublePointer;
 682      int errorNumber;
 683    } data;
 684    /* For the user-defined specifier */
 685    char user_name[MAX_USER_NAME];
 686    char user_data[MAX_USER_DATA];
 687  } trio_parameter_t;
 688  
 689  /* Container for customized functions */
 690  typedef struct {
 691    union {
 692      trio_outstream_t out;
 693      trio_instream_t in;
 694    } stream;
 695    trio_pointer_t closure;
 696  } trio_custom_t;
 697  
 698  /* General trio "class" */
 699  typedef struct _trio_class_t {
 700    /*
 701     * The function to write characters to a stream.
 702     */
 703    void (*OutStream) TRIO_PROTO((struct _trio_class_t *, int));
 704    /*
 705     * The function to read characters from a stream.
 706     */
 707    void (*InStream) TRIO_PROTO((struct _trio_class_t *, int *));
 708    /*
 709     * The current location in the stream.
 710     */
 711    trio_pointer_t location;
 712    /*
 713     * The character currently being processed.
 714     */
 715    int current;
 716    /*
 717     * The number of characters that would have been written/read
 718     * if there had been sufficient space.
 719     */
 720    int processed;
 721    /*
 722     * The number of characters that are actually written/read.
 723     * Processed and committed will only differ for the *nprintf
 724     * and *nscanf functions.
 725     */
 726    int committed;
 727    /*
 728     * The upper limit of characters that may be written/read.
 729     */
 730    int max;
 731    /*
 732     * The last output error that was detected.
 733     */
 734    int error;
 735  } trio_class_t;
 736  
 737  /* References (for user-defined callbacks) */
 738  typedef struct _trio_reference_t {
 739    trio_class_t *data;
 740    trio_parameter_t *parameter;
 741  } trio_reference_t;
 742  
 743  /* Registered entries (for user-defined callbacks) */
 744  typedef struct _trio_userdef_t {
 745    struct _trio_userdef_t *next;
 746    trio_callback_t callback;
 747    char *name;
 748  } trio_userdef_t;
 749  
 750  /*************************************************************************
 751   *
 752   * Internal Variables
 753   *
 754   *************************************************************************/
 755  
 756  static TRIO_CONST char rcsid[] = "@(#)$Id$";
 757  
 758  /*
 759   * Need this to workaround a parser bug in HP C/iX compiler that fails
 760   * to resolves macro definitions that includes type 'long double',
 761   * e.g: va_arg(arg_ptr, long double)
 762   */
 763  #if defined(TRIO_PLATFORM_MPEIX)
 764  static TRIO_CONST trio_long_double_t ___dummy_long_double = 0;
 765  #endif
 766  
 767  static TRIO_CONST char internalNullString[] = "(nil)";
 768  
 769  #if defined(USE_LOCALE)
 770  static struct lconv *internalLocaleValues = NULL;
 771  #endif
 772  
 773  /*
 774   * UNIX98 says "in a locale where the radix character is not defined,
 775   * the radix character defaults to a period (.)"
 776   */
 777  static int internalDecimalPointLength = 1;
 778  static int internalThousandSeparatorLength = 1;
 779  static char internalDecimalPoint = '.';
 780  static char internalDecimalPointString[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ".";
 781  static char internalThousandSeparator[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ",";
 782  static char internalGrouping[MAX_LOCALE_GROUPS] = { (char)NO_GROUPING };
 783  
 784  static TRIO_CONST char internalDigitsLower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
 785  static TRIO_CONST char internalDigitsUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 786  static BOOLEAN_T internalDigitsUnconverted = TRUE;
 787  static int internalDigitArray[128];
 788  #if TRIO_EXTENSION
 789  static BOOLEAN_T internalCollationUnconverted = TRUE;
 790  static char internalCollationArray[MAX_CHARACTER_CLASS][MAX_CHARACTER_CLASS];
 791  #endif
 792  
 793  #if TRIO_EXTENSION
 794  static TRIO_VOLATILE trio_callback_t internalEnterCriticalRegion = NULL;
 795  static TRIO_VOLATILE trio_callback_t internalLeaveCriticalRegion = NULL;
 796  static trio_userdef_t *internalUserDef = NULL;
 797  #endif
 798  
 799  
 800  /*************************************************************************
 801   *
 802   * Internal Functions
 803   *
 804   ************************************************************************/
 805  
 806  #if defined(TRIO_MINIMAL)
 807  # define TRIO_STRING_PUBLIC static
 808  # include "triostr.c"
 809  #endif /* defined(TRIO_MINIMAL) */
 810  
 811  /*************************************************************************
 812   * TrioIsQualifier
 813   *
 814   * Description:
 815   *  Remember to add all new qualifiers to this function.
 816   *  QUALIFIER_POSITION must not be added.
 817   */
 818  TRIO_PRIVATE BOOLEAN_T
 819  TrioIsQualifier
 820  TRIO_ARGS1((character),
 821  	   TRIO_CONST char character)
 822  {
 823    /* QUALIFIER_POSITION is not included */
 824    switch (character)
 825      {
 826      case '0': case '1': case '2': case '3': case '4':
 827      case '5': case '6': case '7': case '8': case '9':
 828      case QUALIFIER_PLUS:
 829      case QUALIFIER_MINUS:
 830      case QUALIFIER_SPACE:
 831      case QUALIFIER_DOT:
 832      case QUALIFIER_STAR:
 833      case QUALIFIER_ALTERNATIVE:
 834      case QUALIFIER_SHORT:
 835      case QUALIFIER_LONG:
 836      case QUALIFIER_LONG_UPPER:
 837      case QUALIFIER_CIRCUMFLEX:
 838  #if defined(QUALIFIER_SIZE_T)
 839      case QUALIFIER_SIZE_T:
 840  #endif
 841  #if defined(QUALIFIER_PTRDIFF_T)
 842      case QUALIFIER_PTRDIFF_T:
 843  #endif
 844  #if defined(QUALIFIER_INTMAX_T)
 845      case QUALIFIER_INTMAX_T:
 846  #endif
 847  #if defined(QUALIFIER_QUAD)
 848      case QUALIFIER_QUAD:
 849  #endif
 850  #if defined(QUALIFIER_SIZE_T_UPPER)
 851      case QUALIFIER_SIZE_T_UPPER:
 852  #endif
 853  #if defined(QUALIFIER_WIDECHAR)
 854      case QUALIFIER_WIDECHAR:
 855  #endif
 856  #if defined(QUALIFIER_QUOTE)
 857      case QUALIFIER_QUOTE:
 858  #endif
 859  #if defined(QUALIFIER_STICKY)
 860      case QUALIFIER_STICKY:
 861  #endif
 862  #if defined(QUALIFIER_VARSIZE)
 863      case QUALIFIER_VARSIZE:
 864  #endif
 865  #if defined(QUALIFIER_PARAM)
 866      case QUALIFIER_PARAM:
 867  #endif
 868  #if defined(QUALIFIER_FIXED_SIZE)
 869      case QUALIFIER_FIXED_SIZE:
 870  #endif
 871  #if defined(QUALIFIER_ROUNDING_UPPER)
 872      case QUALIFIER_ROUNDING_UPPER:
 873  #endif
 874        return TRUE;
 875      default:
 876        return FALSE;
 877      }
 878  }
 879  
 880  /*************************************************************************
 881   * TrioSetLocale
 882   */
 883  #if defined(USE_LOCALE)
 884  TRIO_PRIVATE void
 885  TrioSetLocale(TRIO_NOARGS)
 886  {
 887    internalLocaleValues = (struct lconv *)localeconv();
 888    if (internalLocaleValues)
 889      {
 890        if ((internalLocaleValues->decimal_point) &&
 891  	  (internalLocaleValues->decimal_point[0] != NIL))
 892  	{
 893  	  internalDecimalPointLength = trio_length(internalLocaleValues->decimal_point);
 894  	  if (internalDecimalPointLength == 1)
 895  	    {
 896  	      internalDecimalPoint = internalLocaleValues->decimal_point[0];
 897  	    }
 898  	  else
 899  	    {
 900  	      internalDecimalPoint = NIL;
 901  	      trio_copy_max(internalDecimalPointString,
 902  			    sizeof(internalDecimalPointString),
 903  			    internalLocaleValues->decimal_point);
 904  	    }
 905  	}
 906        if ((internalLocaleValues->thousands_sep) &&
 907  	  (internalLocaleValues->thousands_sep[0] != NIL))
 908  	{
 909  	  trio_copy_max(internalThousandSeparator,
 910  			sizeof(internalThousandSeparator),
 911  			internalLocaleValues->thousands_sep);
 912  	  internalThousandSeparatorLength = trio_length(internalThousandSeparator);
 913  	}
 914        if ((internalLocaleValues->grouping) &&
 915  	  (internalLocaleValues->grouping[0] != NIL))
 916  	{
 917  	  trio_copy_max(internalGrouping,
 918  			sizeof(internalGrouping),
 919  			internalLocaleValues->grouping);
 920  	}
 921      }
 922  }
 923  #endif /* defined(USE_LOCALE) */
 924  
 925  TRIO_PRIVATE int
 926  TrioCalcThousandSeparatorLength
 927  TRIO_ARGS1((digits),
 928  	   int digits)
 929  {
 930  #if TRIO_EXTENSION
 931    int count = 0;
 932    int step = NO_GROUPING;
 933    char *groupingPointer = internalGrouping;
 934  
 935    while (digits > 0)
 936      {
 937        if (*groupingPointer == CHAR_MAX)
 938  	{
 939  	  /* Disable grouping */
 940  	  break; /* while */
 941  	}
 942        else if (*groupingPointer == 0)
 943  	{
 944  	  /* Repeat last group */
 945  	  if (step == NO_GROUPING)
 946  	    {
 947  	      /* Error in locale */
 948  	      break; /* while */
 949  	    }
 950  	}
 951        else
 952  	{
 953  	  step = *groupingPointer++;
 954  	}
 955        if (digits > step)
 956  	count += internalThousandSeparatorLength;
 957        digits -= step;
 958      }
 959    return count;
 960  #else
 961    return 0;
 962  #endif
 963  }
 964  
 965  TRIO_PRIVATE BOOLEAN_T
 966  TrioFollowedBySeparator
 967  TRIO_ARGS1((position),
 968  	   int position)
 969  {
 970  #if TRIO_EXTENSION
 971    int step = 0;
 972    char *groupingPointer = internalGrouping;
 973  
 974    position--;
 975    if (position == 0)
 976      return FALSE;
 977    while (position > 0)
 978      {
 979        if (*groupingPointer == CHAR_MAX)
 980  	{
 981  	  /* Disable grouping */
 982  	  break; /* while */
 983  	}
 984        else if (*groupingPointer != 0)
 985  	{
 986  	  step = *groupingPointer++;
 987  	}
 988        if (step == 0)
 989  	break;
 990        position -= step;
 991      }
 992    return (position == 0);
 993  #else
 994    return FALSE;
 995  #endif
 996  }
 997  
 998  /*************************************************************************
 999   * TrioGetPosition
1000   *
1001   * Get the %n$ position.
1002   */
1003  TRIO_PRIVATE int
1004  TrioGetPosition
1005  TRIO_ARGS2((format, indexPointer),
1006  	   TRIO_CONST char *format,
1007  	   int *indexPointer)
1008  {
1009  #if TRIO_UNIX98
1010    char *tmpformat;
1011    int number = 0;
1012    int index = *indexPointer;
1013  
1014    number = (int)trio_to_long(&format[index], &tmpformat, BASE_DECIMAL);
1015    index = (int)(tmpformat - format);
1016    if ((number != 0) && (QUALIFIER_POSITION == format[index++]))
1017      {
1018        *indexPointer = index;
1019        /*
1020         * number is decreased by 1, because n$ starts from 1, whereas
1021         * the array it is indexing starts from 0.
1022         */
1023        return number - 1;
1024      }
1025  #endif
1026    return NO_POSITION;
1027  }
1028  
1029  #if TRIO_EXTENSION
1030  /*************************************************************************
1031   * TrioFindNamespace
1032   *
1033   * Find registered user-defined specifier.
1034   * The prev argument is used for optimization only.
1035   */
1036  TRIO_PRIVATE trio_userdef_t *
1037  TrioFindNamespace
1038  TRIO_ARGS2((name, prev),
1039  	   TRIO_CONST char *name,
1040  	   trio_userdef_t **prev)
1041  {
1042    trio_userdef_t *def;
1043  
1044    if (internalEnterCriticalRegion)
1045      (void)internalEnterCriticalRegion(NULL);
1046  
1047    for (def = internalUserDef; def; def = def->next)
1048      {
1049        /* Case-sensitive string comparison */
1050        if (trio_equal_case(def->name, name))
1051  	break;
1052  
1053        if (prev)
1054  	*prev = def;
1055      }
1056  
1057    if (internalLeaveCriticalRegion)
1058      (void)internalLeaveCriticalRegion(NULL);
1059  
1060    return def;
1061  }
1062  #endif
1063  
1064  /*************************************************************************
1065   * TrioPower
1066   *
1067   * Description:
1068   *  Calculate pow(base, exponent), where number and exponent are integers.
1069   */
1070  TRIO_PRIVATE trio_long_double_t
1071  TrioPower
1072  TRIO_ARGS2((number, exponent),
1073  	   int number,
1074  	   int exponent)
1075  {
1076    trio_long_double_t result;
1077  
1078    if (number == 10)
1079      {
1080        switch (exponent)
1081  	{
1082  	  /* Speed up calculation of common cases */
1083  	case 0:
1084  	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E-1);
1085  	  break;
1086  	case 1:
1087  	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+0);
1088  	  break;
1089  	case 2:
1090  	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+1);
1091  	  break;
1092  	case 3:
1093  	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+2);
1094  	  break;
1095  	case 4:
1096  	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+3);
1097  	  break;
1098  	case 5:
1099  	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+4);
1100  	  break;
1101  	case 6:
1102  	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+5);
1103  	  break;
1104  	case 7:
1105  	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+6);
1106  	  break;
1107  	case 8:
1108  	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+7);
1109  	  break;
1110  	case 9:
1111  	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+8);
1112  	  break;
1113  	default:
1114  	  result = powl((trio_long_double_t)number,
1115  			(trio_long_double_t)exponent);
1116  	  break;
1117  	}
1118      }
1119    else
1120      {
1121        return powl((trio_long_double_t)number, (trio_long_double_t)exponent);
1122      }
1123    return result;
1124  }
1125  
1126  /*************************************************************************
1127   * TrioLogarithm
1128   */
1129  TRIO_PRIVATE double
1130  TrioLogarithm
1131  TRIO_ARGS2((number, base),
1132  	   double number,
1133  	   int base)
1134  {
1135    double result;
1136  
1137    if (number <= 0.0)
1138      {
1139        /* xlC crashes on log(0) */
1140        result = (number == 0.0) ? trio_ninf() : trio_nan();
1141      }
1142    else
1143      {
1144        if (base == 10)
1145  	{
1146  	  result = log10(number);
1147  	}
1148        else
1149  	{
1150  	  result = log10(number) / log10((double)base);
1151  	}
1152      }
1153    return result;
1154  }
1155  
1156  /*************************************************************************
1157   * TrioLogarithmBase
1158   */
1159  TRIO_PRIVATE double
1160  TrioLogarithmBase
1161  TRIO_ARGS1((base),
1162  	   int base)
1163  {
1164    switch (base)
1165      {
1166      case BASE_BINARY : return 1.0;
1167      case BASE_OCTAL  : return 3.0;
1168      case BASE_DECIMAL: return 3.321928094887362345;
1169      case BASE_HEX    : return 4.0;
1170      default          : return TrioLogarithm((double)base, 2);
1171      }
1172  }
1173  
1174  /*************************************************************************
1175   * TrioParse
1176   *
1177   * Description:
1178   *  Parse the format string
1179   */
1180  TRIO_PRIVATE int
1181  TrioParse
1182  TRIO_ARGS5((type, format, parameters, arglist, argarray),
1183  	   int type,
1184  	   TRIO_CONST char *format,
1185  	   trio_parameter_t *parameters,
1186  	   TRIO_VA_LIST_PTR arglist,
1187  	   trio_pointer_t *argarray)
1188  {
1189    /* Count the number of times a parameter is referenced */
1190    unsigned short usedEntries[MAX_PARAMETERS];
1191    /* Parameter counters */
1192    int parameterPosition;
1193    int currentParam;
1194    int maxParam = -1;
1195    /* Utility variables */
1196    trio_flags_t flags;
1197    int width;
1198    int precision;
1199    int varsize;
1200    int base;
1201    int index;  /* Index into formatting string */
1202    int dots;  /* Count number of dots in modifier part */
1203    BOOLEAN_T positional;  /* Does the specifier have a positional? */
1204    BOOLEAN_T gotSticky = FALSE;  /* Are there any sticky modifiers at all? */
1205    /*
1206     * indices specifies the order in which the parameters must be
1207     * read from the va_args (this is necessary to handle positionals)
1208     */
1209    int indices[MAX_PARAMETERS];
1210    int pos = 0;
1211    /* Various variables */
1212    char ch;
1213  #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
1214    int charlen;
1215  #endif
1216    int save_errno;
1217    int i = -1;
1218    int num;
1219    char *tmpformat;
1220  
1221    /* One and only one of arglist and argarray must be used */
1222    assert((arglist != NULL) ^ (argarray != NULL));
1223  
1224    /*
1225     * The 'parameters' array is not initialized, but we need to
1226     * know which entries we have used.
1227     */
1228    memset(usedEntries, 0, sizeof(usedEntries));
1229  
1230    save_errno = errno;
1231    index = 0;
1232    parameterPosition = 0;
1233  #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
1234    (void)mblen(NULL, 0);
1235  #endif
1236  
1237    while (format[index])
1238      {
1239  #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
1240        if (! isascii(format[index]))
1241  	{
1242  	  /*
1243  	   * Multibyte characters cannot be legal specifiers or
1244  	   * modifiers, so we skip over them.
1245  	   */
1246  	  charlen = mblen(&format[index], MB_LEN_MAX);
1247  	  index += (charlen > 0) ? charlen : 1;
1248  	  continue; /* while */
1249  	}
1250  #endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
1251        if (CHAR_IDENTIFIER == format[index++])
1252  	{
1253  	  if (CHAR_IDENTIFIER == format[index])
1254  	    {
1255  	      index++;
1256  	      continue; /* while */
1257  	    }
1258  
1259  	  flags = FLAGS_NEW;
1260  	  dots = 0;
1261  	  currentParam = TrioGetPosition(format, &index);
1262  	  positional = (NO_POSITION != currentParam);
1263  	  if (!positional)
1264  	    {
1265  	      /* We have no positional, get the next counter */
1266  	      currentParam = parameterPosition;
1267  	    }
1268            if(currentParam >= MAX_PARAMETERS)
1269  	    {
1270  	      /* Bail out completely to make the error more obvious */
1271  	      return TRIO_ERROR_RETURN(TRIO_ETOOMANY, index);
1272  	    }
1273  
1274  	  if (currentParam > maxParam)
1275  	    maxParam = currentParam;
1276  
1277  	  /* Default values */
1278  	  width = NO_WIDTH;
1279  	  precision = NO_PRECISION;
1280  	  base = NO_BASE;
1281  	  varsize = NO_SIZE;
1282  
1283  	  while (TrioIsQualifier(format[index]))
1284  	    {
1285  	      ch = format[index++];
1286  
1287  	      switch (ch)
1288  		{
1289  		case QUALIFIER_SPACE:
1290  		  flags |= FLAGS_SPACE;
1291  		  break;
1292  
1293  		case QUALIFIER_PLUS:
1294  		  flags |= FLAGS_SHOWSIGN;
1295  		  break;
1296  
1297  		case QUALIFIER_MINUS:
1298  		  flags |= FLAGS_LEFTADJUST;
1299  		  flags &= ~FLAGS_NILPADDING;
1300  		  break;
1301  
1302  		case QUALIFIER_ALTERNATIVE:
1303  		  flags |= FLAGS_ALTERNATIVE;
1304  		  break;
1305  
1306  		case QUALIFIER_DOT:
1307  		  if (dots == 0) /* Precision */
1308  		    {
1309  		      dots++;
1310  
1311  		      /* Skip if no precision */
1312  		      if (QUALIFIER_DOT == format[index])
1313  			break;
1314  
1315  		      /* After the first dot we have the precision */
1316  		      flags |= FLAGS_PRECISION;
1317  		      if ((QUALIFIER_STAR == format[index])
1318  #if defined(QUALIFIER_PARAM)
1319  			  || (QUALIFIER_PARAM == format[index])
1320  #endif
1321  			  )
1322  			{
1323  			  index++;
1324  			  flags |= FLAGS_PRECISION_PARAMETER;
1325  
1326  			  precision = TrioGetPosition(format, &index);
1327  			  if (precision == NO_POSITION)
1328  			    {
1329  			      parameterPosition++;
1330  			      if (positional)
1331  				precision = parameterPosition;
1332  			      else
1333  				{
1334  				  precision = currentParam;
1335  				  currentParam = precision + 1;
1336  				}
1337  			    }
1338  			  else
1339  			    {
1340  			      if (! positional)
1341  				currentParam = precision + 1;
1342  			      if (width > maxParam)
1343  				maxParam = precision;
1344  			    }
1345  			  if (currentParam > maxParam)
1346  			    maxParam = currentParam;
1347  			}
1348  		      else
1349  			{
1350  			  precision = trio_to_long(&format[index],
1351  						   &tmpformat,
1352  						   BASE_DECIMAL);
1353  			  index = (int)(tmpformat - format);
1354  			}
1355  		    }
1356  		  else if (dots == 1) /* Base */
1357  		    {
1358  		      dots++;
1359  
1360  		      /* After the second dot we have the base */
1361  		      flags |= FLAGS_BASE;
1362  		      if ((QUALIFIER_STAR == format[index])
1363  #if defined(QUALIFIER_PARAM)
1364  			  || (QUALIFIER_PARAM == format[index])
1365  #endif
1366  			  )
1367  			{
1368  			  index++;
1369  			  flags |= FLAGS_BASE_PARAMETER;
1370  			  base = TrioGetPosition(format, &index);
1371  			  if (base == NO_POSITION)
1372  			    {
1373  			      parameterPosition++;
1374  			      if (positional)
1375  				base = parameterPosition;
1376  			      else
1377  				{
1378  				  base = currentParam;
1379  				  currentParam = base + 1;
1380  				}
1381  			    }
1382  			  else
1383  			    {
1384  			      if (! positional)
1385  				currentParam = base + 1;
1386  			      if (base > maxParam)
1387  				maxParam = base;
1388  			    }
1389  			  if (currentParam > maxParam)
1390  			    maxParam = currentParam;
1391  			}
1392  		      else
1393  			{
1394  			  base = trio_to_long(&format[index],
1395  					      &tmpformat,
1396  					      BASE_DECIMAL);
1397  			  if (base > MAX_BASE)
1398  			    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1399  			  index = (int)(tmpformat - format);
1400  			}
1401  		    }
1402  		  else
1403  		    {
1404  		      return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1405  		    }
1406  		  break; /* QUALIFIER_DOT */
1407  
1408  #if defined(QUALIFIER_PARAM)
1409  		case QUALIFIER_PARAM:
1410  		  type = TYPE_PRINT;
1411  		  /* FALLTHROUGH */
1412  #endif
1413  		case QUALIFIER_STAR:
1414  		  /* This has different meanings for print and scan */
1415  		  if (TYPE_PRINT == type)
1416  		    {
1417  		      /* Read with from parameter */
1418  		      flags |= (FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER);
1419  		      width = TrioGetPosition(format, &index);
1420  		      if (width == NO_POSITION)
1421  			{
1422  			  parameterPosition++;
1423  			  if (positional)
1424  			    width = parameterPosition;
1425  			  else
1426  			    {
1427  			      width = currentParam;
1428  			      currentParam = width + 1;
1429  			    }
1430  			}
1431  		      else
1432  			{
1433  			  if (! positional)
1434  			    currentParam = width + 1;
1435  			  if (width > maxParam)
1436  			    maxParam = width;
1437  			}
1438  		      if (currentParam > maxParam)
1439  			maxParam = currentParam;
1440  		    }
1441  		  else
1442  		    {
1443  		      /* Scan, but do not store result */
1444  		      flags |= FLAGS_IGNORE;
1445  		    }
1446  
1447  		  break; /* QUALIFIER_STAR */
1448  
1449  		case '0':
1450  		  if (! (flags & FLAGS_LEFTADJUST))
1451  		    flags |= FLAGS_NILPADDING;
1452  		  /* FALLTHROUGH */
1453  		case '1': case '2': case '3': case '4':
1454  		case '5': case '6': case '7': case '8': case '9':
1455  		  flags |= FLAGS_WIDTH;
1456  		  /* &format[index - 1] is used to "rewind" the read
1457  		   * character from format
1458  		   */
1459  		  width = trio_to_long(&format[index - 1],
1460  				       &tmpformat,
1461  				       BASE_DECIMAL);
1462  		  index = (int)(tmpformat - format);
1463  		  break;
1464  
1465  		case QUALIFIER_SHORT:
1466  		  if (flags & FLAGS_SHORTSHORT)
1467  		    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1468  		  else if (flags & FLAGS_SHORT)
1469  		    flags |= FLAGS_SHORTSHORT;
1470  		  else
1471  		    flags |= FLAGS_SHORT;
1472  		  break;
1473  
1474  		case QUALIFIER_LONG:
1475  		  if (flags & FLAGS_QUAD)
1476  		    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1477  		  else if (flags & FLAGS_LONG)
1478  		    flags |= FLAGS_QUAD;
1479  		  else
1480  		    flags |= FLAGS_LONG;
1481  		  break;
1482  
1483  		case QUALIFIER_LONG_UPPER:
1484  		  flags |= FLAGS_LONGDOUBLE;
1485  		  break;
1486  
1487  #if defined(QUALIFIER_SIZE_T)
1488  		case QUALIFIER_SIZE_T:
1489  		  flags |= FLAGS_SIZE_T;
1490  		  /* Modify flags for later truncation of number */
1491  		  if (sizeof(size_t) == sizeof(trio_ulonglong_t))
1492  		    flags |= FLAGS_QUAD;
1493  		  else if (sizeof(size_t) == sizeof(long))
1494  		    flags |= FLAGS_LONG;
1495  		  break;
1496  #endif
1497  
1498  #if defined(QUALIFIER_PTRDIFF_T)
1499  		case QUALIFIER_PTRDIFF_T:
1500  		  flags |= FLAGS_PTRDIFF_T;
1501  		  if (sizeof(ptrdiff_t) == sizeof(trio_ulonglong_t))
1502  		    flags |= FLAGS_QUAD;
1503  		  else if (sizeof(ptrdiff_t) == sizeof(long))
1504  		    flags |= FLAGS_LONG;
1505  		  break;
1506  #endif
1507  
1508  #if defined(QUALIFIER_INTMAX_T)
1509  		case QUALIFIER_INTMAX_T:
1510  		  flags |= FLAGS_INTMAX_T;
1511  		  if (sizeof(trio_intmax_t) == sizeof(trio_ulonglong_t))
1512  		    flags |= FLAGS_QUAD;
1513  		  else if (sizeof(trio_intmax_t) == sizeof(long))
1514  		    flags |= FLAGS_LONG;
1515  		  break;
1516  #endif
1517  
1518  #if defined(QUALIFIER_QUAD)
1519  		case QUALIFIER_QUAD:
1520  		  flags |= FLAGS_QUAD;
1521  		  break;
1522  #endif
1523  
1524  #if defined(QUALIFIER_FIXED_SIZE)
1525  		case QUALIFIER_FIXED_SIZE:
1526  		  if (flags & FLAGS_FIXED_SIZE)
1527  		    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1528  
1529  		  if (flags & (FLAGS_ALL_SIZES | FLAGS_LONGDOUBLE |
1530  			       FLAGS_WIDECHAR | FLAGS_VARSIZE_PARAMETER))
1531  		    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1532  
1533  		  if ((format[index] == '6') &&
1534  		      (format[index + 1] == '4'))
1535  		    {
1536  		      varsize = sizeof(trio_int64_t);
1537  		      index += 2;
1538  		    }
1539  		  else if ((format[index] == '3') &&
1540  			   (format[index + 1] == '2'))
1541  		    {
1542  		      varsize = sizeof(trio_int32_t);
1543  		      index += 2;
1544  		    }
1545  		  else if ((format[index] == '1') &&
1546  			   (format[index + 1] == '6'))
1547  		    {
1548  		      varsize = sizeof(trio_int16_t);
1549  		      index += 2;
1550  		    }
1551  		  else if (format[index] == '8')
1552  		    {
1553  		      varsize = sizeof(trio_int8_t);
1554  		      index++;
1555  		    }
1556  		  else
1557  		    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1558  
1559  		  flags |= FLAGS_FIXED_SIZE;
1560  		  break;
1561  #endif
1562  
1563  #if defined(QUALIFIER_WIDECHAR)
1564  		case QUALIFIER_WIDECHAR:
1565  		  flags |= FLAGS_WIDECHAR;
1566  		  break;
1567  #endif
1568  
1569  #if defined(QUALIFIER_SIZE_T_UPPER)
1570  		case QUALIFIER_SIZE_T_UPPER:
1571  		  break;
1572  #endif
1573  
1574  #if defined(QUALIFIER_QUOTE)
1575  		case QUALIFIER_QUOTE:
1576  		  flags |= FLAGS_QUOTE;
1577  		  break;
1578  #endif
1579  
1580  #if defined(QUALIFIER_STICKY)
1581  		case QUALIFIER_STICKY:
1582  		  flags |= FLAGS_STICKY;
1583  		  gotSticky = TRUE;
1584  		  break;
1585  #endif
1586  
1587  #if defined(QUALIFIER_VARSIZE)
1588  		case QUALIFIER_VARSIZE:
1589  		  flags |= FLAGS_VARSIZE_PARAMETER;
1590  		  parameterPosition++;
1591  		  if (positional)
1592  		    varsize = parameterPosition;
1593  		  else
1594  		    {
1595  		      varsize = currentParam;
1596  		      currentParam = varsize + 1;
1597  		    }
1598  		  if (currentParam > maxParam)
1599  		    maxParam = currentParam;
1600  		  break;
1601  #endif
1602  
1603  #if defined(QUALIFIER_ROUNDING_UPPER)
1604  		case QUALIFIER_ROUNDING_UPPER:
1605  		  flags |= FLAGS_ROUNDING;
1606  		  break;
1607  #endif
1608  
1609  		default:
1610  		  /* Bail out completely to make the error more obvious */
1611                    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1612  		}
1613  	    } /* while qualifier */
1614  
1615  	  /*
1616  	   * Parameters only need the type and value. The value is
1617  	   * read later.
1618  	   */
1619  	  if (flags & FLAGS_WIDTH_PARAMETER)
1620  	    {
1621  	      usedEntries[width] += 1;
1622  	      parameters[pos].type = FORMAT_PARAMETER;
1623  	      parameters[pos].flags = 0;
1624  	      indices[width] = pos;
1625  	      width = pos++;
1626  	    }
1627  	  if (flags & FLAGS_PRECISION_PARAMETER)
1628  	    {
1629  	      usedEntries[precision] += 1;
1630  	      parameters[pos].type = FORMAT_PARAMETER;
1631  	      parameters[pos].flags = 0;
1632  	      indices[precision] = pos;
1633  	      precision = pos++;
1634  	    }
1635  	  if (flags & FLAGS_BASE_PARAMETER)
1636  	    {
1637  	      usedEntries[base] += 1;
1638  	      parameters[pos].type = FORMAT_PARAMETER;
1639  	      parameters[pos].flags = 0;
1640  	      indices[base] = pos;
1641  	      base = pos++;
1642  	    }
1643  	  if (flags & FLAGS_VARSIZE_PARAMETER)
1644  	    {
1645  	      usedEntries[varsize] += 1;
1646  	      parameters[pos].type = FORMAT_PARAMETER;
1647  	      parameters[pos].flags = 0;
1648  	      indices[varsize] = pos;
1649  	      varsize = pos++;
1650  	    }
1651  
1652  	  indices[currentParam] = pos;
1653  
1654  	  switch (format[index++])
1655  	    {
1656  #if defined(SPECIFIER_CHAR_UPPER)
1657  	    case SPECIFIER_CHAR_UPPER:
1658  	      flags |= FLAGS_WIDECHAR;
1659  	      /* FALLTHROUGH */
1660  #endif
1661  	    case SPECIFIER_CHAR:
1662  	      if (flags & FLAGS_LONG)
1663  		flags |= FLAGS_WIDECHAR;
1664  	      else if (flags & FLAGS_SHORT)
1665  		flags &= ~FLAGS_WIDECHAR;
1666  	      parameters[pos].type = FORMAT_CHAR;
1667  	      break;
1668  
1669  #if defined(SPECIFIER_STRING_UPPER)
1670  	    case SPECIFIER_STRING_UPPER:
1671  	      flags |= FLAGS_WIDECHAR;
1672  	      /* FALLTHROUGH */
1673  #endif
1674  	    case SPECIFIER_STRING:
1675  	      if (flags & FLAGS_LONG)
1676  		flags |= FLAGS_WIDECHAR;
1677  	      else if (flags & FLAGS_SHORT)
1678  		flags &= ~FLAGS_WIDECHAR;
1679  	      parameters[pos].type = FORMAT_STRING;
1680  	      break;
1681  
1682  	    case SPECIFIER_GROUP:
1683  	      if (TYPE_SCAN == type)
1684  		{
1685  		  int depth = 1;
1686  		  parameters[pos].type = FORMAT_GROUP;
1687  		  if (format[index] == QUALIFIER_CIRCUMFLEX)
1688  		    index++;
1689  		  if (format[index] == SPECIFIER_UNGROUP)
1690  		    index++;
1691  		  if (format[index] == QUALIFIER_MINUS)
1692  		    index++;
1693  		  /* Skip nested brackets */
1694  		  while (format[index] != NIL)
1695  		    {
1696  		      if (format[index] == SPECIFIER_GROUP)
1697  			{
1698  			  depth++;
1699  			}
1700  		      else if (format[index] == SPECIFIER_UNGROUP)
1701  			{
1702  			  if (--depth <= 0)
1703  			    {
1704  			      index++;
1705  			      break;
1706  			    }
1707  			}
1708  		      index++;
1709  		    }
1710  		}
1711  	      break;
1712  
1713  	    case SPECIFIER_INTEGER:
1714  	      parameters[pos].type = FORMAT_INT;
1715  	      break;
1716  
1717  	    case SPECIFIER_UNSIGNED:
1718  	      flags |= FLAGS_UNSIGNED;
1719  	      parameters[pos].type = FORMAT_INT;
1720  	      break;
1721  
1722  	    case SPECIFIER_DECIMAL:
1723  	      /* Disable base modifier */
1724  	      flags &= ~FLAGS_BASE_PARAMETER;
1725  	      base = BASE_DECIMAL;
1726  	      parameters[pos].type = FORMAT_INT;
1727  	      break;
1728  
1729  	    case SPECIFIER_OCTAL:
1730  	      flags |= FLAGS_UNSIGNED;
1731  	      flags &= ~FLAGS_BASE_PARAMETER;
1732  	      base = BASE_OCTAL;
1733  	      parameters[pos].type = FORMAT_INT;
1734  	      break;
1735  
1736  #if defined(SPECIFIER_BINARY)
1737  	    case SPECIFIER_BINARY_UPPER:
1738  	      flags |= FLAGS_UPPER;
1739  	      /* FALLTHROUGH */
1740  	    case SPECIFIER_BINARY:
1741  	      flags |= FLAGS_NILPADDING;
1742  	      flags &= ~FLAGS_BASE_PARAMETER;
1743  	      base = BASE_BINARY;
1744  	      parameters[pos].type = FORMAT_INT;
1745  	      break;
1746  #endif
1747  
1748  	    case SPECIFIER_HEX_UPPER:
1749  	      flags |= FLAGS_UPPER;
1750  	      /* FALLTHROUGH */
1751  	    case SPECIFIER_HEX:
1752  	      flags |= FLAGS_UNSIGNED;
1753  	      flags &= ~FLAGS_BASE_PARAMETER;
1754  	      base = BASE_HEX;
1755  	      parameters[pos].type = FORMAT_INT;
1756  	      break;
1757  
1758  	    case SPECIFIER_FLOAT_E_UPPER:
1759  	      flags |= FLAGS_UPPER;
1760  	      /* FALLTHROUGH */
1761  	    case SPECIFIER_FLOAT_E:
1762  	      flags |= FLAGS_FLOAT_E;
1763  	      parameters[pos].type = FORMAT_DOUBLE;
1764  	      break;
1765  
1766  	    case SPECIFIER_FLOAT_G_UPPER:
1767  	      flags |= FLAGS_UPPER;
1768  	      /* FALLTHROUGH */
1769  	    case SPECIFIER_FLOAT_G:
1770  	      flags |= FLAGS_FLOAT_G;
1771  	      parameters[pos].type = FORMAT_DOUBLE;
1772  	      break;
1773  
1774  	    case SPECIFIER_FLOAT_F_UPPER:
1775  	      flags |= FLAGS_UPPER;
1776  	      /* FALLTHROUGH */
1777  	    case SPECIFIER_FLOAT_F:
1778  	      parameters[pos].type = FORMAT_DOUBLE;
1779  	      break;
1780  
1781  	    case SPECIFIER_POINTER:
1782  	      if (sizeof(trio_pointer_t) == sizeof(trio_ulonglong_t))
1783  		flags |= FLAGS_QUAD;
1784  	      else if (sizeof(trio_pointer_t) == sizeof(long))
1785  		flags |= FLAGS_LONG;
1786  	      parameters[pos].type = FORMAT_POINTER;
1787  	      break;
1788  
1789  	    case SPECIFIER_COUNT:
1790  	      parameters[pos].type = FORMAT_COUNT;
1791  	      break;
1792  
1793  #if defined(SPECIFIER_HEXFLOAT)
1794  # if defined(SPECIFIER_HEXFLOAT_UPPER)
1795  	    case SPECIFIER_HEXFLOAT_UPPER:
1796  	      flags |= FLAGS_UPPER;
1797  	      /* FALLTHROUGH */
1798  # endif
1799  	    case SPECIFIER_HEXFLOAT:
1800  	      base = BASE_HEX;
1801  	      parameters[pos].type = FORMAT_DOUBLE;
1802  	      break;
1803  #endif
1804  
1805  #if defined(FORMAT_ERRNO)
1806  	    case SPECIFIER_ERRNO:
1807  	      parameters[pos].type = FORMAT_ERRNO;
1808  	      break;
1809  #endif
1810  
1811  #if defined(SPECIFIER_USER_DEFINED_BEGIN)
1812  	    case SPECIFIER_USER_DEFINED_BEGIN:
1813  	      {
1814  		unsigned int max;
1815  		int without_namespace = TRUE;
1816  
1817  		parameters[pos].type = FORMAT_USER_DEFINED;
1818  		parameters[pos].user_name[0] = NIL;
1819  		tmpformat = (char *)&format[index];
1820  
1821  		while ((ch = format[index]))
1822  		  {
1823  		    index++;
1824  		    if (ch == SPECIFIER_USER_DEFINED_END)
1825  		      {
1826  			if (without_namespace)
1827  			  {
1828  			    /* We must get the handle first */
1829  			    parameters[pos].type = FORMAT_PARAMETER;
1830  			    parameters[pos].indexAfterSpecifier = index;
1831  			    parameters[pos].flags = FLAGS_USER_DEFINED;
1832  			    /* Adjust parameters for insertion of new one */
1833  			    pos++;
1834  			    usedEntries[currentParam] += 1;
1835  			    parameters[pos].type = FORMAT_USER_DEFINED;
1836  			    currentParam++;
1837  			    indices[currentParam] = pos;
1838  			    if (currentParam > maxParam)
1839  			      maxParam = currentParam;
1840  			  }
1841  			/* Copy the user data */
1842  			max = (unsigned int)(&format[index] - tmpformat);
1843  			if (max > MAX_USER_DATA)
1844  			  max = MAX_USER_DATA;
1845  			trio_copy_max(parameters[pos].user_data,
1846  				      max,
1847  				      tmpformat);
1848  			break; /* while */
1849  		      }
1850  		    if (ch == SPECIFIER_USER_DEFINED_SEPARATOR)
1851  		      {
1852  			without_namespace = FALSE;
1853  			/* Copy the namespace for later looking-up */
1854  			max = (int)(&format[index] - tmpformat);
1855  			if (max > MAX_USER_NAME)
1856  			  max = MAX_USER_NAME;
1857  			trio_copy_max(parameters[pos].user_name,
1858  				      max,
1859  				      tmpformat);
1860  			tmpformat = (char *)&format[index];
1861  		      }
1862  		  }
1863  		if (ch != SPECIFIER_USER_DEFINED_END)
1864  		  return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1865  	      }
1866  	      break;
1867  #endif /* defined(SPECIFIER_USER_DEFINED_BEGIN) */
1868  
1869  	    default:
1870  	      /* Bail out completely to make the error more obvious */
1871                return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1872  	    }
1873  
1874  	  /*  Count the number of times this entry has been used */
1875  	  usedEntries[currentParam] += 1;
1876  
1877  	  /* Find last sticky parameters */
1878  	  if (gotSticky && !(flags & FLAGS_STICKY))
1879  	    {
1880  	      for (i = pos - 1; i >= 0; i--)
1881  		{
1882  		  if (parameters[i].type == FORMAT_PARAMETER)
1883  		    continue;
1884  		  if ((parameters[i].flags & FLAGS_STICKY) &&
1885  		      (parameters[i].type == parameters[pos].type))
1886  		    {
1887  		      /* Do not overwrite current qualifiers */
1888  		      flags |= (parameters[i].flags & (unsigned long)~FLAGS_STICKY);
1889  		      if (width == NO_WIDTH)
1890  			width = parameters[i].width;
1891  		      if (precision == NO_PRECISION)
1892  			precision = parameters[i].precision;
1893  		      if (base == NO_BASE)
1894  			base = parameters[i].base;
1895  		      break;
1896  		    }
1897  		}
1898  	    }
1899  
1900  	  parameters[pos].indexAfterSpecifier = index;
1901  	  parameters[pos].flags = flags;
1902  	  parameters[pos].width = width;
1903  	  parameters[pos].precision = precision;
1904  	  parameters[pos].base = (base == NO_BASE) ? BASE_DECIMAL : base;
1905  	  parameters[pos].varsize = varsize;
1906  	  pos++;
1907  
1908  	  if (! positional)
1909  	    parameterPosition++;
1910  
1911  	} /* if identifier */
1912  
1913      } /* while format characters left */
1914  
1915    for (num = 0; num <= maxParam; num++)
1916      {
1917        if (usedEntries[num] != 1)
1918  	{
1919  	  if (usedEntries[num] == 0) /* gap detected */
1920  	    return TRIO_ERROR_RETURN(TRIO_EGAP, num);
1921  	  else /* double references detected */
1922  	    return TRIO_ERROR_RETURN(TRIO_EDBLREF, num);
1923  	}
1924  
1925        i = indices[num];
1926  
1927        /*
1928         * FORMAT_PARAMETERS are only present if they must be read,
1929         * so it makes no sense to check the ignore flag (besides,
1930         * the flags variable is not set for that particular type)
1931         */
1932        if ((parameters[i].type != FORMAT_PARAMETER) &&
1933  	  (parameters[i].flags & FLAGS_IGNORE))
1934  	continue; /* for all arguments */
1935  
1936        /*
1937         * The stack arguments are read according to ANSI C89
1938         * default argument promotions:
1939         *
1940         *  char           = int
1941         *  short          = int
1942         *  unsigned char  = unsigned int
1943         *  unsigned short = unsigned int
1944         *  float          = double
1945         *
1946         * In addition to the ANSI C89 these types are read (the
1947         * default argument promotions of C99 has not been
1948         * considered yet)
1949         *
1950         *  long long
1951         *  long double
1952         *  size_t
1953         *  ptrdiff_t
1954         *  intmax_t
1955         */
1956        switch (parameters[i].type)
1957  	{
1958  	case FORMAT_GROUP:
1959  	case FORMAT_STRING:
1960  #if TRIO_WIDECHAR
1961  	  if (flags & FLAGS_WIDECHAR)
1962  	    {
1963  	      parameters[i].data.wstring = (argarray == NULL)
1964  		? va_arg(TRIO_VA_LIST_DEREF(arglist), trio_wchar_t *)
1965  		: (trio_wchar_t *)(argarray[num]);
1966  	    }
1967  	  else
1968  #endif
1969  	    {
1970  	      parameters[i].data.string = (argarray == NULL)
1971  		? va_arg(TRIO_VA_LIST_DEREF(arglist), char *)
1972  		: (char *)(argarray[num]);
1973  	    }
1974  	  break;
1975  
1976  #if defined(FORMAT_USER_DEFINED)
1977  	case FORMAT_USER_DEFINED:
1978  #endif
1979  	case FORMAT_POINTER:
1980  	case FORMAT_COUNT:
1981  	case FORMAT_UNKNOWN:
1982  	  parameters[i].data.pointer = (argarray == NULL)
1983  	    ? va_arg(TRIO_VA_LIST_DEREF(arglist), trio_pointer_t )
1984  	    : argarray[num];
1985  	  break;
1986  
1987  	case FORMAT_CHAR:
1988  	case FORMAT_INT:
1989  	  if (TYPE_SCAN == type)
1990  	    {
1991                if (argarray == NULL)
1992                  parameters[i].data.pointer =
1993                    (trio_pointer_t)va_arg(TRIO_VA_LIST_DEREF(arglist), trio_pointer_t);
1994                else
1995                  {
1996                    if (parameters[i].type == FORMAT_CHAR)
1997                      parameters[i].data.pointer =
1998                        (trio_pointer_t)((char *)argarray[num]);
1999                    else if (parameters[i].flags & FLAGS_SHORT)
2000                      parameters[i].data.pointer =
2001                        (trio_pointer_t)((short *)argarray[num]);
2002                    else
2003                      parameters[i].data.pointer =
2004                        (trio_pointer_t)((int *)argarray[num]);
2005                  }
2006  	    }
2007  	  else
2008  	    {
2009  #if defined(QUALIFIER_VARSIZE) || defined(QUALIFIER_FIXED_SIZE)
2010  	      if (parameters[i].flags
2011  		  & (FLAGS_VARSIZE_PARAMETER | FLAGS_FIXED_SIZE))
2012  		{
2013  		  if (parameters[i].flags & FLAGS_VARSIZE_PARAMETER)
2014  		    {
2015  		      /*
2016  		       * Variable sizes are mapped onto the fixed sizes, in
2017  		       * accordance with integer promotion.
2018  		       *
2019  		       * Please note that this may not be portable, as we
2020  		       * only guess the size, not the layout of the numbers.
2021  		       * For example, if int is little-endian, and long is
2022  		       * big-endian, then this will fail.
2023  		       */
2024  		      varsize = (int)parameters[parameters[i].varsize].data.number.as_unsigned;
2025  		    }
2026  		  else
2027  		    {
2028  		      /* Used for the I<bits> modifiers */
2029  		      varsize = parameters[i].varsize;
2030  		    }
2031  		  parameters[i].flags &= ~FLAGS_ALL_VARSIZES;
2032  
2033  		  if (varsize <= (int)sizeof(int))
2034  		    ;
2035  		  else if (varsize <= (int)sizeof(long))
2036  		    parameters[i].flags |= FLAGS_LONG;
2037  #if defined(QUALIFIER_INTMAX_T)
2038  		  else if (varsize <= (int)sizeof(trio_longlong_t))
2039  		    parameters[i].flags |= FLAGS_QUAD;
2040  		  else
2041  		    parameters[i].flags |= FLAGS_INTMAX_T;
2042  #else
2043  		  else
2044  		    parameters[i].flags |= FLAGS_QUAD;
2045  #endif
2046  		}
2047  #endif /* defined(QUALIFIER_VARSIZE) */
2048  #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
2049  	      if (parameters[i].flags & FLAGS_SIZE_T)
2050  		parameters[i].data.number.as_unsigned = (argarray == NULL)
2051  		  ? (trio_uintmax_t)va_arg(TRIO_VA_LIST_DEREF(arglist), size_t)
2052  		  : (trio_uintmax_t)(*((size_t *)argarray[num]));
2053  	      else
2054  #endif
2055  #if defined(QUALIFIER_PTRDIFF_T)
2056  	      if (parameters[i].flags & FLAGS_PTRDIFF_T)
2057  		parameters[i].data.number.as_unsigned = (argarray == NULL)
2058  		  ? (trio_uintmax_t)va_arg(TRIO_VA_LIST_DEREF(arglist), ptrdiff_t)
2059  		  : (trio_uintmax_t)(*((ptrdiff_t *)argarray[num]));
2060  	      else
2061  #endif
2062  #if defined(QUALIFIER_INTMAX_T)
2063  	      if (parameters[i].flags & FLAGS_INTMAX_T)
2064  		parameters[i].data.number.as_unsigned = (argarray == NULL)
2065  		  ? (trio_uintmax_t)va_arg(TRIO_VA_LIST_DEREF(arglist), trio_intmax_t)
2066  		  : (trio_uintmax_t)(*((trio_intmax_t *)argarray[num]));
2067  	      else
2068  #endif
2069  	      if (parameters[i].flags & FLAGS_QUAD)
2070  		parameters[i].data.number.as_unsigned = (argarray == NULL)
2071  		  ? (trio_uintmax_t)va_arg(TRIO_VA_LIST_DEREF(arglist), trio_ulonglong_t)
2072  		  : (trio_uintmax_t)(*((trio_ulonglong_t *)argarray[num]));
2073  	      else if (parameters[i].flags & FLAGS_LONG)
2074  		parameters[i].data.number.as_unsigned = (argarray == NULL)
2075  		  ? (trio_uintmax_t)va_arg(TRIO_VA_LIST_DEREF(arglist), long)
2076  		  : (trio_uintmax_t)(*((long *)argarray[num]));
2077  	      else
2078  		{
2079  		  if (argarray == NULL)
2080  		    parameters[i].data.number.as_unsigned = (trio_uintmax_t)va_arg(TRIO_VA_LIST_DEREF(arglist), int);
2081  		  else
2082  		    {
2083  		      if (parameters[i].type == FORMAT_CHAR)
2084  			parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((char *)argarray[num]));
2085  		      else if (parameters[i].flags & FLAGS_SHORT)
2086  			parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((short *)argarray[num]));
2087  		      else
2088  			parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((int *)argarray[num]));
2089  		    }
2090  		}
2091  	    }
2092  	  break;
2093  
2094  	case FORMAT_PARAMETER:
2095  	  /*
2096  	   * The parameter for the user-defined specifier is a pointer,
2097  	   * whereas the rest (width, precision, base) uses an integer.
2098  	   */
2099  	  if (parameters[i].flags & FLAGS_USER_DEFINED)
2100  	    parameters[i].data.pointer = (argarray == NULL)
2101  	      ? va_arg(TRIO_VA_LIST_DEREF(arglist), trio_pointer_t )
2102  	      : argarray[num];
2103  	  else
2104  	    parameters[i].data.number.as_unsigned = (argarray == NULL)
2105  	      ? (trio_uintmax_t)va_arg(TRIO_VA_LIST_DEREF(arglist), int)
2106  	      : (trio_uintmax_t)(*((int *)argarray[num]));
2107  	  break;
2108  
2109  	case FORMAT_DOUBLE:
2110  	  if (TYPE_SCAN == type)
2111  	    {
2112  	      if (parameters[i].flags & FLAGS_LONGDOUBLE)
2113  		parameters[i].data.longdoublePointer = (argarray == NULL)
2114  		  ? va_arg(TRIO_VA_LIST_DEREF(arglist), trio_long_double_t *)
2115  		  : (trio_long_double_t *)argarray[num];
2116  	      else
2117                  {
2118  		  if (parameters[i].flags & FLAGS_LONG)
2119  		    parameters[i].data.doublePointer = (argarray == NULL)
2120  		      ? va_arg(TRIO_VA_LIST_DEREF(arglist), double *)
2121  		      : (double *)argarray[num];
2122  		  else
2123  		    parameters[i].data.doublePointer = (argarray == NULL)
2124  		      ? (double *)va_arg(TRIO_VA_LIST_DEREF(arglist), float *)
2125  		      : (double *)((float *)argarray[num]);
2126                  }
2127  	    }
2128  	  else
2129  	    {
2130  	      if (parameters[i].flags & FLAGS_LONGDOUBLE)
2131  		parameters[i].data.longdoubleNumber = (argarray == NULL)
2132  		  ? va_arg(TRIO_VA_LIST_DEREF(arglist), trio_long_double_t)
2133  		  : (trio_long_double_t)(*((trio_long_double_t *)argarray[num]));
2134  	      else
2135  		{
2136  		  if (argarray == NULL)
2137  		    parameters[i].data.longdoubleNumber =
2138  		      (trio_long_double_t)va_arg(TRIO_VA_LIST_DEREF(arglist), double);
2139  		  else
2140  		    {
2141  		      if (parameters[i].flags & FLAGS_SHORT)
2142  			parameters[i].data.longdoubleNumber =
2143  			  (trio_long_double_t)(*((float *)argarray[num]));
2144  		      else
2145  			parameters[i].data.longdoubleNumber =
2146  			  (trio_long_double_t)(*((double *)argarray[num]));
2147  		    }
2148  		}
2149  	    }
2150  	  break;
2151  
2152  #if defined(FORMAT_ERRNO)
2153  	case FORMAT_ERRNO:
2154  	  parameters[i].data.errorNumber = save_errno;
2155  	  break;
2156  #endif
2157  
2158  	default:
2159  	  break;
2160  	}
2161      } /* for all specifiers */
2162    return num;
2163  }
2164  
2165  
2166  /*************************************************************************
2167   *
2168   * FORMATTING
2169   *
2170   ************************************************************************/
2171  
2172  
2173  /*************************************************************************
2174   * TrioWriteNumber
2175   *
2176   * Description:
2177   *  Output a number.
2178   *  The complexity of this function is a result of the complexity
2179   *  of the dependencies of the flags.
2180   */
2181  TRIO_PRIVATE void
2182  TrioWriteNumber
2183  TRIO_ARGS6((self, number, flags, width, precision, base),
2184  	   trio_class_t *self,
2185  	   trio_uintmax_t number,
2186  	   trio_flags_t flags,
2187  	   int width,
2188  	   int precision,
2189  	   int base)
2190  {
2191    BOOLEAN_T isNegative;
2192    BOOLEAN_T isNumberZero;
2193    BOOLEAN_T isPrecisionZero;
2194    BOOLEAN_T ignoreNumber;
2195    char buffer[MAX_CHARS_IN(trio_uintmax_t) * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1];
2196    char *bufferend;
2197    char *pointer;
2198    TRIO_CONST char *digits;
2199    int i;
2200    int length;
2201    char *p;
2202    int count;
2203  
2204    assert(VALID(self));
2205    assert(VALID(self->OutStream));
2206    assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE));
2207  
2208    digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
2209    if (base == NO_BASE)
2210      base = BASE_DECIMAL;
2211  
2212    isNumberZero = (number == 0);
2213    isPrecisionZero = (precision == 0);
2214    ignoreNumber = (isNumberZero
2215  		  && isPrecisionZero
2216  		  && !((flags & FLAGS_ALTERNATIVE) && (base == BASE_OCTAL)));
2217  
2218    if (flags & FLAGS_UNSIGNED)
2219      {
2220        isNegative = FALSE;
2221        flags &= ~FLAGS_SHOWSIGN;
2222      }
2223    else
2224      {
2225        isNegative = ((trio_intmax_t)number < 0);
2226        if (isNegative)
2227  	number = -((trio_intmax_t)number);
2228      }
2229  
2230    if (flags & FLAGS_QUAD)
2231      number &= (trio_ulonglong_t)-1;
2232    else if (flags & FLAGS_LONG)
2233      number &= (unsigned long)-1;
2234    else
2235      number &= (unsigned int)-1;
2236  
2237    /* Build number */
2238    pointer = bufferend = &buffer[sizeof(buffer) - 1];
2239    *pointer-- = NIL;
2240    for (i = 1; i < (int)sizeof(buffer); i++)
2241      {
2242        *pointer-- = digits[number % base];
2243        number /= base;
2244        if (number == 0)
2245  	break;
2246  
2247        if ((flags & FLAGS_QUOTE) && TrioFollowedBySeparator(i + 1))
2248  	{
2249  	  /*
2250  	   * We are building the number from the least significant
2251  	   * to the most significant digit, so we have to copy the
2252  	   * thousand separator backwards
2253  	   */
2254  	  length = internalThousandSeparatorLength;
2255  	  if (((int)(pointer - buffer) - length) > 0)
2256  	    {
2257  	      p = &internalThousandSeparator[length - 1];
2258  	      while (length-- > 0)
2259  		*pointer-- = *p--;
2260  	    }
2261  	}
2262      }
2263  
2264    if (! ignoreNumber)
2265      {
2266        /* Adjust width */
2267        width -= (bufferend - pointer) - 1;
2268      }
2269  
2270    /* Adjust precision */
2271    if (NO_PRECISION != precision)
2272      {
2273        precision -= (bufferend - pointer) - 1;
2274        if (precision < 0)
2275  	precision = 0;
2276        flags |= FLAGS_NILPADDING;
2277      }
2278  
2279    /* Calculate padding */
2280    count = (! ((flags & FLAGS_LEFTADJUST) || (precision == NO_PRECISION)))
2281      ? precision
2282      : 0;
2283  
2284    /* Adjust width further */
2285    if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
2286      width--;
2287    if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero)
2288      {
2289        switch (base)
2290  	{
2291  	case BASE_BINARY:
2292  	case BASE_HEX:
2293  	  width -= 2;
2294  	  break;
2295  	case BASE_OCTAL:
2296  	  if (!(flags & FLAGS_NILPADDING) || (count == 0))
2297  	    width--;
2298  	  break;
2299  	default:
2300  	  break;
2301  	}
2302      }
2303  
2304    /* Output prefixes spaces if needed */
2305    if (! ((flags & FLAGS_LEFTADJUST) ||
2306  	 ((flags & FLAGS_NILPADDING) && (precision == NO_PRECISION))))
2307      {
2308        while (width-- > count)
2309  	self->OutStream(self, CHAR_ADJUST);
2310      }
2311  
2312    /* width has been adjusted for signs and alternatives */
2313    if (isNegative)
2314      self->OutStream(self, '-');
2315    else if (flags & FLAGS_SHOWSIGN)
2316      self->OutStream(self, '+');
2317    else if (flags & FLAGS_SPACE)
2318      self->OutStream(self, ' ');
2319  
2320    /* Prefix is not written when the value is zero */
2321    if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero)
2322      {
2323        switch (base)
2324  	{
2325  	case BASE_BINARY:
2326  	  self->OutStream(self, '0');
2327  	  self->OutStream(self, (flags & FLAGS_UPPER) ? 'B' : 'b');
2328  	  break;
2329  
2330  	case BASE_OCTAL:
2331  	  if (!(flags & FLAGS_NILPADDING) || (count == 0))
2332  	    self->OutStream(self, '0');
2333  	  break;
2334  
2335  	case BASE_HEX:
2336  	  self->OutStream(self, '0');
2337  	  self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2338  	  break;
2339  
2340  	default:
2341  	  break;
2342  	} /* switch base */
2343      }
2344  
2345    /* Output prefixed zero padding if needed */
2346    if (flags & FLAGS_NILPADDING)
2347      {
2348        if (precision == NO_PRECISION)
2349  	precision = width;
2350        while (precision-- > 0)
2351  	{
2352  	  self->OutStream(self, '0');
2353  	  width--;
2354  	}
2355      }
2356  
2357    if (! ignoreNumber)
2358      {
2359        /* Output the number itself */
2360        while (*(++pointer))
2361  	{
2362  	  self->OutStream(self, *pointer);
2363  	}
2364      }
2365  
2366    /* Output trailing spaces if needed */
2367    if (flags & FLAGS_LEFTADJUST)
2368      {
2369        while (width-- > 0)
2370  	self->OutStream(self, CHAR_ADJUST);
2371      }
2372  }
2373  
2374  /*************************************************************************
2375   * TrioWriteStringCharacter
2376   *
2377   * Description:
2378   *  Output a single character of a string
2379   */
2380  TRIO_PRIVATE void
2381  TrioWriteStringCharacter
2382  TRIO_ARGS3((self, ch, flags),
2383  	   trio_class_t *self,
2384  	   int ch,
2385  	   trio_flags_t flags)
2386  {
2387    if (flags & FLAGS_ALTERNATIVE)
2388      {
2389        if (! isprint(ch))
2390  	{
2391  	  /*
2392  	   * Non-printable characters are converted to C escapes or
2393  	   * \number, if no C escape exists.
2394  	   */
2395  	  self->OutStream(self, CHAR_BACKSLASH);
2396  	  switch (ch)
2397  	    {
2398  	    case '\007': self->OutStream(self, 'a'); break;
2399  	    case '\b': self->OutStream(self, 'b'); break;
2400  	    case '\f': self->OutStream(self, 'f'); break;
2401  	    case '\n': self->OutStream(self, 'n'); break;
2402  	    case '\r': self->OutStream(self, 'r'); break;
2403  	    case '\t': self->OutStream(self, 't'); break;
2404  	    case '\v': self->OutStream(self, 'v'); break;
2405  	    case '\\': self->OutStream(self, '\\'); break;
2406  	    default:
2407  	      self->OutStream(self, 'x');
2408  	      TrioWriteNumber(self, (trio_uintmax_t)ch,
2409  			      FLAGS_UNSIGNED | FLAGS_NILPADDING,
2410  			      2, 2, BASE_HEX);
2411  	      break;
2412  	    }
2413  	}
2414        else if (ch == CHAR_BACKSLASH)
2415  	{
2416  	  self->OutStream(self, CHAR_BACKSLASH);
2417  	  self->OutStream(self, CHAR_BACKSLASH);
2418  	}
2419        else
2420  	{
2421  	  self->OutStream(self, ch);
2422  	}
2423      }
2424    else
2425      {
2426        self->OutStream(self, ch);
2427      }
2428  }
2429  
2430  /*************************************************************************
2431   * TrioWriteString
2432   *
2433   * Description:
2434   *  Output a string
2435   */
2436  TRIO_PRIVATE void
2437  TrioWriteString
2438  TRIO_ARGS5((self, string, flags, width, precision),
2439  	   trio_class_t *self,
2440  	   TRIO_CONST char *string,
2441  	   trio_flags_t flags,
2442  	   int width,
2443  	   int precision)
2444  {
2445    int length;
2446    int ch;
2447  
2448    assert(VALID(self));
2449    assert(VALID(self->OutStream));
2450  
2451    if (string == NULL)
2452      {
2453        string = internalNullString;
2454        length = sizeof(internalNullString) - 1;
2455        /* Disable quoting for the null pointer */
2456        flags &= (~FLAGS_QUOTE);
2457        width = 0;
2458      }
2459    else
2460      {
2461        length = trio_length(string);
2462      }
2463    if ((NO_PRECISION != precision) &&
2464        (precision < length))
2465      {
2466        length = precision;
2467      }
2468    width -= length;
2469  
2470    if (flags & FLAGS_QUOTE)
2471      self->OutStream(self, CHAR_QUOTE);
2472  
2473    if (! (flags & FLAGS_LEFTADJUST))
2474      {
2475        while (width-- > 0)
2476  	self->OutStream(self, CHAR_ADJUST);
2477      }
2478  
2479    while (length-- > 0)
2480      {
2481        /* The ctype parameters must be an unsigned char (or EOF) */
2482        ch = (int)((unsigned char)(*string++));
2483        TrioWriteStringCharacter(self, ch, flags);
2484      }
2485  
2486    if (flags & FLAGS_LEFTADJUST)
2487      {
2488        while (width-- > 0)
2489  	self->OutStream(self, CHAR_ADJUST);
2490      }
2491    if (flags & FLAGS_QUOTE)
2492      self->OutStream(self, CHAR_QUOTE);
2493  }
2494  
2495  /*************************************************************************
2496   * TrioWriteWideStringCharacter
2497   *
2498   * Description:
2499   *  Output a wide string as a multi-byte sequence
2500   */
2501  #if TRIO_WIDECHAR
2502  TRIO_PRIVATE int
2503  TrioWriteWideStringCharacter
2504  TRIO_ARGS4((self, wch, flags, width),
2505  	   trio_class_t *self,
2506  	   trio_wchar_t wch,
2507  	   trio_flags_t flags,
2508  	   int width)
2509  {
2510    int size;
2511    int i;
2512    int ch;
2513    char *string;
2514    char buffer[MB_LEN_MAX + 1];
2515  
2516    if (width == NO_WIDTH)
2517      width = sizeof(buffer);
2518  
2519    size = wctomb(buffer, wch);
2520    if ((size <= 0) || (size > width) || (buffer[0] == NIL))
2521      return 0;
2522  
2523    string = buffer;
2524    i = size;
2525    while ((width >= i) && (width-- > 0) && (i-- > 0))
2526      {
2527        /* The ctype parameters must be an unsigned char (or EOF) */
2528        ch = (int)((unsigned char)(*string++));
2529        TrioWriteStringCharacter(self, ch, flags);
2530      }
2531    return size;
2532  }
2533  #endif /* TRIO_WIDECHAR */
2534  
2535  /*************************************************************************
2536   * TrioWriteWideString
2537   *
2538   * Description:
2539   *  Output a wide character string as a multi-byte string
2540   */
2541  #if TRIO_WIDECHAR
2542  TRIO_PRIVATE void
2543  TrioWriteWideString
2544  TRIO_ARGS5((self, wstring, flags, width, precision),
2545  	   trio_class_t *self,
2546  	   TRIO_CONST trio_wchar_t *wstring,
2547  	   trio_flags_t flags,
2548  	   int width,
2549  	   int precision)
2550  {
2551    int length;
2552    int size;
2553  
2554    assert(VALID(self));
2555    assert(VALID(self->OutStream));
2556  
2557  #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
2558    (void)mblen(NULL, 0);
2559  #endif
2560  
2561    if (wstring == NULL)
2562      {
2563        TrioWriteString(self, NULL, flags, width, precision);
2564        return;
2565      }
2566  
2567    if (NO_PRECISION == precision)
2568      {
2569        length = INT_MAX;
2570      }
2571    else
2572      {
2573        length = precision;
2574        width -= length;
2575      }
2576  
2577    if (flags & FLAGS_QUOTE)
2578      self->OutStream(self, CHAR_QUOTE);
2579  
2580    if (! (flags & FLAGS_LEFTADJUST))
2581      {
2582        while (width-- > 0)
2583  	self->OutStream(self, CHAR_ADJUST);
2584      }
2585  
2586    while (length > 0)
2587      {
2588        size = TrioWriteWideStringCharacter(self, *wstring++, flags, length);
2589        if (size == 0)
2590  	break; /* while */
2591        length -= size;
2592      }
2593  
2594    if (flags & FLAGS_LEFTADJUST)
2595      {
2596        while (width-- > 0)
2597  	self->OutStream(self, CHAR_ADJUST);
2598      }
2599    if (flags & FLAGS_QUOTE)
2600      self->OutStream(self, CHAR_QUOTE);
2601  }
2602  #endif /* TRIO_WIDECHAR */
2603  
2604  /*************************************************************************
2605   * TrioWriteDouble
2606   *
2607   * http://wwwold.dkuug.dk/JTC1/SC22/WG14/www/docs/dr_211.htm
2608   *
2609   * "5.2.4.2.2 paragraph #4
2610   *
2611   *  The accuracy [...] is implementation defined, as is the accuracy
2612   *  of the conversion between floating-point internal representations
2613   *  and string representations performed by the libray routine in
2614   *  <stdio.h>"
2615   */
2616  /* FIXME: handle all instances of constant long-double number (L)
2617   *   and *l() math functions.
2618   */
2619  TRIO_PRIVATE void
2620  TrioWriteDouble
2621  TRIO_ARGS6((self, number, flags, width, precision, base),
2622  	   trio_class_t *self,
2623  	   trio_long_double_t number,
2624  	   trio_flags_t flags,
2625  	   int width,
2626  	   int precision,
2627  	   int base)
2628  {
2629    trio_long_double_t integerNumber;
2630    trio_long_double_t fractionNumber;
2631    trio_long_double_t workNumber;
2632    int integerDigits;
2633    int fractionDigits;
2634    int exponentDigits;
2635    int baseDigits;
2636    int integerThreshold;
2637    int fractionThreshold;
2638    int expectedWidth;
2639    int exponent = 0;
2640    unsigned int uExponent = 0;
2641    int exponentBase;
2642    trio_long_double_t dblBase;
2643    trio_long_double_t dblIntegerBase;
2644    trio_long_double_t dblFractionBase;
2645    trio_long_double_t integerAdjust;
2646    trio_long_double_t fractionAdjust;
2647    BOOLEAN_T isNegative;
2648    BOOLEAN_T isExponentNegative = FALSE;
2649    BOOLEAN_T requireTwoDigitExponent;
2650    BOOLEAN_T isHex;
2651    TRIO_CONST char *digits;
2652    char *groupingPointer;
2653    int i;
2654    int index;
2655    BOOLEAN_T hasOnlyZeroes;
2656    int zeroes = 0;
2657    register int trailingZeroes;
2658    BOOLEAN_T keepTrailingZeroes;
2659    BOOLEAN_T keepDecimalPoint;
2660    trio_long_double_t epsilon;
2661  
2662    assert(VALID(self));
2663    assert(VALID(self->OutStream));
2664    assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE));
2665  
2666    /* Determine sign and look for special quantities */
2667    switch (trio_fpclassify_and_signbit(number, &isNegative))
2668      {
2669      case TRIO_FP_NAN:
2670        TrioWriteString(self,
2671  		      (flags & FLAGS_UPPER)
2672  		      ? NAN_UPPER
2673  		      : NAN_LOWER,
2674  		      flags, width, precision);
2675        return;
2676  
2677      case TRIO_FP_INFINITE:
2678        if (isNegative)
2679  	{
2680  	  /* Negative infinity */
2681  	  TrioWriteString(self,
2682  			  (flags & FLAGS_UPPER)
2683  			  ? "-" INFINITE_UPPER
2684  			  : "-" INFINITE_LOWER,
2685  			  flags, width, precision);
2686  	  return;
2687  	}
2688        else
2689  	{
2690  	  /* Positive infinity */
2691  	  TrioWriteString(self,
2692  			  (flags & FLAGS_UPPER)
2693  			  ? INFINITE_UPPER
2694  			  : INFINITE_LOWER,
2695  			  flags, width, precision);
2696  	  return;
2697  	}
2698  
2699      default:
2700        /* Finitude */
2701        break;
2702      }
2703  
2704    /* Normal numbers */
2705    if (flags & FLAGS_LONGDOUBLE)
2706      {
2707        baseDigits = (base == 10)
2708  	? LDBL_DIG
2709  	: (int)floor(LDBL_MANT_DIG / TrioLogarithmBase(base));
2710        epsilon = LDBL_EPSILON;
2711      }
2712    else if (flags & FLAGS_SHORT)
2713      {
2714        baseDigits = (base == BASE_DECIMAL)
2715  	? FLT_DIG
2716  	: (int)floor(FLT_MANT_DIG / TrioLogarithmBase(base));
2717        epsilon = FLT_EPSILON;
2718      }
2719    else
2720      {
2721        baseDigits = (base == BASE_DECIMAL)
2722  	? DBL_DIG
2723  	: (int)floor(DBL_MANT_DIG / TrioLogarithmBase(base));
2724        epsilon = DBL_EPSILON;
2725      }
2726  
2727    digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
2728    isHex = (base == BASE_HEX);
2729    if (base == NO_BASE)
2730      base = BASE_DECIMAL;
2731    dblBase = (trio_long_double_t)base;
2732    keepTrailingZeroes = !( (flags & FLAGS_ROUNDING) ||
2733  			  ( (flags & FLAGS_FLOAT_G) &&
2734  			    !(flags & FLAGS_ALTERNATIVE) ) );
2735  
2736    if (flags & FLAGS_ROUNDING)
2737      precision = baseDigits;
2738  
2739    if (precision == NO_PRECISION)
2740      {
2741        if (isHex)
2742  	{
2743  	  keepTrailingZeroes = FALSE;
2744  	  precision = FLT_MANT_DIG;
2745  	}
2746        else
2747  	{
2748  	  precision = FLT_DIG;
2749  	}
2750      }
2751  
2752    if (isNegative)
2753      number = -number;
2754  
2755    if (isHex)
2756      flags |= FLAGS_FLOAT_E;
2757  
2758    if (flags & FLAGS_FLOAT_G)
2759      {
2760        if (precision == 0)
2761  	precision = 1;
2762  
2763        if ((number < 1.0E-4) || (number > powl(base,
2764  					      (trio_long_double_t)precision)))
2765  	{
2766  	  /* Use scientific notation */
2767  	  flags |= FLAGS_FLOAT_E;
2768  	}
2769        else if (number < 1.0)
2770  	{
2771  	  /*
2772  	   * Use normal notation. If the integer part of the number is
2773  	   * zero, then adjust the precision to include leading fractional
2774  	   * zeros.
2775  	   */
2776  	  workNumber = TrioLogarithm(number, base);
2777  	  workNumber = TRIO_FABS(workNumber);
2778  	  if (workNumber - floorl(workNumber) < 0.001)
2779  	    workNumber--;
2780  	  zeroes = (int)floorl(workNumber);
2781  	}
2782      }
2783  
2784    if (flags & FLAGS_FLOAT_E)
2785      {
2786        /* Scale the number */
2787        workNumber = TrioLogarithm(number, base);
2788        if (trio_isinf(workNumber) == -1)
2789  	{
2790  	  exponent = 0;
2791  	  /* Undo setting */
2792  	  if (flags & FLAGS_FLOAT_G)
2793  	    flags &= ~FLAGS_FLOAT_E;
2794  	}
2795        else
2796  	{
2797  	  exponent = (int)floorl(workNumber);
2798  	  number /= powl(dblBase, (trio_long_double_t)exponent);
2799  	  isExponentNegative = (exponent < 0);
2800  	  uExponent = (isExponentNegative) ? -exponent : exponent;
2801  	  if (isHex)
2802  	    uExponent *= 4; /* log16(2) */
2803  	  /* No thousand separators */
2804  	  flags &= ~FLAGS_QUOTE;
2805  	}
2806      }
2807  
2808    integerNumber = floorl(number);
2809    fractionNumber = number - integerNumber;
2810  
2811    /*
2812     * Truncated number.
2813     *
2814     * Precision is number of significant digits for FLOAT_G
2815     * and number of fractional digits for others.
2816     */
2817    integerDigits = (integerNumber > epsilon)
2818      ? 1 + (int)TrioLogarithm(integerNumber, base)
2819      : 1;
2820    fractionDigits = ((flags & FLAGS_FLOAT_G) && (zeroes == 0))
2821      ? precision - integerDigits
2822      : zeroes + precision;
2823  
2824    dblFractionBase = TrioPower(base, fractionDigits);
2825  
2826    workNumber = number + 0.5 / dblFractionBase;
2827    if (floorl(number) != floorl(workNumber))
2828      {
2829        if (flags & FLAGS_FLOAT_E)
2830  	{
2831  	  /* Adjust if number was rounded up one digit (ie. 0.99 to 1.00) */
2832  	  exponent++;
2833  	  isExponentNegative = (exponent < 0);
2834  	  uExponent = (isExponentNegative) ? -exponent : exponent;
2835  	  if (isHex)
2836  	    uExponent *= 4; /* log16(2) */
2837  	  workNumber = (number + 0.5 / dblFractionBase) / dblBase;
2838  	  integerNumber = floorl(workNumber);
2839  	  fractionNumber = workNumber - integerNumber;
2840  	}
2841        else
2842  	{
2843  	  /* Adjust if number was rounded up one digit (ie. 99 to 100) */
2844  	  integerNumber = floorl(number + 0.5);
2845  	  fractionNumber = 0.0;
2846  	  integerDigits = (integerNumber > epsilon)
2847  	    ? 1 + (int)TrioLogarithm(integerNumber, base)
2848  	    : 1;
2849  	}
2850      }
2851  
2852    /* Estimate accuracy */
2853    integerAdjust = fractionAdjust = 0.5;
2854    if (flags & FLAGS_ROUNDING)
2855      {
2856        if (integerDigits > baseDigits)
2857  	{
2858  	  integerThreshold = baseDigits;
2859  	  fractionDigits = 0;
2860  	  dblFractionBase = 1.0;
2861  	  fractionThreshold = 0;
2862  	  precision = 0; /* Disable decimal-point */
2863  	  integerAdjust = TrioPower(base, integerDigits - integerThreshold - 1);
2864  	  fractionAdjust = 0.0;
2865  	}
2866        else
2867  	{
2868  	  integerThreshold = integerDigits;
2869  	  fractionThreshold = fractionDigits - integerThreshold;
2870  	  fractionAdjust = 1.0;
2871  	}
2872      }
2873    else
2874      {
2875        integerThreshold = INT_MAX;
2876        fractionThreshold = INT_MAX;
2877      }
2878  
2879    /*
2880     * Calculate expected width.
2881     *  sign + integer part + thousands separators + decimal point
2882     *  + fraction + exponent
2883     */
2884    fractionAdjust /= dblFractionBase;
2885    hasOnlyZeroes = (floorl((fractionNumber + fractionAdjust) * dblFractionBase) < epsilon);
2886    keepDecimalPoint = ( (flags & FLAGS_ALTERNATIVE) ||
2887  		       !((precision == 0) ||
2888  			 (!keepTrailingZeroes && hasOnlyZeroes)) );
2889    if (flags & FLAGS_FLOAT_E)
2890      {
2891        exponentDigits = (uExponent == 0)
2892  	? 1
2893  	: (int)ceil(TrioLogarithm((double)(uExponent + 1),
2894  				  (isHex) ? 10.0 : base));
2895      }
2896    else
2897      exponentDigits = 0;
2898    requireTwoDigitExponent = ((base == BASE_DECIMAL) && (exponentDigits == 1));
2899  
2900    expectedWidth = integerDigits + fractionDigits
2901      + (keepDecimalPoint
2902         ? internalDecimalPointLength
2903         : 0)
2904      + ((flags & FLAGS_QUOTE)
2905         ? TrioCalcThousandSeparatorLength(integerDigits)
2906         : 0);
2907    if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
2908      expectedWidth += sizeof("-") - 1;
2909    if (exponentDigits > 0)
2910      expectedWidth += exponentDigits +
2911        ((requireTwoDigitExponent ? sizeof("E+0") : sizeof("E+")) - 1);
2912    if (isHex)
2913      expectedWidth += sizeof("0X") - 1;
2914  
2915    /* Output prefixing */
2916    if (flags & FLAGS_NILPADDING)
2917      {
2918        /* Leading zeros must be after sign */
2919        if (isNegative)
2920  	self->OutStream(self, '-');
2921        else if (flags & FLAGS_SHOWSIGN)
2922  	self->OutStream(self, '+');
2923        else if (flags & FLAGS_SPACE)
2924  	self->OutStream(self, ' ');
2925        if (isHex)
2926  	{
2927  	  self->OutStream(self, '0');
2928  	  self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2929  	}
2930        if (!(flags & FLAGS_LEFTADJUST))
2931  	{
2932  	  for (i = expectedWidth; i < width; i++)
2933  	    {
2934  	      self->OutStream(self, '0');
2935  	    }
2936  	}
2937      }
2938    else
2939      {
2940        /* Leading spaces must be before sign */
2941        if (!(flags & FLAGS_LEFTADJUST))
2942  	{
2943  	  for (i = expectedWidth; i < width; i++)
2944  	    {
2945  	      self->OutStream(self, CHAR_ADJUST);
2946  	    }
2947  	}
2948        if (isNegative)
2949  	self->OutStream(self, '-');
2950        else if (flags & FLAGS_SHOWSIGN)
2951  	self->OutStream(self, '+');
2952        else if (flags & FLAGS_SPACE)
2953  	self->OutStream(self, ' ');
2954        if (isHex)
2955  	{
2956  	  self->OutStream(self, '0');
2957  	  self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2958  	}
2959      }
2960  
2961    /* Output the integer part and thousand separators */
2962    dblIntegerBase = 1.0 / TrioPower(base, integerDigits - 1);
2963    for (i = 0; i < integerDigits; i++)
2964      {
2965        workNumber = floorl(((integerNumber + integerAdjust) * dblIntegerBase));
2966        if (i > integerThreshold)
2967  	{
2968  	  /* Beyond accuracy */
2969  	  self->OutStream(self, digits[0]);
2970  	}
2971        else
2972  	{
2973  	  self->OutStream(self, digits[(int)fmodl(workNumber, dblBase)]);
2974  	}
2975        dblIntegerBase *= dblBase;
2976  
2977        if (((flags & (FLAGS_FLOAT_E | FLAGS_QUOTE)) == FLAGS_QUOTE)
2978  	  && TrioFollowedBySeparator(integerDigits - i))
2979  	{
2980  	  for (groupingPointer = internalThousandSeparator;
2981  	       *groupingPointer != NIL;
2982  	       groupingPointer++)
2983  	    {
2984  	      self->OutStream(self, *groupingPointer);
2985  	    }
2986  	}
2987      }
2988  
2989    /* Insert decimal point and build the fraction part */
2990    trailingZeroes = 0;
2991  
2992    if (keepDecimalPoint)
2993      {
2994        if (internalDecimalPoint)
2995  	{
2996  	  self->OutStream(self, internalDecimalPoint);
2997  	}
2998        else
2999  	{
3000  	  for (i = 0; i < internalDecimalPointLength; i++)
3001  	    {
3002  	      self->OutStream(self, internalDecimalPointString[i]);
3003  	    }
3004  	}
3005      }
3006  
3007    for (i = 0; i < fractionDigits; i++)
3008      {
3009        if ((integerDigits > integerThreshold) || (i > fractionThreshold))
3010  	{
3011  	  /* Beyond accuracy */
3012  	  trailingZeroes++;
3013  	}
3014        else
3015  	{
3016  	  fractionNumber *= dblBase;
3017  	  fractionAdjust *= dblBase;
3018  	  workNumber = floorl(fractionNumber + fractionAdjust);
3019  	  fractionNumber -= workNumber;
3020  	  index = (int)fmodl(workNumber, dblBase);
3021  	  if (index == 0)
3022  	    {
3023  	      trailingZeroes++;
3024  	    }
3025  	  else
3026  	    {
3027  	      while (trailingZeroes > 0)
3028  		{
3029  		  /* Not trailing zeroes after all */
3030  		  self->OutStream(self, digits[0]);
3031  		  trailingZeroes--;
3032  		}
3033  	      self->OutStream(self, digits[index]);
3034  	    }
3035  	}
3036      }
3037  
3038    if (keepTrailingZeroes)
3039      {
3040        while (trailingZeroes > 0)
3041  	{
3042  	  self->OutStream(self, digits[0]);
3043  	  trailingZeroes--;
3044  	}
3045      }
3046  
3047    /* Output exponent */
3048    if (exponentDigits > 0)
3049      {
3050        self->OutStream(self,
3051  		      isHex
3052  		      ? ((flags & FLAGS_UPPER) ? 'P' : 'p')
3053  		      : ((flags & FLAGS_UPPER) ? 'E' : 'e'));
3054        self->OutStream(self, (isExponentNegative) ? '-' : '+');
3055  
3056        /* The exponent must contain at least two digits */
3057        if (requireTwoDigitExponent)
3058          self->OutStream(self, '0');
3059  
3060        if (isHex)
3061  	base = 10.0;
3062        exponentBase = (int)TrioPower(base, exponentDigits - 1);
3063        for (i = 0; i < exponentDigits; i++)
3064  	{
3065  	  self->OutStream(self, digits[(uExponent / exponentBase) % base]);
3066  	  exponentBase /= base;
3067  	}
3068      }
3069    /* Output trailing spaces */
3070    if (flags & FLAGS_LEFTADJUST)
3071      {
3072        for (i = expectedWidth; i < width; i++)
3073  	{
3074  	  self->OutStream(self, CHAR_ADJUST);
3075  	}
3076      }
3077  }
3078  
3079  /*************************************************************************
3080   * TrioFormatProcess
3081   *
3082   * Description:
3083   *  This is the main engine for formatting output
3084   */
3085  TRIO_PRIVATE int
3086  TrioFormatProcess
3087  TRIO_ARGS3((data, format, parameters),
3088  	   trio_class_t *data,
3089  	   TRIO_CONST char *format,
3090  	   trio_parameter_t *parameters)
3091  {
3092  #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
3093    int charlen;
3094  #endif
3095    int i;
3096    TRIO_CONST char *string;
3097    trio_pointer_t pointer;
3098    trio_flags_t flags;
3099    int width;
3100    int precision;
3101    int base;
3102    int index;
3103  
3104    index = 0;
3105    i = 0;
3106  #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
3107    (void)mblen(NULL, 0);
3108  #endif
3109  
3110    while (format[index])
3111      {
3112  #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
3113        if (! isascii(format[index]))
3114  	{
3115  	  charlen = mblen(&format[index], MB_LEN_MAX);
3116  	  /*
3117  	   * Only valid multibyte characters are handled here. Invalid
3118  	   * multibyte characters (charlen == -1) are handled as normal
3119  	   * characters.
3120  	   */
3121  	  if (charlen != -1)
3122  	    {
3123  	      while (charlen-- > 0)
3124  		{
3125  		  data->OutStream(data, format[index++]);
3126  		}
3127  	      continue; /* while characters left in formatting string */
3128  	    }
3129  	}
3130  #endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
3131        if (CHAR_IDENTIFIER == format[index])
3132  	{
3133  	  if (CHAR_IDENTIFIER == format[index + 1])
3134  	    {
3135  	      data->OutStream(data, CHAR_IDENTIFIER);
3136  	      index += 2;
3137  	    }
3138  	  else
3139  	    {
3140  	      /* Skip the parameter entries */
3141  	      while (parameters[i].type == FORMAT_PARAMETER)
3142  		i++;
3143  
3144  	      flags = parameters[i].flags;
3145  
3146  	      /* Find width */
3147  	      width = parameters[i].width;
3148  	      if (flags & FLAGS_WIDTH_PARAMETER)
3149  		{
3150  		  /* Get width from parameter list */
3151  		  width = (int)parameters[width].data.number.as_signed;
3152  		  if (width < 0)
3153  		    {
3154  		      /*
3155  		       * A negative width is the same as the - flag and
3156  		       * a positive width.
3157  		       */
3158  		      flags |= FLAGS_LEFTADJUST;
3159  		      flags &= ~FLAGS_NILPADDING;
3160  		      width = -width;
3161  		    }
3162  		}
3163  
3164  	      /* Find precision */
3165  	      if (flags & FLAGS_PRECISION)
3166  		{
3167  		  precision = parameters[i].precision;
3168  		  if (flags & FLAGS_PRECISION_PARAMETER)
3169  		    {
3170  		      /* Get precision from parameter list */
3171  		      precision = (int)parameters[precision].data.number.as_signed;
3172  		      if (precision < 0)
3173  			{
3174  			  /*
3175  			   * A negative precision is the same as no
3176  			   * precision
3177  			   */
3178  			  precision = NO_PRECISION;
3179  			}
3180  		    }
3181  		}
3182  	      else
3183  		{
3184  		  precision = NO_PRECISION;
3185  		}
3186  
3187  	      /* Find base */
3188  	      base = parameters[i].base;
3189  	      if (flags & FLAGS_BASE_PARAMETER)
3190  		{
3191  		  /* Get base from parameter list */
3192  		  base = (int)parameters[base].data.number.as_signed;
3193  		}
3194  
3195  	      switch (parameters[i].type)
3196  		{
3197  		case FORMAT_CHAR:
3198  		  if (flags & FLAGS_QUOTE)
3199  		    data->OutStream(data, CHAR_QUOTE);
3200  		  if (! (flags & FLAGS_LEFTADJUST))
3201  		    {
3202  		      while (--width > 0)
3203  			data->OutStream(data, CHAR_ADJUST);
3204  		    }
3205  #if TRIO_WIDECHAR
3206  		  if (flags & FLAGS_WIDECHAR)
3207  		    {
3208  		      TrioWriteWideStringCharacter(data,
3209  						   (trio_wchar_t)parameters[i].data.number.as_signed,
3210  						   flags,
3211  						   NO_WIDTH);
3212  		    }
3213  		  else
3214  #endif
3215  		    {
3216  		      TrioWriteStringCharacter(data,
3217  					       (int)parameters[i].data.number.as_signed,
3218  					       flags);
3219  		    }
3220  
3221  		  if (flags & FLAGS_LEFTADJUST)
3222  		    {
3223  		      while(--width > 0)
3224  			data->OutStream(data, CHAR_ADJUST);
3225  		    }
3226  		  if (flags & FLAGS_QUOTE)
3227  		    data->OutStream(data, CHAR_QUOTE);
3228  
3229  		  break; /* FORMAT_CHAR */
3230  
3231  		case FORMAT_INT:
3232  		  TrioWriteNumber(data,
3233  				  parameters[i].data.number.as_unsigned,
3234  				  flags,
3235  				  width,
3236  				  precision,
3237  				  base);
3238  
3239  		  break; /* FORMAT_INT */
3240  
3241  		case FORMAT_DOUBLE:
3242  		  TrioWriteDouble(data,
3243  				  parameters[i].data.longdoubleNumber,
3244  				  flags,
3245  				  width,
3246  				  precision,
3247  				  base);
3248  		  break; /* FORMAT_DOUBLE */
3249  
3250  		case FORMAT_STRING:
3251  #if TRIO_WIDECHAR
3252  		  if (flags & FLAGS_WIDECHAR)
3253  		    {
3254  		      TrioWriteWideString(data,
3255  					  parameters[i].data.wstring,
3256  					  flags,
3257  					  width,
3258  					  precision);
3259  		    }
3260  		  else
3261  #endif
3262  		    {
3263  		      TrioWriteString(data,
3264  				      parameters[i].data.string,
3265  				      flags,
3266  				      width,
3267  				      precision);
3268  		    }
3269  		  break; /* FORMAT_STRING */
3270  
3271  		case FORMAT_POINTER:
3272  		  {
3273  		    trio_reference_t reference;
3274  
3275  		    reference.data = data;
3276  		    reference.parameter = &parameters[i];
3277  		    trio_print_pointer(&reference, parameters[i].data.pointer);
3278  		  }
3279  		  break; /* FORMAT_POINTER */
3280  
3281  		case FORMAT_COUNT:
3282  		  pointer = parameters[i].data.pointer;
3283  		  if (NULL != pointer)
3284  		    {
3285  		      /*
3286  		       * C99 paragraph 7.19.6.1.8 says "the number of
3287  		       * characters written to the output stream so far by
3288  		       * this call", which is data->committed
3289  		       */
3290  #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
3291  		      if (flags & FLAGS_SIZE_T)
3292  			*(size_t *)pointer = (size_t)data->committed;
3293  		      else
3294  #endif
3295  #if defined(QUALIFIER_PTRDIFF_T)
3296  		      if (flags & FLAGS_PTRDIFF_T)
3297  			*(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
3298  		      else
3299  #endif
3300  #if defined(QUALIFIER_INTMAX_T)
3301  		      if (flags & FLAGS_INTMAX_T)
3302  			*(trio_intmax_t *)pointer = (trio_intmax_t)data->committed;
3303  		      else
3304  #endif
3305  		      if (flags & FLAGS_QUAD)
3306  			{
3307  			  *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->committed;
3308  			}
3309  		      else if (flags & FLAGS_LONG)
3310  			{
3311  			  *(long int *)pointer = (long int)data->committed;
3312  			}
3313  		      else if (flags & FLAGS_SHORT)
3314  			{
3315  			  *(short int *)pointer = (short int)data->committed;
3316  			}
3317  		      else
3318  			{
3319  			  *(int *)pointer = (int)data->committed;
3320  			}
3321  		    }
3322  		  break; /* FORMAT_COUNT */
3323  
3324  		case FORMAT_PARAMETER:
3325  		  break; /* FORMAT_PARAMETER */
3326  
3327  #if defined(FORMAT_ERRNO)
3328  		case FORMAT_ERRNO:
3329  		  string = trio_error(parameters[i].data.errorNumber);
3330  		  if (string)
3331  		    {
3332  		      TrioWriteString(data,
3333  				      string,
3334  				      flags,
3335  				      width,
3336  				      precision);
3337  		    }
3338  		  else
3339  		    {
3340  		      data->OutStream(data, '#');
3341  		      TrioWriteNumber(data,
3342  				      (trio_uintmax_t)parameters[i].data.errorNumber,
3343  				      flags,
3344  				      width,
3345  				      precision,
3346  				      BASE_DECIMAL);
3347  		    }
3348  		  break; /* FORMAT_ERRNO */
3349  #endif /* defined(FORMAT_ERRNO) */
3350  
3351  #if defined(FORMAT_USER_DEFINED)
3352  		case FORMAT_USER_DEFINED:
3353  		  {
3354  		    trio_reference_t reference;
3355  		    trio_userdef_t *def = NULL;
3356  
3357  		    if (parameters[i].user_name[0] == NIL)
3358  		      {
3359  			/* Use handle */
3360  			if ((i > 0) ||
3361  			    (parameters[i - 1].type == FORMAT_PARAMETER))
3362  			  def = (trio_userdef_t *)parameters[i - 1].data.pointer;
3363  		      }
3364  		    else
3365  		      {
3366  			/* Look up namespace */
3367  			def = TrioFindNamespace(parameters[i].user_name, NULL);
3368  		      }
3369  		    if (def) {
3370  		      reference.data = data;
3371  		      reference.parameter = &parameters[i];
3372  		      def->callback(&reference);
3373  		    }
3374  		  }
3375  		  break;
3376  #endif /* defined(FORMAT_USER_DEFINED) */
3377  
3378  		default:
3379  		  break;
3380  		} /* switch parameter type */
3381  
3382  	      /* Prepare for next */
3383  	      index = parameters[i].indexAfterSpecifier;
3384  	      i++;
3385  	    }
3386  	}
3387        else /* not identifier */
3388  	{
3389  	  data->OutStream(data, format[index++]);
3390  	}
3391      }
3392    return data->processed;
3393  }
3394  
3395  /*************************************************************************
3396   * TrioFormatRef
3397   */
3398  TRIO_PRIVATE int
3399  TrioFormatRef
3400  TRIO_ARGS4((reference, format, arglist, argarray),
3401  	   trio_reference_t *reference,
3402  	   TRIO_CONST char *format,
3403  	   TRIO_VA_LIST_PTR arglist,
3404  	   trio_pointer_t *argarray)
3405  {
3406    int status;
3407    trio_parameter_t parameters[MAX_PARAMETERS];
3408  
3409    status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray);
3410    if (status < 0)
3411      return status;
3412  
3413    status = TrioFormatProcess(reference->data, format, parameters);
3414    if (reference->data->error != 0)
3415      {
3416        status = reference->data->error;
3417      }
3418    return status;
3419  }
3420  
3421  /*************************************************************************
3422   * TrioFormat
3423   */
3424  TRIO_PRIVATE int
3425  TrioFormat
3426  TRIO_ARGS6((destination, destinationSize, OutStream, format, arglist, argarray),
3427  	   trio_pointer_t destination,
3428  	   size_t destinationSize,
3429  	   void (*OutStream) TRIO_PROTO((trio_class_t *, int)),
3430  	   TRIO_CONST char *format,
3431  	   TRIO_VA_LIST_PTR arglist,
3432  	   trio_pointer_t *argarray)
3433  {
3434    int status;
3435    trio_class_t data;
3436    trio_parameter_t parameters[MAX_PARAMETERS];
3437  
3438    assert(VALID(OutStream));
3439    assert(VALID(format));
3440  
3441    memset(&data, 0, sizeof(data));
3442    data.OutStream = OutStream;
3443    data.location = destination;
3444    data.max = destinationSize;
3445    data.error = 0;
3446  
3447  #if defined(USE_LOCALE)
3448    if (NULL == internalLocaleValues)
3449      {
3450        TrioSetLocale();
3451      }
3452  #endif
3453  
3454    status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray);
3455    if (status < 0)
3456      return status;
3457  
3458    status = TrioFormatProcess(&data, format, parameters);
3459    if (data.error != 0)
3460      {
3461        status = data.error;
3462      }
3463    return status;
3464  }
3465  
3466  /*************************************************************************
3467   * TrioOutStreamFile
3468   */
3469  TRIO_PRIVATE void
3470  TrioOutStreamFile
3471  TRIO_ARGS2((self, output),
3472  	   trio_class_t *self,
3473  	   int output)
3474  {
3475    FILE *file;
3476  
3477    assert(VALID(self));
3478    assert(VALID(self->location));
3479  
3480    file = (FILE *)self->location;
3481    self->processed++;
3482    if (fputc(output, file) == EOF)
3483      {
3484        self->error = TRIO_ERROR_RETURN(TRIO_EOF, 0);
3485      }
3486    else
3487      {
3488        self->committed++;
3489      }
3490  }
3491  
3492  /*************************************************************************
3493   * TrioOutStreamFileDescriptor
3494   */
3495  TRIO_PRIVATE void
3496  TrioOutStreamFileDescriptor
3497  TRIO_ARGS2((self, output),
3498  	   trio_class_t *self,
3499  	   int output)
3500  {
3501    int fd;
3502    char ch;
3503  
3504    assert(VALID(self));
3505  
3506    fd = *((int *)self->location);
3507    ch = (char)output;
3508    self->processed++;
3509    if (write(fd, &ch, sizeof(char)) == -1)
3510      {
3511        self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0);
3512      }
3513    else
3514      {
3515        self->committed++;
3516      }
3517  }
3518  
3519  /*************************************************************************
3520   * TrioOutStreamCustom
3521   */
3522  TRIO_PRIVATE void
3523  TrioOutStreamCustom
3524  TRIO_ARGS2((self, output),
3525  	   trio_class_t *self,
3526  	   int output)
3527  {
3528    int status;
3529    trio_custom_t *data;
3530  
3531    assert(VALID(self));
3532    assert(VALID(self->location));
3533  
3534    data = (trio_custom_t *)self->location;
3535    if (data->stream.out)
3536      {
3537        status = (data->stream.out)(data->closure, output);
3538        if (status >= 0)
3539  	{
3540  	  self->committed++;
3541  	}
3542        else
3543  	{
3544  	  if (self->error == 0)
3545  	    {
3546  	      self->error = TRIO_ERROR_RETURN(TRIO_ECUSTOM, -status);
3547  	    }
3548  	}
3549      }
3550    self->processed++;
3551  }
3552  
3553  /*************************************************************************
3554   * TrioOutStreamString
3555   */
3556  TRIO_PRIVATE void
3557  TrioOutStreamString
3558  TRIO_ARGS2((self, output),
3559  	   trio_class_t *self,
3560  	   int output)
3561  {
3562    char **buffer;
3563  
3564    assert(VALID(self));
3565    assert(VALID(self->location));
3566  
3567    buffer = (char **)self->location;
3568    **buffer = (char)output;
3569    (*buffer)++;
3570    self->processed++;
3571    self->committed++;
3572  }
3573  
3574  /*************************************************************************
3575   * TrioOutStreamStringMax
3576   */
3577  TRIO_PRIVATE void
3578  TrioOutStreamStringMax
3579  TRIO_ARGS2((self, output),
3580  	   trio_class_t *self,
3581  	   int output)
3582  {
3583    char **buffer;
3584  
3585    assert(VALID(self));
3586    assert(VALID(self->location));
3587  
3588    buffer = (char **)self->location;
3589  
3590    if (self->processed < self->max)
3591      {
3592        **buffer = (char)output;
3593        (*buffer)++;
3594        self->committed++;
3595      }
3596    self->processed++;
3597  }
3598  
3599  /*************************************************************************
3600   * TrioOutStreamStringDynamic
3601   */
3602  TRIO_PRIVATE void
3603  TrioOutStreamStringDynamic
3604  TRIO_ARGS2((self, output),
3605  	   trio_class_t *self,
3606  	   int output)
3607  {
3608    assert(VALID(self));
3609    assert(VALID(self->location));
3610  
3611    if (self->error == 0)
3612      {
3613        trio_xstring_append_char((trio_string_t *)self->location,
3614  			       (char)output);
3615        self->committed++;
3616      }
3617    /* The processed variable must always be increased */
3618    self->processed++;
3619  }
3620  
3621  /*************************************************************************
3622   *
3623   * Formatted printing functions
3624   *
3625   ************************************************************************/
3626  
3627  #if defined(TRIO_DOCUMENTATION)
3628  # include "doc/doc_printf.h"
3629  #endif
3630  /** @addtogroup Printf
3631      @{
3632  */
3633  
3634  /*************************************************************************
3635   * printf
3636   */
3637  
3638  /**
3639     Print to standard output stream.
3640  
3641     @param format Formatting string.
3642     @param ... Arguments.
3643     @return Number of printed characters.
3644   */
3645  TRIO_PUBLIC int
3646  trio_printf
3647  TRIO_VARGS2((format, va_alist),
3648  	    TRIO_CONST char *format,
3649  	    TRIO_VA_DECL)
3650  {
3651    int status;
3652    va_list args;
3653  
3654    assert(VALID(format));
3655  
3656    TRIO_VA_START(args, format);
3657    status = TrioFormat(stdout, 0, TrioOutStreamFile, format, TRIO_VA_LIST_ADDR(args), NULL);
3658    TRIO_VA_END(args);
3659    return status;
3660  }
3661  
3662  /**
3663     Print to standard output stream.
3664  
3665     @param format Formatting string.
3666     @param args Arguments.
3667     @return Number of printed characters.
3668   */
3669  TRIO_PUBLIC int
3670  trio_vprintf
3671  TRIO_ARGS2((format, args),
3672  	   TRIO_CONST char *format,
3673  	   va_list args)
3674  {
3675    assert(VALID(format));
3676  
3677    return TrioFormat(stdout, 0, TrioOutStreamFile, format, TRIO_VA_LIST_ADDR(args), NULL);
3678  }
3679  
3680  /**
3681     Print to standard output stream.
3682  
3683     @param format Formatting string.
3684     @param args Arguments.
3685     @return Number of printed characters.
3686   */
3687  TRIO_PUBLIC int
3688  trio_printfv
3689  TRIO_ARGS2((format, args),
3690  	   TRIO_CONST char *format,
3691  	   trio_pointer_t * args)
3692  {
3693    assert(VALID(format));
3694  
3695    return TrioFormat(stdout, 0, TrioOutStreamFile, format, NULL, args);
3696  }
3697  
3698  /*************************************************************************
3699   * fprintf
3700   */
3701  
3702  /**
3703     Print to file.
3704  
3705     @param file File pointer.
3706     @param format Formatting string.
3707     @param ... Arguments.
3708     @return Number of printed characters.
3709   */
3710  TRIO_PUBLIC int
3711  trio_fprintf
3712  TRIO_VARGS3((file, format, va_alist),
3713  	    FILE *file,
3714  	    TRIO_CONST char *format,
3715  	    TRIO_VA_DECL)
3716  {
3717    int status;
3718    va_list args;
3719  
3720    assert(VALID(file));
3721    assert(VALID(format));
3722  
3723    TRIO_VA_START(args, format);
3724    status = TrioFormat(file, 0, TrioOutStreamFile, format, TRIO_VA_LIST_ADDR(args), NULL);
3725    TRIO_VA_END(args);
3726    return status;
3727  }
3728  
3729  /**
3730     Print to file.
3731  
3732     @param file File pointer.
3733     @param format Formatting string.
3734     @param args Arguments.
3735     @return Number of printed characters.
3736   */
3737  TRIO_PUBLIC int
3738  trio_vfprintf
3739  TRIO_ARGS3((file, format, args),
3740  	   FILE *file,
3741  	   TRIO_CONST char *format,
3742  	   va_list args)
3743  {
3744    assert(VALID(file));
3745    assert(VALID(format));
3746  
3747    return TrioFormat(file, 0, TrioOutStreamFile, format, TRIO_VA_LIST_ADDR(args), NULL);
3748  }
3749  
3750  /**
3751     Print to file.
3752  
3753     @param file File pointer.
3754     @param format Formatting string.
3755     @param args Arguments.
3756     @return Number of printed characters.
3757   */
3758  TRIO_PUBLIC int
3759  trio_fprintfv
3760  TRIO_ARGS3((file, format, args),
3761  	   FILE *file,
3762  	   TRIO_CONST char *format,
3763  	   trio_pointer_t * args)
3764  {
3765    assert(VALID(file));
3766    assert(VALID(format));
3767  
3768    return TrioFormat(file, 0, TrioOutStreamFile, format, NULL, args);
3769  }
3770  
3771  /*************************************************************************
3772   * dprintf
3773   */
3774  
3775  /**
3776     Print to file descriptor.
3777  
3778     @param fd File descriptor.
3779     @param format Formatting string.
3780     @param ... Arguments.
3781     @return Number of printed characters.
3782   */
3783  TRIO_PUBLIC int
3784  trio_dprintf
3785  TRIO_VARGS3((fd, format, va_alist),
3786  	    int fd,
3787  	    TRIO_CONST char *format,
3788  	    TRIO_VA_DECL)
3789  {
3790    int status;
3791    va_list args;
3792  
3793    assert(VALID(format));
3794  
3795    TRIO_VA_START(args, format);
3796    status = TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, TRIO_VA_LIST_ADDR(args), NULL);
3797    TRIO_VA_END(args);
3798    return status;
3799  }
3800  
3801  /**
3802     Print to file descriptor.
3803  
3804     @param fd File descriptor.
3805     @param format Formatting string.
3806     @param args Arguments.
3807     @return Number of printed characters.
3808   */
3809  TRIO_PUBLIC int
3810  trio_vdprintf
3811  TRIO_ARGS3((fd, format, args),
3812  	   int fd,
3813  	   TRIO_CONST char *format,
3814  	   va_list args)
3815  {
3816    assert(VALID(format));
3817  
3818    return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, TRIO_VA_LIST_ADDR(args), NULL);
3819  }
3820  
3821  /**
3822     Print to file descriptor.
3823  
3824     @param fd File descriptor.
3825     @param format Formatting string.
3826     @param args Arguments.
3827     @return Number of printed characters.
3828   */
3829  TRIO_PUBLIC int
3830  trio_dprintfv
3831  TRIO_ARGS3((fd, format, args),
3832  	   int fd,
3833  	   TRIO_CONST char *format,
3834  	   trio_pointer_t *args)
3835  {
3836    assert(VALID(format));
3837  
3838    return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, NULL, args);
3839  }
3840  
3841  /*************************************************************************
3842   * cprintf
3843   */
3844  TRIO_PUBLIC int
3845  trio_cprintf
3846  TRIO_VARGS4((stream, closure, format, va_alist),
3847  	    trio_outstream_t stream,
3848  	    trio_pointer_t closure,
3849  	    TRIO_CONST char *format,
3850  	    TRIO_VA_DECL)
3851  {
3852    int status;
3853    va_list args;
3854    trio_custom_t data;
3855  
3856    assert(VALID(stream));
3857    assert(VALID(format));
3858  
3859    TRIO_VA_START(args, format);
3860    data.stream.out = stream;
3861    data.closure = closure;
3862    status = TrioFormat(&data, 0, TrioOutStreamCustom, format, TRIO_VA_LIST_ADDR(args), NULL);
3863    TRIO_VA_END(args);
3864    return status;
3865  }
3866  
3867  TRIO_PUBLIC int
3868  trio_vcprintf
3869  TRIO_ARGS4((stream, closure, format, args),
3870  	   trio_outstream_t stream,
3871  	   trio_pointer_t closure,
3872  	   TRIO_CONST char *format,
3873  	   va_list args)
3874  {
3875    trio_custom_t data;
3876  
3877    assert(VALID(stream));
3878    assert(VALID(format));
3879  
3880    data.stream.out = stream;
3881    data.closure = closure;
3882    return TrioFormat(&data, 0, TrioOutStreamCustom, format, TRIO_VA_LIST_ADDR(args), NULL);
3883  }
3884  
3885  TRIO_PUBLIC int
3886  trio_cprintfv
3887  TRIO_ARGS4((stream, closure, format, args),
3888  	   trio_outstream_t stream,
3889  	   trio_pointer_t closure,
3890  	   TRIO_CONST char *format,
3891  	   void **args)
3892  {
3893    trio_custom_t data;
3894  
3895    assert(VALID(stream));
3896    assert(VALID(format));
3897  
3898    data.stream.out = stream;
3899    data.closure = closure;
3900    return TrioFormat(&data, 0, TrioOutStreamCustom, format, NULL, args);
3901  }
3902  
3903  /*************************************************************************
3904   * sprintf
3905   */
3906  
3907  /**
3908     Print to string.
3909  
3910     @param buffer Output string.
3911     @param format Formatting string.
3912     @param ... Arguments.
3913     @return Number of printed characters.
3914   */
3915  TRIO_PUBLIC int
3916  trio_sprintf
3917  TRIO_VARGS3((buffer, format, va_alist),
3918  	    char *buffer,
3919  	    TRIO_CONST char *format,
3920  	    TRIO_VA_DECL)
3921  {
3922    int status;
3923    va_list args;
3924  
3925    assert(VALID(buffer));
3926    assert(VALID(format));
3927  
3928    TRIO_VA_START(args, format);
3929    status = TrioFormat(&buffer, 0, TrioOutStreamString, format, TRIO_VA_LIST_ADDR(args), NULL);
3930    *buffer = NIL; /* Terminate with NIL character */
3931    TRIO_VA_END(args);
3932    return status;
3933  }
3934  
3935  /**
3936     Print to string.
3937  
3938     @param buffer Output string.
3939     @param format Formatting string.
3940     @param args Arguments.
3941     @return Number of printed characters.
3942   */
3943  TRIO_PUBLIC int
3944  trio_vsprintf
3945  TRIO_ARGS3((buffer, format, args),
3946  	   char *buffer,
3947  	   TRIO_CONST char *format,
3948  	   va_list args)
3949  {
3950    int status;
3951  
3952    assert(VALID(buffer));
3953    assert(VALID(format));
3954  
3955    status = TrioFormat(&buffer, 0, TrioOutStreamString, format, TRIO_VA_LIST_ADDR(args), NULL);
3956    *buffer = NIL;
3957    return status;
3958  }
3959  
3960  /**
3961     Print to string.
3962  
3963     @param buffer Output string.
3964     @param format Formatting string.
3965     @param args Arguments.
3966     @return Number of printed characters.
3967   */
3968  TRIO_PUBLIC int
3969  trio_sprintfv
3970  TRIO_ARGS3((buffer, format, args),
3971  	   char *buffer,
3972  	   TRIO_CONST char *format,
3973  	   trio_pointer_t *args)
3974  {
3975    int status;
3976  
3977    assert(VALID(buffer));
3978    assert(VALID(format));
3979  
3980    status = TrioFormat(&buffer, 0, TrioOutStreamString, format, NULL, args);
3981    *buffer = NIL;
3982    return status;
3983  }
3984  
3985  /*************************************************************************
3986   * snprintf
3987   */
3988  
3989  /**
3990     Print at most @p max characters to string.
3991  
3992     @param buffer Output string.
3993     @param max Maximum number of characters to print.
3994     @param format Formatting string.
3995     @param ... Arguments.
3996     @return Number of printed characters.
3997   */
3998  TRIO_PUBLIC int
3999  trio_snprintf
4000  TRIO_VARGS4((buffer, max, format, va_alist),
4001  	    char *buffer,
4002  	    size_t max,
4003  	    TRIO_CONST char *format,
4004  	    TRIO_VA_DECL)
4005  {
4006    int status;
4007    va_list args;
4008  
4009    assert(VALID(buffer));
4010    assert(VALID(format));
4011  
4012    TRIO_VA_START(args, format);
4013    status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
4014  		      TrioOutStreamStringMax, format, TRIO_VA_LIST_ADDR(args), NULL);
4015    if (max > 0)
4016      *buffer = NIL;
4017    TRIO_VA_END(args);
4018    return status;
4019  }
4020  
4021  /**
4022     Print at most @p max characters to string.
4023  
4024     @param buffer Output string.
4025     @param max Maximum number of characters to print.
4026     @param format Formatting string.
4027     @param args Arguments.
4028     @return Number of printed characters.
4029   */
4030  TRIO_PUBLIC int
4031  trio_vsnprintf
4032  TRIO_ARGS4((buffer, max, format, args),
4033  	   char *buffer,
4034  	   size_t max,
4035  	   TRIO_CONST char *format,
4036  	   va_list args)
4037  {
4038    int status;
4039  
4040    assert(VALID(buffer));
4041    assert(VALID(format));
4042  
4043    status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
4044  		      TrioOutStreamStringMax, format, TRIO_VA_LIST_ADDR(args), NULL);
4045    if (max > 0)
4046      *buffer = NIL;
4047    return status;
4048  }
4049  
4050  /**
4051     Print at most @p max characters to string.
4052  
4053     @param buffer Output string.
4054     @param max Maximum number of characters to print.
4055     @param format Formatting string.
4056     @param args Arguments.
4057     @return Number of printed characters.
4058   */
4059  TRIO_PUBLIC int
4060  trio_snprintfv
4061  TRIO_ARGS4((buffer, max, format, args),
4062  	   char *buffer,
4063  	   size_t max,
4064  	   TRIO_CONST char *format,
4065  	   trio_pointer_t *args)
4066  {
4067    int status;
4068  
4069    assert(VALID(buffer));
4070    assert(VALID(format));
4071  
4072    status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
4073  		      TrioOutStreamStringMax, format, NULL, args);
4074    if (max > 0)
4075      *buffer = NIL;
4076    return status;
4077  }
4078  
4079  /*************************************************************************
4080   * snprintfcat
4081   * Appends the new string to the buffer string overwriting the '\0'
4082   * character at the end of buffer.
4083   */
4084  TRIO_PUBLIC int
4085  trio_snprintfcat
4086  TRIO_VARGS4((buffer, max, format, va_alist),
4087  	    char *buffer,
4088  	    size_t max,
4089  	    TRIO_CONST char *format,
4090  	    TRIO_VA_DECL)
4091  {
4092    int status;
4093    va_list args;
4094    size_t buf_len;
4095  
4096    TRIO_VA_START(args, format);
4097  
4098    assert(VALID(buffer));
4099    assert(VALID(format));
4100  
4101    buf_len = trio_length(buffer);
4102    buffer = &buffer[buf_len];
4103  
4104    status = TrioFormat(&buffer, max - 1 - buf_len,
4105  		      TrioOutStreamStringMax, format, TRIO_VA_LIST_ADDR(args), NULL);
4106    TRIO_VA_END(args);
4107    *buffer = NIL;
4108    return status;
4109  }
4110  
4111  TRIO_PUBLIC int
4112  trio_vsnprintfcat
4113  TRIO_ARGS4((buffer, max, format, args),
4114  	   char *buffer,
4115  	   size_t max,
4116  	   TRIO_CONST char *format,
4117  	   va_list args)
4118  {
4119    int status;
4120    size_t buf_len;
4121  
4122    assert(VALID(buffer));
4123    assert(VALID(format));
4124  
4125    buf_len = trio_length(buffer);
4126    buffer = &buffer[buf_len];
4127    status = TrioFormat(&buffer, max - 1 - buf_len,
4128  		      TrioOutStreamStringMax, format, TRIO_VA_LIST_ADDR(args), NULL);
4129    *buffer = NIL;
4130    return status;
4131  }
4132  
4133  /*************************************************************************
4134   * trio_aprintf
4135   */
4136  
4137  /* Deprecated */
4138  TRIO_PUBLIC char *
4139  trio_aprintf
4140  TRIO_VARGS2((format, va_alist),
4141  	    TRIO_CONST char *format,
4142  	    TRIO_VA_DECL)
4143  {
4144    va_list args;
4145    trio_string_t *info;
4146    char *result = NULL;
4147  
4148    assert(VALID(format));
4149  
4150    info = trio_xstring_duplicate("");
4151    if (info)
4152      {
4153        TRIO_VA_START(args, format);
4154        (void)TrioFormat(info, 0, TrioOutStreamStringDynamic,
4155  		       format, TRIO_VA_LIST_ADDR(args), NULL);
4156        TRIO_VA_END(args);
4157  
4158        trio_string_terminate(info);
4159        result = trio_string_extract(info);
4160        trio_string_destroy(info);
4161      }
4162    return result;
4163  }
4164  
4165  /* Deprecated */
4166  TRIO_PUBLIC char *
4167  trio_vaprintf
4168  TRIO_ARGS2((format, args),
4169  	   TRIO_CONST char *format,
4170  	   va_list args)
4171  {
4172    trio_string_t *info;
4173    char *result = NULL;
4174  
4175    assert(VALID(format));
4176  
4177    info = trio_xstring_duplicate("");
4178    if (info)
4179      {
4180        (void)TrioFormat(info, 0, TrioOutStreamStringDynamic,
4181  		       format, TRIO_VA_LIST_ADDR(args), NULL);
4182        trio_string_terminate(info);
4183        result = trio_string_extract(info);
4184        trio_string_destroy(info);
4185      }
4186    return result;
4187  }
4188  
4189  TRIO_PUBLIC int
4190  trio_asprintf
4191  TRIO_VARGS3((result, format, va_alist),
4192  	    char **result,
4193  	    TRIO_CONST char *format,
4194  	    TRIO_VA_DECL)
4195  {
4196    va_list args;
4197    int status;
4198    trio_string_t *info;
4199  
4200    assert(VALID(format));
4201  
4202    *result = NULL;
4203  
4204    info = trio_xstring_duplicate("");
4205    if (info == NULL)
4206      {
4207        status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
4208      }
4209    else
4210      {
4211        TRIO_VA_START(args, format);
4212        status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
4213  			  format, TRIO_VA_LIST_ADDR(args), NULL);
4214        TRIO_VA_END(args);
4215        if (status >= 0)
4216  	{
4217  	  trio_string_terminate(info);
4218  	  *result = trio_string_extract(info);
4219  	}
4220        trio_string_destroy(info);
4221      }
4222    return status;
4223  }
4224  
4225  TRIO_PUBLIC int
4226  trio_vasprintf
4227  TRIO_ARGS3((result, format, args),
4228  	   char **result,
4229  	   TRIO_CONST char *format,
4230  	   va_list args)
4231  {
4232    int status;
4233    trio_string_t *info;
4234  
4235    assert(VALID(format));
4236  
4237    *result = NULL;
4238  
4239    info = trio_xstring_duplicate("");
4240    if (info == NULL)
4241      {
4242        status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
4243      }
4244    else
4245      {
4246        status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
4247  			  format, TRIO_VA_LIST_ADDR(args), NULL);
4248        if (status >= 0)
4249  	{
4250  	  trio_string_terminate(info);
4251  	  *result = trio_string_extract(info);
4252  	}
4253        trio_string_destroy(info);
4254      }
4255    return status;
4256  }
4257  
4258  /** @} End of Printf documentation module */
4259  
4260  /*************************************************************************
4261   *
4262   * CALLBACK
4263   *
4264   ************************************************************************/
4265  
4266  #if defined(TRIO_DOCUMENTATION)
4267  # include "doc/doc_register.h"
4268  #endif
4269  /**
4270     @addtogroup UserDefined
4271     @{
4272  */
4273  
4274  #if TRIO_EXTENSION
4275  
4276  /*************************************************************************
4277   * trio_register
4278   */
4279  
4280  /**
4281     Register new user-defined specifier.
4282  
4283     @param callback
4284     @param name
4285     @return Handle.
4286   */
4287  TRIO_PUBLIC trio_pointer_t
4288  trio_register
4289  TRIO_ARGS2((callback, name),
4290  	   trio_callback_t callback,
4291  	   TRIO_CONST char *name)
4292  {
4293    trio_userdef_t *def;
4294    trio_userdef_t *prev = NULL;
4295  
4296    if (callback == NULL)
4297      return NULL;
4298  
4299    if (name)
4300      {
4301        /* Handle built-in namespaces */
4302        if (name[0] == ':')
4303  	{
4304  	  if (trio_equal(name, ":enter"))
4305  	    {
4306  	      internalEnterCriticalRegion = callback;
4307  	    }
4308  	  else if (trio_equal(name, ":leave"))
4309  	    {
4310  	      internalLeaveCriticalRegion = callback;
4311  	    }
4312  	  return NULL;
4313  	}
4314  
4315        /* Bail out if namespace is too long */
4316        if (trio_length(name) >= MAX_USER_NAME)
4317  	return NULL;
4318  
4319        /* Bail out if namespace already is registered */
4320        def = TrioFindNamespace(name, &prev);
4321        if (def)
4322  	return NULL;
4323      }
4324  
4325    def = (trio_userdef_t *)TRIO_MALLOC(sizeof(trio_userdef_t));
4326    if (def)
4327      {
4328        if (internalEnterCriticalRegion)
4329  	(void)internalEnterCriticalRegion(NULL);
4330  
4331        if (name)
4332  	{
4333  	  /* Link into internal list */
4334  	  if (prev == NULL)
4335  	    internalUserDef = def;
4336  	  else
4337  	    prev->next = def;
4338  	}
4339        /* Initialize */
4340        def->callback = callback;
4341        def->name = (name == NULL)
4342  	? NULL
4343  	: trio_duplicate(name);
4344        def->next = NULL;
4345  
4346        if (internalLeaveCriticalRegion)
4347  	(void)internalLeaveCriticalRegion(NULL);
4348      }
4349    return (trio_pointer_t)def;
4350  }
4351  
4352  /**
4353     Unregister an existing user-defined specifier.
4354  
4355     @param handle
4356   */
4357  void
4358  trio_unregister
4359  TRIO_ARGS1((handle),
4360  	   trio_pointer_t handle)
4361  {
4362    trio_userdef_t *self = (trio_userdef_t *)handle;
4363    trio_userdef_t *def;
4364    trio_userdef_t *prev = NULL;
4365  
4366    assert(VALID(self));
4367  
4368    if (self->name)
4369      {
4370        def = TrioFindNamespace(self->name, &prev);
4371        if (def)
4372  	{
4373  	  if (internalEnterCriticalRegion)
4374  	    (void)internalEnterCriticalRegion(NULL);
4375  
4376  	  if (prev == NULL)
4377  	    internalUserDef = NULL;
4378  	  else
4379  	    prev->next = def->next;
4380  
4381  	  if (internalLeaveCriticalRegion)
4382  	    (void)internalLeaveCriticalRegion(NULL);
4383  	}
4384        trio_destroy(self->name);
4385      }
4386    TRIO_FREE(self);
4387  }
4388  
4389  /*************************************************************************
4390   * trio_get_format [public]
4391   */
4392  TRIO_CONST char *
4393  trio_get_format
4394  TRIO_ARGS1((ref),
4395  	   trio_pointer_t ref)
4396  {
4397  #if defined(FORMAT_USER_DEFINED)
4398    assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED);
4399  #endif
4400  
4401    return (((trio_reference_t *)ref)->parameter->user_data);
4402  }
4403  
4404  /*************************************************************************
4405   * trio_get_argument [public]
4406   */
4407  trio_pointer_t
4408  trio_get_argument
4409  TRIO_ARGS1((ref),
4410  	   trio_pointer_t ref)
4411  {
4412  #if defined(FORMAT_USER_DEFINED)
4413    assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED);
4414  #endif
4415  
4416    return ((trio_reference_t *)ref)->parameter->data.pointer;
4417  }
4418  
4419  /*************************************************************************
4420   * trio_get_width / trio_set_width [public]
4421   */
4422  int
4423  trio_get_width
4424  TRIO_ARGS1((ref),
4425  	   trio_pointer_t ref)
4426  {
4427    return ((trio_reference_t *)ref)->parameter->width;
4428  }
4429  
4430  void
4431  trio_set_width
4432  TRIO_ARGS2((ref, width),
4433  	   trio_pointer_t ref,
4434  	   int width)
4435  {
4436    ((trio_reference_t *)ref)->parameter->width = width;
4437  }
4438  
4439  /*************************************************************************
4440   * trio_get_precision / trio_set_precision [public]
4441   */
4442  int
4443  trio_get_precision
4444  TRIO_ARGS1((ref),
4445  	   trio_pointer_t ref)
4446  {
4447    return (((trio_reference_t *)ref)->parameter->precision);
4448  }
4449  
4450  void
4451  trio_set_precision
4452  TRIO_ARGS2((ref, precision),
4453  	   trio_pointer_t ref,
4454  	   int precision)
4455  {
4456    ((trio_reference_t *)ref)->parameter->precision = precision;
4457  }
4458  
4459  /*************************************************************************
4460   * trio_get_base / trio_set_base [public]
4461   */
4462  int
4463  trio_get_base
4464  TRIO_ARGS1((ref),
4465  	   trio_pointer_t ref)
4466  {
4467    return (((trio_reference_t *)ref)->parameter->base);
4468  }
4469  
4470  void
4471  trio_set_base
4472  TRIO_ARGS2((ref, base),
4473  	   trio_pointer_t ref,
4474  	   int base)
4475  {
4476    ((trio_reference_t *)ref)->parameter->base = base;
4477  }
4478  
4479  /*************************************************************************
4480   * trio_get_long / trio_set_long [public]
4481   */
4482  int
4483  trio_get_long
4484  TRIO_ARGS1((ref),
4485  	   trio_pointer_t ref)
4486  {
4487    return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONG)
4488      ? TRUE
4489      : FALSE;
4490  }
4491  
4492  void
4493  trio_set_long
4494  TRIO_ARGS2((ref, is_long),
4495  	   trio_pointer_t ref,
4496  	   int is_long)
4497  {
4498    if (is_long)
4499      ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONG;
4500    else
4501      ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONG;
4502  }
4503  
4504  /*************************************************************************
4505   * trio_get_longlong / trio_set_longlong [public]
4506   */
4507  int
4508  trio_get_longlong
4509  TRIO_ARGS1((ref),
4510  	   trio_pointer_t ref)
4511  {
4512    return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUAD)
4513      ? TRUE
4514      : FALSE;
4515  }
4516  
4517  void
4518  trio_set_longlong
4519  TRIO_ARGS2((ref, is_longlong),
4520  	   trio_pointer_t ref,
4521  	   int is_longlong)
4522  {
4523    if (is_longlong)
4524      ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUAD;
4525    else
4526      ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUAD;
4527  }
4528  
4529  /*************************************************************************
4530   * trio_get_longdouble / trio_set_longdouble [public]
4531   */
4532  int
4533  trio_get_longdouble
4534  TRIO_ARGS1((ref),
4535  	   trio_pointer_t ref)
4536  {
4537    return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONGDOUBLE)
4538      ? TRUE
4539      : FALSE;
4540  }
4541  
4542  void
4543  trio_set_longdouble
4544  TRIO_ARGS2((ref, is_longdouble),
4545  	   trio_pointer_t ref,
4546  	   int is_longdouble)
4547  {
4548    if (is_longdouble)
4549      ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONGDOUBLE;
4550    else
4551      ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONGDOUBLE;
4552  }
4553  
4554  /*************************************************************************
4555   * trio_get_short / trio_set_short [public]
4556   */
4557  int
4558  trio_get_short
4559  TRIO_ARGS1((ref),
4560  	   trio_pointer_t ref)
4561  {
4562    return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORT)
4563      ? TRUE
4564      : FALSE;
4565  }
4566  
4567  void
4568  trio_set_short
4569  TRIO_ARGS2((ref, is_short),
4570  	   trio_pointer_t ref,
4571  	   int is_short)
4572  {
4573    if (is_short)
4574      ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORT;
4575    else
4576      ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORT;
4577  }
4578  
4579  /*************************************************************************
4580   * trio_get_shortshort / trio_set_shortshort [public]
4581   */
4582  int
4583  trio_get_shortshort
4584  TRIO_ARGS1((ref),
4585  	   trio_pointer_t ref)
4586  {
4587    return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORTSHORT)
4588      ? TRUE
4589      : FALSE;
4590  }
4591  
4592  void
4593  trio_set_shortshort
4594  TRIO_ARGS2((ref, is_shortshort),
4595  	   trio_pointer_t ref,
4596  	   int is_shortshort)
4597  {
4598    if (is_shortshort)
4599      ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORTSHORT;
4600    else
4601      ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORTSHORT;
4602  }
4603  
4604  /*************************************************************************
4605   * trio_get_alternative / trio_set_alternative [public]
4606   */
4607  int
4608  trio_get_alternative
4609  TRIO_ARGS1((ref),
4610  	   trio_pointer_t ref)
4611  {
4612    return (((trio_reference_t *)ref)->parameter->flags & FLAGS_ALTERNATIVE)
4613      ? TRUE
4614      : FALSE;
4615  }
4616  
4617  void
4618  trio_set_alternative
4619  TRIO_ARGS2((ref, is_alternative),
4620  	   trio_pointer_t ref,
4621  	   int is_alternative)
4622  {
4623    if (is_alternative)
4624      ((trio_reference_t *)ref)->parameter->flags |= FLAGS_ALTERNATIVE;
4625    else
4626      ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_ALTERNATIVE;
4627  }
4628  
4629  /*************************************************************************
4630   * trio_get_alignment / trio_set_alignment [public]
4631   */
4632  int
4633  trio_get_alignment
4634  TRIO_ARGS1((ref),
4635  	   trio_pointer_t ref)
4636  {
4637    return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LEFTADJUST)
4638      ? TRUE
4639      : FALSE;
4640  }
4641  
4642  void
4643  trio_set_alignment
4644  TRIO_ARGS2((ref, is_leftaligned),
4645  	   trio_pointer_t ref,
4646  	   int is_leftaligned)
4647  {
4648    if (is_leftaligned)
4649      ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LEFTADJUST;
4650    else
4651      ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LEFTADJUST;
4652  }
4653  
4654  /*************************************************************************
4655   * trio_get_spacing /trio_set_spacing [public]
4656   */
4657  int
4658  trio_get_spacing
4659  TRIO_ARGS1((ref),
4660  	   trio_pointer_t ref)
4661  {
4662    return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SPACE)
4663      ? TRUE
4664      : FALSE;
4665  }
4666  
4667  void
4668  trio_set_spacing
4669  TRIO_ARGS2((ref, is_space),
4670  	   trio_pointer_t ref,
4671  	   int is_space)
4672  {
4673    if (is_space)
4674      ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SPACE;
4675    else
4676      ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SPACE;
4677  }
4678  
4679  /*************************************************************************
4680   * trio_get_sign / trio_set_sign [public]
4681   */
4682  int
4683  trio_get_sign
4684  TRIO_ARGS1((ref),
4685  	   trio_pointer_t ref)
4686  {
4687    return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHOWSIGN)
4688      ? TRUE
4689      : FALSE;
4690  }
4691  
4692  void
4693  trio_set_sign
4694  TRIO_ARGS2((ref, is_sign),
4695  	   trio_pointer_t ref,
4696  	   int is_sign)
4697  {
4698    if (is_sign)
4699      ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHOWSIGN;
4700    else
4701      ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHOWSIGN;
4702  }
4703  
4704  /*************************************************************************
4705   * trio_get_padding / trio_set_padding [public]
4706   */
4707  int
4708  trio_get_padding
4709  TRIO_ARGS1((ref),
4710  	   trio_pointer_t ref)
4711  {
4712    return (((trio_reference_t *)ref)->parameter->flags & FLAGS_NILPADDING)
4713      ? TRUE
4714      : FALSE;
4715  }
4716  
4717  void
4718  trio_set_padding
4719  TRIO_ARGS2((ref, is_padding),
4720  	   trio_pointer_t ref,
4721  	   int is_padding)
4722  {
4723    if (is_padding)
4724      ((trio_reference_t *)ref)->parameter->flags |= FLAGS_NILPADDING;
4725    else
4726      ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_NILPADDING;
4727  }
4728  
4729  /*************************************************************************
4730   * trio_get_quote / trio_set_quote [public]
4731   */
4732  int
4733  trio_get_quote
4734  TRIO_ARGS1((ref),
4735  	   trio_pointer_t ref)
4736  {
4737    return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUOTE)
4738      ? TRUE
4739      : FALSE;
4740  }
4741  
4742  void
4743  trio_set_quote
4744  TRIO_ARGS2((ref, is_quote),
4745  	   trio_pointer_t ref,
4746  	   int is_quote)
4747  {
4748    if (is_quote)
4749      ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUOTE;
4750    else
4751      ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUOTE;
4752  }
4753  
4754  /*************************************************************************
4755   * trio_get_upper / trio_set_upper [public]
4756   */
4757  int
4758  trio_get_upper
4759  TRIO_ARGS1((ref),
4760  	   trio_pointer_t ref)
4761  {
4762    return (((trio_reference_t *)ref)->parameter->flags & FLAGS_UPPER)
4763      ? TRUE
4764      : FALSE;
4765  }
4766  
4767  void
4768  trio_set_upper
4769  TRIO_ARGS2((ref, is_upper),
4770  	   trio_pointer_t ref,
4771  	   int is_upper)
4772  {
4773    if (is_upper)
4774      ((trio_reference_t *)ref)->parameter->flags |= FLAGS_UPPER;
4775    else
4776      ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_UPPER;
4777  }
4778  
4779  /*************************************************************************
4780   * trio_get_largest / trio_set_largest [public]
4781   */
4782  #if TRIO_C99
4783  int
4784  trio_get_largest
4785  TRIO_ARGS1((ref),
4786  	   trio_pointer_t ref)
4787  {
4788    return (((trio_reference_t *)ref)->parameter->flags & FLAGS_INTMAX_T)
4789      ? TRUE
4790      : FALSE;
4791  }
4792  
4793  void
4794  trio_set_largest
4795  TRIO_ARGS2((ref, is_largest),
4796  	   trio_pointer_t ref,
4797  	   int is_largest)
4798  {
4799    if (is_largest)
4800      ((trio_reference_t *)ref)->parameter->flags |= FLAGS_INTMAX_T;
4801    else
4802      ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_INTMAX_T;
4803  }
4804  #endif
4805  
4806  /*************************************************************************
4807   * trio_get_ptrdiff / trio_set_ptrdiff [public]
4808   */
4809  int
4810  trio_get_ptrdiff
4811  TRIO_ARGS1((ref),
4812  	   trio_pointer_t ref)
4813  {
4814    return (((trio_reference_t *)ref)->parameter->flags & FLAGS_PTRDIFF_T)
4815      ? TRUE
4816      : FALSE;
4817  }
4818  
4819  void
4820  trio_set_ptrdiff
4821  TRIO_ARGS2((ref, is_ptrdiff),
4822  	   trio_pointer_t ref,
4823  	   int is_ptrdiff)
4824  {
4825    if (is_ptrdiff)
4826      ((trio_reference_t *)ref)->parameter->flags |= FLAGS_PTRDIFF_T;
4827    else
4828      ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_PTRDIFF_T;
4829  }
4830  
4831  /*************************************************************************
4832   * trio_get_size / trio_set_size [public]
4833   */
4834  #if TRIO_C99
4835  int
4836  trio_get_size
4837  TRIO_ARGS1((ref),
4838  	   trio_pointer_t ref)
4839  {
4840    return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SIZE_T)
4841      ? TRUE
4842      : FALSE;
4843  }
4844  
4845  void
4846  trio_set_size
4847  TRIO_ARGS2((ref, is_size),
4848  	   trio_pointer_t ref,
4849  	   int is_size)
4850  {
4851    if (is_size)
4852      ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SIZE_T;
4853    else
4854      ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SIZE_T;
4855  }
4856  #endif
4857  
4858  /*************************************************************************
4859   * trio_print_int [public]
4860   */
4861  void
4862  trio_print_int
4863  TRIO_ARGS2((ref, number),
4864  	   trio_pointer_t ref,
4865  	   int number)
4866  {
4867    trio_reference_t *self = (trio_reference_t *)ref;
4868  
4869    TrioWriteNumber(self->data,
4870  		  (trio_uintmax_t)number,
4871  		  self->parameter->flags,
4872  		  self->parameter->width,
4873  		  self->parameter->precision,
4874  		  self->parameter->base);
4875  }
4876  
4877  /*************************************************************************
4878   * trio_print_uint [public]
4879   */
4880  void
4881  trio_print_uint
4882  TRIO_ARGS2((ref, number),
4883  	   trio_pointer_t ref,
4884  	   unsigned int number)
4885  {
4886    trio_reference_t *self = (trio_reference_t *)ref;
4887  
4888    TrioWriteNumber(self->data,
4889  		  (trio_uintmax_t)number,
4890  		  self->parameter->flags | FLAGS_UNSIGNED,
4891  		  self->parameter->width,
4892  		  self->parameter->precision,
4893  		  self->parameter->base);
4894  }
4895  
4896  /*************************************************************************
4897   * trio_print_double [public]
4898   */
4899  void
4900  trio_print_double
4901  TRIO_ARGS2((ref, number),
4902  	   trio_pointer_t ref,
4903  	   double number)
4904  {
4905    trio_reference_t *self = (trio_reference_t *)ref;
4906  
4907    TrioWriteDouble(self->data,
4908  		  number,
4909  		  self->parameter->flags,
4910  		  self->parameter->width,
4911  		  self->parameter->precision,
4912  		  self->parameter->base);
4913  }
4914  
4915  /*************************************************************************
4916   * trio_print_string [public]
4917   */
4918  void
4919  trio_print_string
4920  TRIO_ARGS2((ref, string),
4921  	   trio_pointer_t ref,
4922  	   char *string)
4923  {
4924    trio_reference_t *self = (trio_reference_t *)ref;
4925  
4926    TrioWriteString(self->data,
4927  		  string,
4928  		  self->parameter->flags,
4929  		  self->parameter->width,
4930  		  self->parameter->precision);
4931  }
4932  
4933  /*************************************************************************
4934   * trio_print_ref [public]
4935   */
4936  int
4937  trio_print_ref
4938  TRIO_VARGS3((ref, format, va_alist),
4939  	    trio_pointer_t ref,
4940  	    TRIO_CONST char *format,
4941  	    TRIO_VA_DECL)
4942  {
4943    int status;
4944    va_list arglist;
4945  
4946    assert(VALID(format));
4947  
4948    TRIO_VA_START(arglist, format);
4949    status = TrioFormatRef((trio_reference_t *)ref, format, TRIO_VA_LIST_ADDR(arglist), NULL);
4950    TRIO_VA_END(arglist);
4951    return status;
4952  }
4953  
4954  /*************************************************************************
4955   * trio_vprint_ref [public]
4956   */
4957  int
4958  trio_vprint_ref
4959  TRIO_ARGS3((ref, format, arglist),
4960  	   trio_pointer_t ref,
4961  	   TRIO_CONST char *format,
4962  	   va_list arglist)
4963  {
4964    assert(VALID(format));
4965  
4966    return TrioFormatRef((trio_reference_t *)ref, format, TRIO_VA_LIST_ADDR(arglist), NULL);
4967  }
4968  
4969  /*************************************************************************
4970   * trio_printv_ref [public]
4971   */
4972  int
4973  trio_printv_ref
4974  TRIO_ARGS3((ref, format, argarray),
4975  	   trio_pointer_t ref,
4976  	   TRIO_CONST char *format,
4977  	   trio_pointer_t *argarray)
4978  {
4979    assert(VALID(format));
4980  
4981    return TrioFormatRef((trio_reference_t *)ref, format, NULL, argarray);
4982  }
4983  
4984  #endif /* TRIO_EXTENSION */
4985  
4986  /*************************************************************************
4987   * trio_print_pointer [public]
4988   */
4989  void
4990  trio_print_pointer
4991  TRIO_ARGS2((ref, pointer),
4992  	   trio_pointer_t ref,
4993  	   trio_pointer_t pointer)
4994  {
4995    trio_reference_t *self = (trio_reference_t *)ref;
4996    trio_flags_t flags;
4997    trio_uintmax_t number;
4998  
4999    if (NULL == pointer)
5000      {
5001        TRIO_CONST char *string = internalNullString;
5002        while (*string)
5003  	self->data->OutStream(self->data, *string++);
5004      }
5005    else
5006      {
5007        /*
5008         * The subtraction of the null pointer is a workaround
5009         * to avoid a compiler warning. The performance overhead
5010         * is negligible (and likely to be removed by an
5011         * optimizing compiler). The (char *) casting is done
5012         * to please ANSI C++.
5013         */
5014        number = (trio_uintmax_t)((char *)pointer - (char *)0);
5015        /* Shrink to size of pointer */
5016        number &= (trio_uintmax_t)-1;
5017        flags = self->parameter->flags;
5018        flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE |
5019  	        FLAGS_NILPADDING);
5020        TrioWriteNumber(self->data,
5021  		      number,
5022  		      flags,
5023  		      POINTER_WIDTH,
5024  		      NO_PRECISION,
5025  		      BASE_HEX);
5026      }
5027  }
5028  
5029  /** @} End of UserDefined documentation module */
5030  
5031  /*************************************************************************
5032   *
5033   * LOCALES
5034   *
5035   ************************************************************************/
5036  
5037  /*************************************************************************
5038   * trio_locale_set_decimal_point
5039   *
5040   * Decimal point can only be one character. The input argument is a
5041   * string to enable multibyte characters. At most MB_LEN_MAX characters
5042   * will be used.
5043   */
5044  TRIO_PUBLIC void
5045  trio_locale_set_decimal_point
5046  TRIO_ARGS1((decimalPoint),
5047  	   char *decimalPoint)
5048  {
5049  #if defined(USE_LOCALE)
5050    if (NULL == internalLocaleValues)
5051      {
5052        TrioSetLocale();
5053      }
5054  #endif
5055    internalDecimalPointLength = trio_length(decimalPoint);
5056    if (internalDecimalPointLength == 1)
5057      {
5058        internalDecimalPoint = *decimalPoint;
5059      }
5060    else
5061      {
5062        internalDecimalPoint = NIL;
5063        trio_copy_max(internalDecimalPointString,
5064  		    sizeof(internalDecimalPointString),
5065  		    decimalPoint);
5066      }
5067  }
5068  
5069  /*************************************************************************
5070   * trio_locale_set_thousand_separator
5071   *
5072   * See trio_locale_set_decimal_point
5073   */
5074  TRIO_PUBLIC void
5075  trio_locale_set_thousand_separator
5076  TRIO_ARGS1((thousandSeparator),
5077  	   char *thousandSeparator)
5078  {
5079  #if defined(USE_LOCALE)
5080    if (NULL == internalLocaleValues)
5081      {
5082        TrioSetLocale();
5083      }
5084  #endif
5085    trio_copy_max(internalThousandSeparator,
5086  		sizeof(internalThousandSeparator),
5087  		thousandSeparator);
5088    internalThousandSeparatorLength = trio_length(internalThousandSeparator);
5089  }
5090  
5091  /*************************************************************************
5092   * trio_locale_set_grouping
5093   *
5094   * Array of bytes. Reversed order.
5095   *
5096   *  CHAR_MAX : No further grouping
5097   *  0        : Repeat last group for the remaining digits (not necessary
5098   *             as C strings are zero-terminated)
5099   *  n        : Set current group to n
5100   *
5101   * Same order as the grouping attribute in LC_NUMERIC.
5102   */
5103  TRIO_PUBLIC void
5104  trio_locale_set_grouping
5105  TRIO_ARGS1((grouping),
5106  	   char *grouping)
5107  {
5108  #if defined(USE_LOCALE)
5109    if (NULL == internalLocaleValues)
5110      {
5111        TrioSetLocale();
5112      }
5113  #endif
5114    trio_copy_max(internalGrouping,
5115  		sizeof(internalGrouping),
5116  		grouping);
5117  }
5118  
5119  
5120  /*************************************************************************
5121   *
5122   * SCANNING
5123   *
5124   ************************************************************************/
5125  
5126  /*************************************************************************
5127   * TrioSkipWhitespaces
5128   */
5129  TRIO_PRIVATE int
5130  TrioSkipWhitespaces
5131  TRIO_ARGS1((self),
5132  	   trio_class_t *self)
5133  {
5134    int ch;
5135  
5136    ch = self->current;
5137    while (isspace(ch))
5138      {
5139        self->InStream(self, &ch);
5140      }
5141    return ch;
5142  }
5143  
5144  /*************************************************************************
5145   * TrioGetCollation
5146   */
5147  #if TRIO_EXTENSION
5148  TRIO_PRIVATE void
5149  TrioGetCollation(TRIO_NOARGS)
5150  {
5151    int i;
5152    int j;
5153    int k;
5154    char first[2];
5155    char second[2];
5156  
5157    /* This is computationally expensive */
5158    first[1] = NIL;
5159    second[1] = NIL;
5160    for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5161      {
5162        k = 0;
5163        first[0] = (char)i;
5164        for (j = 0; j < MAX_CHARACTER_CLASS; j++)
5165  	{
5166  	  second[0] = (char)j;
5167  	  if (trio_equal_locale(first, second))
5168  	    internalCollationArray[i][k++] = (char)j;
5169  	}
5170        internalCollationArray[i][k] = NIL;
5171      }
5172  }
5173  #endif
5174  
5175  /*************************************************************************
5176   * TrioGetCharacterClass
5177   *
5178   * FIXME:
5179   *  multibyte
5180   */
5181  TRIO_PRIVATE int
5182  TrioGetCharacterClass
5183  TRIO_ARGS4((format, indexPointer, flagsPointer, characterclass),
5184  	   TRIO_CONST char *format,
5185  	   int *indexPointer,
5186  	   trio_flags_t *flagsPointer,
5187  	   int *characterclass)
5188  {
5189    int index = *indexPointer;
5190    int i;
5191    char ch;
5192    char range_begin;
5193    char range_end;
5194  
5195    *flagsPointer &= ~FLAGS_EXCLUDE;
5196  
5197    if (format[index] == QUALIFIER_CIRCUMFLEX)
5198      {
5199        *flagsPointer |= FLAGS_EXCLUDE;
5200        index++;
5201      }
5202    /*
5203     * If the ungroup character is at the beginning of the scanlist,
5204     * it will be part of the class, and a second ungroup character
5205     * must follow to end the group.
5206     */
5207    if (format[index] == SPECIFIER_UNGROUP)
5208      {
5209        characterclass[(int)SPECIFIER_UNGROUP]++;
5210        index++;
5211      }
5212    /*
5213     * Minus is used to specify ranges. To include minus in the class,
5214     * it must be at the beginning of the list
5215     */
5216    if (format[index] == QUALIFIER_MINUS)
5217      {
5218        characterclass[(int)QUALIFIER_MINUS]++;
5219        index++;
5220      }
5221    /* Collect characters */
5222    for (ch = format[index];
5223         (ch != SPECIFIER_UNGROUP) && (ch != NIL);
5224         ch = format[++index])
5225      {
5226        switch (ch)
5227  	{
5228  	case QUALIFIER_MINUS: /* Scanlist ranges */
5229  
5230  	  /*
5231  	   * Both C99 and UNIX98 describes ranges as implementation-
5232  	   * defined.
5233  	   *
5234  	   * We support the following behaviour (although this may
5235  	   * change as we become wiser)
5236  	   * - only increasing ranges, ie. [a-b] but not [b-a]
5237  	   * - transitive ranges, ie. [a-b-c] == [a-c]
5238  	   * - trailing minus, ie. [a-] is interpreted as an 'a'
5239  	   *   and a '-'
5240  	   * - duplicates (although we can easily convert these
5241  	   *   into errors)
5242  	   */
5243  	  range_begin = format[index - 1];
5244  	  range_end = format[++index];
5245  	  if (range_end == SPECIFIER_UNGROUP)
5246  	    {
5247  	      /* Trailing minus is included */
5248  	      characterclass[(int)ch]++;
5249  	      ch = range_end;
5250  	      break; /* for */
5251  	    }
5252  	  if (range_end == NIL)
5253  	    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5254  	  if (range_begin > range_end)
5255  	    return TRIO_ERROR_RETURN(TRIO_ERANGE, index);
5256  
5257  	  for (i = (int)range_begin; i <= (int)range_end; i++)
5258  	    characterclass[i]++;
5259  
5260  	  ch = range_end;
5261  	  break;
5262  
5263  #if TRIO_EXTENSION
5264  
5265  	case SPECIFIER_GROUP:
5266  
5267  	  switch (format[index + 1])
5268  	    {
5269  	    case QUALIFIER_DOT: /* Collating symbol */
5270  	      /*
5271  	       * FIXME: This will be easier to implement when multibyte
5272  	       * characters have been implemented. Until now, we ignore
5273  	       * this feature.
5274  	       */
5275  	      for (i = index + 2; ; i++)
5276  		{
5277  		  if (format[i] == NIL)
5278  		    /* Error in syntax */
5279  		    return -1;
5280  		  else if (format[i] == QUALIFIER_DOT)
5281  		    break; /* for */
5282  		}
5283  	      if (format[++i] != SPECIFIER_UNGROUP)
5284  		return -1;
5285  
5286  	      index = i;
5287  	      break;
5288  
5289  	    case QUALIFIER_EQUAL: /* Equivalence class expressions */
5290  	      {
5291  		unsigned int j;
5292  		unsigned int k;
5293  
5294  		if (internalCollationUnconverted)
5295  		  {
5296  		    /* Lazy evaluation of collation array */
5297  		    TrioGetCollation();
5298  		    internalCollationUnconverted = FALSE;
5299  		  }
5300  		for (i = index + 2; ; i++)
5301  		  {
5302  		    if (format[i] == NIL)
5303  		      /* Error in syntax */
5304  		      return -1;
5305  		    else if (format[i] == QUALIFIER_EQUAL)
5306  		      break; /* for */
5307  		    else
5308  		      {
5309  			/* Mark any equivalent character */
5310  			k = (unsigned int)format[i];
5311  			for (j = 0; internalCollationArray[k][j] != NIL; j++)
5312  			  characterclass[(int)internalCollationArray[k][j]]++;
5313  		      }
5314  		  }
5315  		if (format[++i] != SPECIFIER_UNGROUP)
5316  		  return -1;
5317  
5318  		index = i;
5319  	      }
5320  	      break;
5321  
5322  	    case QUALIFIER_COLON: /* Character class expressions */
5323  
5324  	      if (trio_equal_max(CLASS_ALNUM, sizeof(CLASS_ALNUM) - 1,
5325  				 &format[index]))
5326  		{
5327  		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5328  		    if (isalnum(i))
5329  		      characterclass[i]++;
5330  		  index += sizeof(CLASS_ALNUM) - 1;
5331  		}
5332  	      else if (trio_equal_max(CLASS_ALPHA, sizeof(CLASS_ALPHA) - 1,
5333  				      &format[index]))
5334  		{
5335  		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5336  		    if (isalpha(i))
5337  		      characterclass[i]++;
5338  		  index += sizeof(CLASS_ALPHA) - 1;
5339  		}
5340  	      else if (trio_equal_max(CLASS_CNTRL, sizeof(CLASS_CNTRL) - 1,
5341  				      &format[index]))
5342  		{
5343  		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5344  		    if (iscntrl(i))
5345  		      characterclass[i]++;
5346  		  index += sizeof(CLASS_CNTRL) - 1;
5347  		}
5348  	      else if (trio_equal_max(CLASS_DIGIT, sizeof(CLASS_DIGIT) - 1,
5349  				      &format[index]))
5350  		{
5351  		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5352  		    if (isdigit(i))
5353  		      characterclass[i]++;
5354  		  index += sizeof(CLASS_DIGIT) - 1;
5355  		}
5356  	      else if (trio_equal_max(CLASS_GRAPH, sizeof(CLASS_GRAPH) - 1,
5357  				      &format[index]))
5358  		{
5359  		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5360  		    if (isgraph(i))
5361  		      characterclass[i]++;
5362  		  index += sizeof(CLASS_GRAPH) - 1;
5363  		}
5364  	      else if (trio_equal_max(CLASS_LOWER, sizeof(CLASS_LOWER) - 1,
5365  				      &format[index]))
5366  		{
5367  		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5368  		    if (islower(i))
5369  		      characterclass[i]++;
5370  		  index += sizeof(CLASS_LOWER) - 1;
5371  		}
5372  	      else if (trio_equal_max(CLASS_PRINT, sizeof(CLASS_PRINT) - 1,
5373  				      &format[index]))
5374  		{
5375  		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5376  		    if (isprint(i))
5377  		      characterclass[i]++;
5378  		  index += sizeof(CLASS_PRINT) - 1;
5379  		}
5380  	      else if (trio_equal_max(CLASS_PUNCT, sizeof(CLASS_PUNCT) - 1,
5381  				      &format[index]))
5382  		{
5383  		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5384  		    if (ispunct(i))
5385  		      characterclass[i]++;
5386  		  index += sizeof(CLASS_PUNCT) - 1;
5387  		}
5388  	      else if (trio_equal_max(CLASS_SPACE, sizeof(CLASS_SPACE) - 1,
5389  				      &format[index]))
5390  		{
5391  		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5392  		    if (isspace(i))
5393  		      characterclass[i]++;
5394  		  index += sizeof(CLASS_SPACE) - 1;
5395  		}
5396  	      else if (trio_equal_max(CLASS_UPPER, sizeof(CLASS_UPPER) - 1,
5397  				      &format[index]))
5398  		{
5399  		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5400  		    if (isupper(i))
5401  		      characterclass[i]++;
5402  		  index += sizeof(CLASS_UPPER) - 1;
5403  		}
5404  	      else if (trio_equal_max(CLASS_XDIGIT, sizeof(CLASS_XDIGIT) - 1,
5405  				      &format[index]))
5406  		{
5407  		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5408  		    if (isxdigit(i))
5409  		      characterclass[i]++;
5410  		  index += sizeof(CLASS_XDIGIT) - 1;
5411  		}
5412  	      else
5413  		{
5414  		  characterclass[(int)ch]++;
5415  		}
5416  	      break;
5417  
5418  	    default:
5419  	      characterclass[(int)ch]++;
5420  	      break;
5421  	    }
5422  	  break;
5423  
5424  #endif /* TRIO_EXTENSION */
5425  
5426  	default:
5427  	  characterclass[(int)ch]++;
5428  	  break;
5429  	}
5430      }
5431    return 0;
5432  }
5433  
5434  /*************************************************************************
5435   * TrioReadNumber
5436   *
5437   * We implement our own number conversion in preference of strtol and
5438   * strtoul, because we must handle 'long long' and thousand separators.
5439   */
5440  TRIO_PRIVATE BOOLEAN_T
5441  TrioReadNumber
5442  TRIO_ARGS5((self, target, flags, width, base),
5443  	   trio_class_t *self,
5444  	   trio_uintmax_t *target,
5445  	   trio_flags_t flags,
5446  	   int width,
5447  	   int base)
5448  {
5449    trio_uintmax_t number = 0;
5450    int digit;
5451    int count;
5452    BOOLEAN_T isNegative = FALSE;
5453    BOOLEAN_T gotNumber = FALSE;
5454    int j;
5455  
5456    assert(VALID(self));
5457    assert(VALID(self->InStream));
5458    assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
5459  
5460    if (internalDigitsUnconverted)
5461      {
5462        /* Lazy evaluation of digits array */
5463        memset(internalDigitArray, -1, sizeof(internalDigitArray));
5464        for (j = 0; j < (int)sizeof(internalDigitsLower) - 1; j++)
5465  	{
5466  	  internalDigitArray[(int)internalDigitsLower[j]] = j;
5467  	  internalDigitArray[(int)internalDigitsUpper[j]] = j;
5468  	}
5469        internalDigitsUnconverted = FALSE;
5470      }
5471  
5472    TrioSkipWhitespaces(self);
5473  
5474    if (!(flags & FLAGS_UNSIGNED))
5475      {
5476        /* Leading sign */
5477        if (self->current == '+')
5478  	{
5479  	  self->InStream(self, NULL);
5480  	}
5481        else if (self->current == '-')
5482  	{
5483  	  self->InStream(self, NULL);
5484  	  isNegative = TRUE;
5485  	}
5486      }
5487  
5488    count = self->processed;
5489  
5490    if (flags & FLAGS_ALTERNATIVE)
5491      {
5492        switch (base)
5493  	{
5494  	case NO_BASE:
5495  	case BASE_OCTAL:
5496  	case BASE_HEX:
5497  	case BASE_BINARY:
5498  	  if (self->current == '0')
5499  	    {
5500  	      self->InStream(self, NULL);
5501  	      if (self->current)
5502  		{
5503  		  if ((base == BASE_HEX) &&
5504  		      (trio_to_upper(self->current) == 'X'))
5505  		    {
5506  		      self->InStream(self, NULL);
5507  		    }
5508  		  else if ((base == BASE_BINARY) &&
5509  			   (trio_to_upper(self->current) == 'B'))
5510  		    {
5511  		      self->InStream(self, NULL);
5512  		    }
5513  		}
5514  	    }
5515  	  else
5516  	    return FALSE;
5517  	  break;
5518  	default:
5519  	  break;
5520  	}
5521      }
5522  
5523    while (((width == NO_WIDTH) || (self->processed - count < width)) &&
5524  	 (! ((self->current == EOF) || isspace(self->current))))
5525      {
5526        if (isascii(self->current))
5527  	{
5528  	  digit = internalDigitArray[self->current];
5529  	  /* Abort if digit is not allowed in the specified base */
5530  	  if ((digit == -1) || (digit >= base))
5531  	    break;
5532  	}
5533        else if (flags & FLAGS_QUOTE)
5534  	{
5535  	  /* Compare with thousands separator */
5536  	  for (j = 0; internalThousandSeparator[j] && self->current; j++)
5537  	    {
5538  	      if (internalThousandSeparator[j] != self->current)
5539  		break;
5540  
5541  	      self->InStream(self, NULL);
5542  	    }
5543  	  if (internalThousandSeparator[j])
5544  	    break; /* Mismatch */
5545  	  else
5546  	    continue; /* Match */
5547  	}
5548        else
5549  	break;
5550  
5551        number *= base;
5552        number += digit;
5553        gotNumber = TRUE; /* we need at least one digit */
5554  
5555        self->InStream(self, NULL);
5556      }
5557  
5558    /* Was anything read at all? */
5559    if (!gotNumber)
5560      return FALSE;
5561  
5562    if (target)
5563      *target = (isNegative) ? -((trio_intmax_t)number) : number;
5564    return TRUE;
5565  }
5566  
5567  /*************************************************************************
5568   * TrioReadChar
5569   */
5570  TRIO_PRIVATE int
5571  TrioReadChar
5572  TRIO_ARGS4((self, target, flags, width),
5573  	   trio_class_t *self,
5574  	   char *target,
5575  	   trio_flags_t flags,
5576  	   int width)
5577  {
5578    int i;
5579    char ch;
5580    trio_uintmax_t number;
5581  
5582    assert(VALID(self));
5583    assert(VALID(self->InStream));
5584  
5585    for (i = 0;
5586         (self->current != EOF) && (i < width);
5587         i++)
5588      {
5589        ch = (char)self->current;
5590        self->InStream(self, NULL);
5591        if ((flags & FLAGS_ALTERNATIVE) && (ch == CHAR_BACKSLASH))
5592  	{
5593  	  switch (self->current)
5594  	    {
5595  	    case '\\': ch = '\\'; break;
5596  	    case 'a': ch = '\007'; break;
5597  	    case 'b': ch = '\b'; break;
5598  	    case 'f': ch = '\f'; break;
5599  	    case 'n': ch = '\n'; break;
5600  	    case 'r': ch = '\r'; break;
5601  	    case 't': ch = '\t'; break;
5602  	    case 'v': ch = '\v'; break;
5603  	    default:
5604  	      if (isdigit(self->current))
5605  		{
5606  		  /* Read octal number */
5607  		  if (!TrioReadNumber(self, &number, 0, 3, BASE_OCTAL))
5608  		    return 0;
5609  		  ch = (char)number;
5610  		}
5611  	      else if (trio_to_upper(self->current) == 'X')
5612  		{
5613  		  /* Read hexadecimal number */
5614  		  self->InStream(self, NULL);
5615  		  if (!TrioReadNumber(self, &number, 0, 2, BASE_HEX))
5616  		    return 0;
5617  		  ch = (char)number;
5618  		}
5619  	      else
5620  		{
5621  		  ch = (char)self->current;
5622  		}
5623  	      break;
5624  	    }
5625  	}
5626  
5627        if (target)
5628  	target[i] = ch;
5629      }
5630    return i + 1;
5631  }
5632  
5633  /*************************************************************************
5634   * TrioReadString
5635   */
5636  TRIO_PRIVATE BOOLEAN_T
5637  TrioReadString
5638  TRIO_ARGS4((self, target, flags, width),
5639  	   trio_class_t *self,
5640  	   char *target,
5641  	   trio_flags_t flags,
5642  	   int width)
5643  {
5644    int i;
5645  
5646    assert(VALID(self));
5647    assert(VALID(self->InStream));
5648  
5649    TrioSkipWhitespaces(self);
5650  
5651    /*
5652     * Continue until end of string is reached, a whitespace is encountered,
5653     * or width is exceeded
5654     */
5655    for (i = 0;
5656         ((width == NO_WIDTH) || (i < width)) &&
5657         (! ((self->current == EOF) || isspace(self->current)));
5658         i++)
5659      {
5660        if (TrioReadChar(self, (target ? &target[i] : 0), flags, 1) == 0)
5661  	break; /* for */
5662      }
5663    if (target)
5664      target[i] = NIL;
5665    return TRUE;
5666  }
5667  
5668  /*************************************************************************
5669   * TrioReadWideChar
5670   */
5671  #if TRIO_WIDECHAR
5672  TRIO_PRIVATE int
5673  TrioReadWideChar
5674  TRIO_ARGS4((self, target, flags, width),
5675  	   trio_class_t *self,
5676  	   trio_wchar_t *target,
5677  	   trio_flags_t flags,
5678  	   int width)
5679  {
5680    int i;
5681    int j;
5682    int size;
5683    int amount = 0;
5684    trio_wchar_t wch;
5685    char buffer[MB_LEN_MAX + 1];
5686  
5687    assert(VALID(self));
5688    assert(VALID(self->InStream));
5689  
5690    for (i = 0;
5691         (self->current != EOF) && (i < width);
5692         i++)
5693      {
5694        if (isascii(self->current))
5695  	{
5696  	  if (TrioReadChar(self, buffer, flags, 1) == 0)
5697  	    return 0;
5698  	  buffer[1] = NIL;
5699  	}
5700        else
5701  	{
5702  	  /*
5703  	   * Collect a multibyte character, by enlarging buffer until
5704  	   * it contains a fully legal multibyte character, or the
5705  	   * buffer is full.
5706  	   */
5707  	  j = 0;
5708  	  do
5709  	    {
5710  	      buffer[j++] = (char)self->current;
5711  	      buffer[j] = NIL;
5712  	      self->InStream(self, NULL);
5713  	    }
5714  	  while ((j < (int)sizeof(buffer)) && (mblen(buffer, (size_t)j) != j));
5715  	}
5716        if (target)
5717  	{
5718  	  size = mbtowc(&wch, buffer, sizeof(buffer));
5719  	  if (size > 0)
5720  	    target[i] = wch;
5721  	}
5722        amount += size;
5723        self->InStream(self, NULL);
5724      }
5725    return amount;
5726  }
5727  #endif /* TRIO_WIDECHAR */
5728  
5729  /*************************************************************************
5730   * TrioReadWideString
5731   */
5732  #if TRIO_WIDECHAR
5733  TRIO_PRIVATE BOOLEAN_T
5734  TrioReadWideString
5735  TRIO_ARGS4((self, target, flags, width),
5736  	   trio_class_t *self,
5737  	   trio_wchar_t *target,
5738  	   trio_flags_t flags,
5739  	   int width)
5740  {
5741    int i;
5742    int size;
5743  
5744    assert(VALID(self));
5745    assert(VALID(self->InStream));
5746  
5747    TrioSkipWhitespaces(self);
5748  
5749  #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
5750    (void)mblen(NULL, 0);
5751  #endif
5752  
5753    /*
5754     * Continue until end of string is reached, a whitespace is encountered,
5755     * or width is exceeded
5756     */
5757    for (i = 0;
5758         ((width == NO_WIDTH) || (i < width)) &&
5759         (! ((self->current == EOF) || isspace(self->current)));
5760         )
5761      {
5762        size = TrioReadWideChar(self, &target[i], flags, 1);
5763        if (size == 0)
5764  	break; /* for */
5765  
5766        i += size;
5767      }
5768    if (target)
5769      target[i] = WCONST('\0');
5770    return TRUE;
5771  }
5772  #endif /* TRIO_WIDECHAR */
5773  
5774  /*************************************************************************
5775   * TrioReadGroup
5776   *
5777   * FIXME: characterclass does not work with multibyte characters
5778   */
5779  TRIO_PRIVATE BOOLEAN_T
5780  TrioReadGroup
5781  TRIO_ARGS5((self, target, characterclass, flags, width),
5782  	   trio_class_t *self,
5783  	   char *target,
5784  	   int *characterclass,
5785  	   trio_flags_t flags,
5786  	   int width)
5787  {
5788    int ch;
5789    int i;
5790  
5791    assert(VALID(self));
5792    assert(VALID(self->InStream));
5793  
5794    ch = self->current;
5795    for (i = 0;
5796         ((width == NO_WIDTH) || (i < width)) &&
5797         (! ((ch == EOF) ||
5798  	   (((flags & FLAGS_EXCLUDE) != 0) ^ (characterclass[ch] == 0))));
5799         i++)
5800      {
5801        if (target)
5802  	target[i] = (char)ch;
5803        self->InStream(self, &ch);
5804      }
5805  
5806    if (target)
5807      target[i] = NIL;
5808    return TRUE;
5809  }
5810  
5811  /*************************************************************************
5812   * TrioReadDouble
5813   *
5814   * FIXME:
5815   *  add long double
5816   *  handle base
5817   */
5818  TRIO_PRIVATE BOOLEAN_T
5819  TrioReadDouble
5820  TRIO_ARGS4((self, target, flags, width),
5821  	   trio_class_t *self,
5822  	   trio_pointer_t target,
5823  	   trio_flags_t flags,
5824  	   int width)
5825  {
5826    int ch;
5827    char doubleString[512];
5828    int index = 0;
5829    int start;
5830    int j;
5831    BOOLEAN_T isHex = FALSE;
5832  
5833    doubleString[0] = 0;
5834  
5835    if ((width == NO_WIDTH) || (width > (int)sizeof(doubleString) - 1))
5836      width = sizeof(doubleString) - 1;
5837  
5838    TrioSkipWhitespaces(self);
5839  
5840    /*
5841     * Read entire double number from stream. trio_to_double requires
5842     * a string as input, but InStream can be anything, so we have to
5843     * collect all characters.
5844     */
5845    ch = self->current;
5846    if ((ch == '+') || (ch == '-'))
5847      {
5848        doubleString[index++] = (char)ch;
5849        self->InStream(self, &ch);
5850        width--;
5851      }
5852  
5853    start = index;
5854    switch (ch)
5855      {
5856      case 'n':
5857      case 'N':
5858        /* Not-a-number */
5859        if (index != 0)
5860  	break;
5861        /* FALLTHROUGH */
5862      case 'i':
5863      case 'I':
5864        /* Infinity */
5865        while (isalpha(ch) && (index - start < width))
5866  	{
5867  	  doubleString[index++] = (char)ch;
5868  	  self->InStream(self, &ch);
5869  	}
5870        doubleString[index] = NIL;
5871  
5872        /* Case insensitive string comparison */
5873        if (trio_equal(&doubleString[start], INFINITE_UPPER) ||
5874  	  trio_equal(&doubleString[start], LONG_INFINITE_UPPER))
5875  	{
5876  	  if (flags & FLAGS_LONGDOUBLE)
5877  	    {
5878  	      if ((start == 1) && (doubleString[0] == '-'))
5879  		{
5880  		  *((trio_long_double_t *)target) = trio_ninf();
5881  		}
5882  	      else
5883  		{
5884  		  *((trio_long_double_t *)target) = trio_pinf();
5885  		}
5886  	    }
5887  	  else
5888  	    {
5889  	      if ((start == 1) && (doubleString[0] == '-'))
5890  		{
5891  		  *((double *)target) = trio_ninf();
5892  		}
5893  	      else
5894  		{
5895  		  *((double *)target) = trio_pinf();
5896  		}
5897  	    }
5898  	  return TRUE;
5899  	}
5900        if (trio_equal(doubleString, NAN_UPPER))
5901  	{
5902  	  /* NaN must not have a preceeding + nor - */
5903  	  if (flags & FLAGS_LONGDOUBLE)
5904  	    {
5905  	      *((trio_long_double_t *)target) = trio_nan();
5906  	    }
5907  	  else
5908  	    {
5909  	      *((double *)target) = trio_nan();
5910  	    }
5911  	  return TRUE;
5912  	}
5913        return FALSE;
5914  
5915      case '0':
5916        doubleString[index++] = (char)ch;
5917        self->InStream(self, &ch);
5918        if (trio_to_upper(ch) == 'X')
5919  	{
5920  	  isHex = TRUE;
5921  	  doubleString[index++] = (char)ch;
5922  	  self->InStream(self, &ch);
5923  	}
5924        break;
5925  
5926      default:
5927        break;
5928      }
5929  
5930    while ((ch != EOF) && (index - start < width))
5931      {
5932        /* Integer part */
5933        if (isHex ? isxdigit(ch) : isdigit(ch))
5934  	{
5935  	  doubleString[index++] = (char)ch;
5936  	  self->InStream(self, &ch);
5937  	}
5938        else if (flags & FLAGS_QUOTE)
5939  	{
5940  	  /* Compare with thousands separator */
5941  	  for (j = 0; internalThousandSeparator[j] && self->current; j++)
5942  	    {
5943  	      if (internalThousandSeparator[j] != self->current)
5944  		break;
5945  
5946  	      self->InStream(self, &ch);
5947  	    }
5948  	  if (internalThousandSeparator[j])
5949  	    break; /* Mismatch */
5950  	  else
5951  	    continue; /* Match */
5952  	}
5953        else
5954  	break; /* while */
5955      }
5956    if (ch == '.')
5957      {
5958        /* Decimal part */
5959        doubleString[index++] = (char)ch;
5960        self->InStream(self, &ch);
5961        while ((isHex ? isxdigit(ch) : isdigit(ch)) &&
5962  	     (index - start < width))
5963  	{
5964  	  doubleString[index++] = (char)ch;
5965  	  self->InStream(self, &ch);
5966  	}
5967        if (isHex ? (trio_to_upper(ch) == 'P') : (trio_to_upper(ch) == 'E'))
5968  	{
5969  	  /* Exponent */
5970  	  doubleString[index++] = (char)ch;
5971  	  self->InStream(self, &ch);
5972  	  if ((ch == '+') || (ch == '-'))
5973  	    {
5974  	      doubleString[index++] = (char)ch;
5975  	      self->InStream(self, &ch);
5976  	    }
5977  	  while (isdigit(ch) && (index - start < width))
5978  	    {
5979  	      doubleString[index++] = (char)ch;
5980  	      self->InStream(self, &ch);
5981  	    }
5982  	}
5983      }
5984  
5985    if ((index == start) || (*doubleString == NIL))
5986      return FALSE;
5987  
5988    doubleString[index] = 0;
5989  
5990    if (flags & FLAGS_LONGDOUBLE)
5991      {
5992        *((trio_long_double_t *)target) = trio_to_long_double(doubleString, NULL);
5993      }
5994    else
5995      {
5996        *((double *)target) = trio_to_double(doubleString, NULL);
5997      }
5998    return TRUE;
5999  }
6000  
6001  /*************************************************************************
6002   * TrioReadPointer
6003   */
6004  TRIO_PRIVATE BOOLEAN_T
6005  TrioReadPointer
6006  TRIO_ARGS3((self, target, flags),
6007  	   trio_class_t *self,
6008  	   trio_pointer_t *target,
6009  	   trio_flags_t flags)
6010  {
6011    trio_uintmax_t number;
6012    char buffer[sizeof(internalNullString)];
6013  
6014    flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | FLAGS_NILPADDING);
6015  
6016    if (TrioReadNumber(self,
6017  		     &number,
6018  		     flags,
6019  		     POINTER_WIDTH,
6020  		     BASE_HEX))
6021      {
6022        /*
6023         * The strange assignment of number is a workaround for a compiler
6024         * warning
6025         */
6026        if (target)
6027  	*target = (char *)0 + number;
6028        return TRUE;
6029      }
6030    else if (TrioReadString(self,
6031  			  (flags & FLAGS_IGNORE)
6032  			  ? NULL
6033  			  : buffer,
6034  			  0,
6035  			  sizeof(internalNullString) - 1))
6036      {
6037        if (trio_equal_case(buffer, internalNullString))
6038  	{
6039  	  if (target)
6040  	    *target = NULL;
6041  	  return TRUE;
6042  	}
6043      }
6044    return FALSE;
6045  }
6046  
6047  /*************************************************************************
6048   * TrioScanProcess
6049   */
6050  TRIO_PRIVATE int
6051  TrioScanProcess
6052  TRIO_ARGS3((data, format, parameters),
6053  	   trio_class_t *data,
6054  	   TRIO_CONST char *format,
6055  	   trio_parameter_t *parameters)
6056  {
6057  #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
6058    int charlen;
6059    int cnt;
6060  #endif
6061    int assignment;
6062    int ch;
6063    int index; /* Index of format string */
6064    int i; /* Index of current parameter */
6065    trio_flags_t flags;
6066    int width;
6067    int base;
6068    trio_pointer_t pointer;
6069  
6070    assignment = 0;
6071    i = 0;
6072    index = 0;
6073    data->InStream(data, &ch);
6074  
6075  #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
6076    (void)mblen(NULL, 0);
6077  #endif
6078  
6079    while (format[index])
6080      {
6081  #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
6082        if (! isascii(format[index]))
6083  	{
6084  	  charlen = mblen(&format[index], MB_LEN_MAX);
6085  	  if (charlen != -1)
6086  	    {
6087  	      /* Compare multibyte characters in format string */
6088  	      for (cnt = 0; cnt < charlen - 1; cnt++)
6089  		{
6090  		  if (ch != format[index + cnt])
6091  		    {
6092  		      return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
6093  		    }
6094  		  data->InStream(data, &ch);
6095  		}
6096  	      continue; /* while characters left in formatting string */
6097  	    }
6098  	}
6099  #endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
6100  
6101        if ((EOF == ch) && (parameters[i].type != FORMAT_COUNT))
6102  	{
6103  	  return (assignment > 0) ? assignment : EOF;
6104  	}
6105  
6106        if (CHAR_IDENTIFIER == format[index])
6107  	{
6108  	  if (CHAR_IDENTIFIER == format[index + 1])
6109  	    {
6110  	      /* Two % in format matches one % in input stream */
6111  	      if (CHAR_IDENTIFIER == ch)
6112  		{
6113  		  data->InStream(data, &ch);
6114  		  index += 2;
6115  		  continue; /* while format chars left */
6116  		}
6117  	      else
6118  		return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
6119  	    }
6120  
6121  	  /* Skip the parameter entries */
6122  	  while (parameters[i].type == FORMAT_PARAMETER)
6123  	    i++;
6124  
6125  	  flags = parameters[i].flags;
6126  	  /* Find width */
6127  	  width = parameters[i].width;
6128  	  if (flags & FLAGS_WIDTH_PARAMETER)
6129  	    {
6130  	      /* Get width from parameter list */
6131  	      width = (int)parameters[width].data.number.as_signed;
6132  	    }
6133  	  /* Find base */
6134  	  base = parameters[i].base;
6135  	  if (flags & FLAGS_BASE_PARAMETER)
6136  	    {
6137  	      /* Get base from parameter list */
6138  	      base = (int)parameters[base].data.number.as_signed;
6139  	    }
6140  
6141  	  switch (parameters[i].type)
6142  	    {
6143  	    case FORMAT_INT:
6144  	      {
6145  		trio_uintmax_t number;
6146  
6147  		if (0 == base)
6148  		  base = BASE_DECIMAL;
6149  
6150  		if (!TrioReadNumber(data,
6151  				    &number,
6152  				    flags,
6153  				    width,
6154  				    base))
6155  		  return assignment;
6156  
6157  		if (!(flags & FLAGS_IGNORE))
6158  		  {
6159  		    assignment++;
6160  
6161  		    pointer = parameters[i].data.pointer;
6162  #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
6163  		    if (flags & FLAGS_SIZE_T)
6164  		      *(size_t *)pointer = (size_t)number;
6165  		    else
6166  #endif
6167  #if defined(QUALIFIER_PTRDIFF_T)
6168  		    if (flags & FLAGS_PTRDIFF_T)
6169  		      *(ptrdiff_t *)pointer = (ptrdiff_t)number;
6170  		    else
6171  #endif
6172  #if defined(QUALIFIER_INTMAX_T)
6173  		    if (flags & FLAGS_INTMAX_T)
6174  		      *(trio_intmax_t *)pointer = (trio_intmax_t)number;
6175  		    else
6176  #endif
6177  		    if (flags & FLAGS_QUAD)
6178  		      *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)number;
6179  		    else if (flags & FLAGS_LONG)
6180  		      *(long int *)pointer = (long int)number;
6181  		    else if (flags & FLAGS_SHORT)
6182  		      *(short int *)pointer = (short int)number;
6183  		    else
6184  		      *(int *)pointer = (int)number;
6185  		  }
6186  	      }
6187  	      break; /* FORMAT_INT */
6188  
6189  	    case FORMAT_STRING:
6190  #if TRIO_WIDECHAR
6191  	      if (flags & FLAGS_WIDECHAR)
6192  		{
6193  		  if (!TrioReadWideString(data,
6194  					  (flags & FLAGS_IGNORE)
6195  					  ? NULL
6196  					  : parameters[i].data.wstring,
6197  					  flags,
6198  					  width))
6199  		    return assignment;
6200  		}
6201  	      else
6202  #endif
6203  		{
6204  		  if (!TrioReadString(data,
6205  				      (flags & FLAGS_IGNORE)
6206  				      ? NULL
6207  				      : parameters[i].data.string,
6208  				      flags,
6209  				      width))
6210  		    return assignment;
6211  		}
6212  	      if (!(flags & FLAGS_IGNORE))
6213  		assignment++;
6214  	      break; /* FORMAT_STRING */
6215  
6216  	    case FORMAT_DOUBLE:
6217  	      {
6218  		trio_pointer_t pointer;
6219  
6220  		if (flags & FLAGS_IGNORE)
6221  		  {
6222  		    pointer = NULL;
6223  		  }
6224  		else
6225  		  {
6226  		    pointer = (flags & FLAGS_LONGDOUBLE)
6227  		      ? (trio_pointer_t)parameters[i].data.longdoublePointer
6228  		      : (trio_pointer_t)parameters[i].data.doublePointer;
6229  		  }
6230  		if (!TrioReadDouble(data, pointer, flags, width))
6231  		  {
6232  		    return assignment;
6233  		  }
6234  		if (!(flags & FLAGS_IGNORE))
6235  		  {
6236  		    assignment++;
6237  		  }
6238  		break; /* FORMAT_DOUBLE */
6239  	      }
6240  	    case FORMAT_GROUP:
6241  	      {
6242  		int characterclass[MAX_CHARACTER_CLASS + 1];
6243  		int rc;
6244  
6245  		/* Skip over modifiers */
6246  		while (format[index] != SPECIFIER_GROUP)
6247  		  {
6248  		    index++;
6249  		  }
6250  		/* Skip over group specifier */
6251  		index++;
6252  
6253  		memset(characterclass, 0, sizeof(characterclass));
6254  		rc = TrioGetCharacterClass(format,
6255  					   &index,
6256  					   &flags,
6257  					   characterclass);
6258  		if (rc < 0)
6259  		  return rc;
6260  
6261  		if (!TrioReadGroup(data,
6262  				   (flags & FLAGS_IGNORE)
6263  				   ? NULL
6264  				   : parameters[i].data.string,
6265  				   characterclass,
6266  				   flags,
6267  				   parameters[i].width))
6268  		  return assignment;
6269  		if (!(flags & FLAGS_IGNORE))
6270  		  assignment++;
6271  	      }
6272  	      break; /* FORMAT_GROUP */
6273  
6274  	    case FORMAT_COUNT:
6275  	      pointer = parameters[i].data.pointer;
6276  	      if (NULL != pointer)
6277  		{
6278  		  int count = data->committed;
6279  		  if (ch != EOF)
6280  		    count--; /* a character is read, but is not consumed yet */
6281  #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
6282  		  if (flags & FLAGS_SIZE_T)
6283  		    *(size_t *)pointer = (size_t)count;
6284  		  else
6285  #endif
6286  #if defined(QUALIFIER_PTRDIFF_T)
6287  		  if (flags & FLAGS_PTRDIFF_T)
6288  		    *(ptrdiff_t *)pointer = (ptrdiff_t)count;
6289  		  else
6290  #endif
6291  #if defined(QUALIFIER_INTMAX_T)
6292  		  if (flags & FLAGS_INTMAX_T)
6293  		    *(trio_intmax_t *)pointer = (trio_intmax_t)count;
6294  		  else
6295  #endif
6296  		  if (flags & FLAGS_QUAD)
6297  		    {
6298  		      *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)count;
6299  		    }
6300  		  else if (flags & FLAGS_LONG)
6301  		    {
6302  		      *(long int *)pointer = (long int)count;
6303  		    }
6304  		  else if (flags & FLAGS_SHORT)
6305  		    {
6306  		      *(short int *)pointer = (short int)count;
6307  		    }
6308  		  else
6309  		    {
6310  		      *(int *)pointer = (int)count;
6311  		    }
6312  		}
6313  	      break; /* FORMAT_COUNT */
6314  
6315  	    case FORMAT_CHAR:
6316  #if TRIO_WIDECHAR
6317  	      if (flags & FLAGS_WIDECHAR)
6318  		{
6319  		  if (TrioReadWideChar(data,
6320  				       (flags & FLAGS_IGNORE)
6321  				       ? NULL
6322  				       : parameters[i].data.wstring,
6323  				       flags,
6324  				       (width == NO_WIDTH) ? 1 : width) == 0)
6325  		    return assignment;
6326  		}
6327  	      else
6328  #endif
6329  		{
6330  		  if (TrioReadChar(data,
6331  				   (flags & FLAGS_IGNORE)
6332  				   ? NULL
6333  				   : parameters[i].data.string,
6334  				   flags,
6335  				   (width == NO_WIDTH) ? 1 : width) == 0)
6336  		    return assignment;
6337  		}
6338  	      if (!(flags & FLAGS_IGNORE))
6339  		assignment++;
6340  	      break; /* FORMAT_CHAR */
6341  
6342  	    case FORMAT_POINTER:
6343  	      if (!TrioReadPointer(data,
6344  				   (flags & FLAGS_IGNORE)
6345  				   ? NULL
6346  				   : (trio_pointer_t *)parameters[i].data.pointer,
6347  				   flags))
6348  		return assignment;
6349  	      if (!(flags & FLAGS_IGNORE))
6350  		assignment++;
6351  	      break; /* FORMAT_POINTER */
6352  
6353  	    case FORMAT_PARAMETER:
6354  	      break; /* FORMAT_PARAMETER */
6355  
6356  	    default:
6357  	      return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
6358  	    }
6359  	  ch = data->current;
6360  	  index = parameters[i].indexAfterSpecifier;
6361  	  i++;
6362  	}
6363        else /* Not an % identifier */
6364  	{
6365  	  if (isspace((int)format[index]))
6366  	    {
6367  	      /* Whitespaces may match any amount of whitespaces */
6368  	      ch = TrioSkipWhitespaces(data);
6369  	    }
6370  	  else if (ch == format[index])
6371  	    {
6372  	      data->InStream(data, &ch);
6373  	    }
6374  	  else
6375  	    return assignment;
6376  
6377  	  index++;
6378  	}
6379      }
6380    return assignment;
6381  }
6382  
6383  /*************************************************************************
6384   * TrioScan
6385   */
6386  TRIO_PRIVATE int
6387  TrioScan
6388  TRIO_ARGS6((source, sourceSize, InStream, format, arglist, argarray),
6389  	   trio_pointer_t source,
6390  	   size_t sourceSize,
6391  	   void (*InStream) TRIO_PROTO((trio_class_t *, int *)),
6392  	   TRIO_CONST char *format,
6393  	   TRIO_VA_LIST_PTR arglist,
6394  	   trio_pointer_t *argarray)
6395  {
6396    int status;
6397    trio_parameter_t parameters[MAX_PARAMETERS];
6398    trio_class_t data;
6399  
6400    assert(VALID(InStream));
6401    assert(VALID(format));
6402  
6403    memset(&data, 0, sizeof(data));
6404    data.InStream = InStream;
6405    data.location = (trio_pointer_t)source;
6406    data.max = sourceSize;
6407    data.error = 0;
6408  
6409  #if defined(USE_LOCALE)
6410    if (NULL == internalLocaleValues)
6411      {
6412        TrioSetLocale();
6413      }
6414  #endif
6415  
6416    status = TrioParse(TYPE_SCAN, format, parameters, arglist, argarray);
6417    if (status < 0)
6418      return status;
6419  
6420    status = TrioScanProcess(&data, format, parameters);
6421    if (data.error != 0)
6422      {
6423        status = data.error;
6424      }
6425    return status;
6426  }
6427  
6428  /*************************************************************************
6429   * TrioInStreamFile
6430   */
6431  TRIO_PRIVATE void
6432  TrioInStreamFile
6433  TRIO_ARGS2((self, intPointer),
6434  	   trio_class_t *self,
6435  	   int *intPointer)
6436  {
6437    FILE *file;
6438  
6439    assert(VALID(self));
6440    assert(VALID(self->location));
6441    assert(VALID(file));
6442  
6443    file = (FILE *)self->location;
6444  
6445    self->current = fgetc(file);
6446    if (self->current == EOF)
6447      {
6448        self->error = (ferror(file))
6449  	? TRIO_ERROR_RETURN(TRIO_ERRNO, 0)
6450  	: TRIO_ERROR_RETURN(TRIO_EOF, 0);
6451      }
6452    else
6453      {
6454        self->processed++;
6455        self->committed++;
6456      }
6457  
6458    if (VALID(intPointer))
6459      {
6460        *intPointer = self->current;
6461      }
6462  }
6463  
6464  /*************************************************************************
6465   * TrioInStreamFileDescriptor
6466   */
6467  TRIO_PRIVATE void
6468  TrioInStreamFileDescriptor
6469  TRIO_ARGS2((self, intPointer),
6470  	   trio_class_t *self,
6471  	   int *intPointer)
6472  {
6473    int fd;
6474    int size;
6475    unsigned char input;
6476  
6477    assert(VALID(self));
6478    assert(VALID(self->location));
6479  
6480    fd = *((int *)self->location);
6481  
6482    size = read(fd, &input, sizeof(char));
6483    if (size == -1)
6484      {
6485        self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0);
6486        self->current = EOF;
6487      }
6488    else
6489      {
6490        self->current = (size == 0) ? EOF : input;
6491      }
6492    if (self->current != EOF)
6493      {
6494        self->committed++;
6495        self->processed++;
6496      }
6497  
6498    if (VALID(intPointer))
6499      {
6500        *intPointer = self->current;
6501      }
6502  }
6503  
6504  /*************************************************************************
6505   * TrioInStreamCustom
6506   */
6507  TRIO_PRIVATE void
6508  TrioInStreamCustom
6509  TRIO_ARGS2((self, intPointer),
6510  	   trio_class_t *self,
6511  	   int *intPointer)
6512  {
6513    trio_custom_t *data;
6514  
6515    assert(VALID(self));
6516    assert(VALID(self->location));
6517  
6518    data = (trio_custom_t *)self->location;
6519  
6520    self->current = (data->stream.in == NULL)
6521      ? NIL
6522      : (data->stream.in)(data->closure);
6523  
6524    if (self->current == NIL)
6525      {
6526        self->current = EOF;
6527      }
6528    else
6529      {
6530        self->processed++;
6531        self->committed++;
6532      }
6533  
6534    if (VALID(intPointer))
6535      {
6536        *intPointer = self->current;
6537      }
6538  }
6539  
6540  /*************************************************************************
6541   * TrioInStreamString
6542   */
6543  TRIO_PRIVATE void
6544  TrioInStreamString
6545  TRIO_ARGS2((self, intPointer),
6546  	   trio_class_t *self,
6547  	   int *intPointer)
6548  {
6549    unsigned char **buffer;
6550  
6551    assert(VALID(self));
6552    assert(VALID(self->location));
6553  
6554    buffer = (unsigned char **)self->location;
6555    self->current = (*buffer)[0];
6556    if (self->current == NIL)
6557      {
6558        self->current = EOF;
6559      }
6560    else
6561      {
6562        (*buffer)++;
6563        self->processed++;
6564        self->committed++;
6565      }
6566  
6567    if (VALID(intPointer))
6568      {
6569        *intPointer = self->current;
6570      }
6571  }
6572  
6573  /*************************************************************************
6574   *
6575   * Formatted scanning functions
6576   *
6577   ************************************************************************/
6578  
6579  #if defined(TRIO_DOCUMENTATION)
6580  # include "doc/doc_scanf.h"
6581  #endif
6582  /** @addtogroup Scanf
6583      @{
6584  */
6585  
6586  /*************************************************************************
6587   * scanf
6588   */
6589  
6590  /**
6591     Scan characters from standard input stream.
6592  
6593     @param format Formatting string.
6594     @param ... Arguments.
6595     @return Number of scanned characters.
6596   */
6597  TRIO_PUBLIC int
6598  trio_scanf
6599  TRIO_VARGS2((format, va_alist),
6600  	    TRIO_CONST char *format,
6601  	    TRIO_VA_DECL)
6602  {
6603    int status;
6604    va_list args;
6605  
6606    assert(VALID(format));
6607  
6608    TRIO_VA_START(args, format);
6609    status = TrioScan((trio_pointer_t)stdin, 0,
6610  		    TrioInStreamFile,
6611  		    format, TRIO_VA_LIST_ADDR(args), NULL);
6612    TRIO_VA_END(args);
6613    return status;
6614  }
6615  
6616  TRIO_PUBLIC int
6617  trio_vscanf
6618  TRIO_ARGS2((format, args),
6619  	   TRIO_CONST char *format,
6620  	   va_list args)
6621  {
6622    assert(VALID(format));
6623  
6624    return TrioScan((trio_pointer_t)stdin, 0,
6625  		  TrioInStreamFile,
6626  		  format, TRIO_VA_LIST_ADDR(args), NULL);
6627  }
6628  
6629  TRIO_PUBLIC int
6630  trio_scanfv
6631  TRIO_ARGS2((format, args),
6632  	   TRIO_CONST char *format,
6633  	   trio_pointer_t *args)
6634  {
6635    assert(VALID(format));
6636  
6637    return TrioScan((trio_pointer_t)stdin, 0,
6638  		  TrioInStreamFile,
6639  		  format, NULL, args);
6640  }
6641  
6642  /*************************************************************************
6643   * fscanf
6644   */
6645  TRIO_PUBLIC int
6646  trio_fscanf
6647  TRIO_VARGS3((file, format, va_alist),
6648  	    FILE *file,
6649  	    TRIO_CONST char *format,
6650  	    TRIO_VA_DECL)
6651  {
6652    int status;
6653    va_list args;
6654  
6655    assert(VALID(file));
6656    assert(VALID(format));
6657  
6658    TRIO_VA_START(args, format);
6659    status = TrioScan((trio_pointer_t)file, 0,
6660  		    TrioInStreamFile,
6661  		    format, TRIO_VA_LIST_ADDR(args), NULL);
6662    TRIO_VA_END(args);
6663    return status;
6664  }
6665  
6666  TRIO_PUBLIC int
6667  trio_vfscanf
6668  TRIO_ARGS3((file, format, args),
6669  	   FILE *file,
6670  	   TRIO_CONST char *format,
6671  	   va_list args)
6672  {
6673    assert(VALID(file));
6674    assert(VALID(format));
6675  
6676    return TrioScan((trio_pointer_t)file, 0,
6677  		  TrioInStreamFile,
6678  		  format, TRIO_VA_LIST_ADDR(args), NULL);
6679  }
6680  
6681  TRIO_PUBLIC int
6682  trio_fscanfv
6683  TRIO_ARGS3((file, format, args),
6684  	   FILE *file,
6685  	   TRIO_CONST char *format,
6686  	   trio_pointer_t *args)
6687  {
6688    assert(VALID(file));
6689    assert(VALID(format));
6690  
6691    return TrioScan((trio_pointer_t)file, 0,
6692  		  TrioInStreamFile,
6693  		  format, NULL, args);
6694  }
6695  
6696  /*************************************************************************
6697   * dscanf
6698   */
6699  TRIO_PUBLIC int
6700  trio_dscanf
6701  TRIO_VARGS3((fd, format, va_alist),
6702  	    int fd,
6703  	    TRIO_CONST char *format,
6704  	    TRIO_VA_DECL)
6705  {
6706    int status;
6707    va_list args;
6708  
6709    assert(VALID(format));
6710  
6711    TRIO_VA_START(args, format);
6712    status = TrioScan((trio_pointer_t)&fd, 0,
6713  		    TrioInStreamFileDescriptor,
6714  		    format, TRIO_VA_LIST_ADDR(args), NULL);
6715    TRIO_VA_END(args);
6716    return status;
6717  }
6718  
6719  TRIO_PUBLIC int
6720  trio_vdscanf
6721  TRIO_ARGS3((fd, format, args),
6722  	   int fd,
6723  	   TRIO_CONST char *format,
6724  	   va_list args)
6725  {
6726    assert(VALID(format));
6727  
6728    return TrioScan((trio_pointer_t)&fd, 0,
6729  		  TrioInStreamFileDescriptor,
6730  		  format, TRIO_VA_LIST_ADDR(args), NULL);
6731  }
6732  
6733  TRIO_PUBLIC int
6734  trio_dscanfv
6735  TRIO_ARGS3((fd, format, args),
6736  	   int fd,
6737  	   TRIO_CONST char *format,
6738  	   trio_pointer_t *args)
6739  {
6740    assert(VALID(format));
6741  
6742    return TrioScan((trio_pointer_t)&fd, 0,
6743  		  TrioInStreamFileDescriptor,
6744  		  format, NULL, args);
6745  }
6746  
6747  /*************************************************************************
6748   * cscanf
6749   */
6750  TRIO_PUBLIC int
6751  trio_cscanf
6752  TRIO_VARGS4((stream, closure, format, va_alist),
6753  	    trio_instream_t stream,
6754  	    trio_pointer_t closure,
6755  	    TRIO_CONST char *format,
6756  	    TRIO_VA_DECL)
6757  {
6758    int status;
6759    va_list args;
6760    trio_custom_t data;
6761  
6762    assert(VALID(stream));
6763    assert(VALID(format));
6764  
6765    TRIO_VA_START(args, format);
6766    data.stream.in = stream;
6767    data.closure = closure;
6768    status = TrioScan(&data, 0, TrioInStreamCustom, format, TRIO_VA_LIST_ADDR(args), NULL);
6769    TRIO_VA_END(args);
6770    return status;
6771  }
6772  
6773  TRIO_PUBLIC int
6774  trio_vcscanf
6775  TRIO_ARGS4((stream, closure, format, args),
6776  	   trio_instream_t stream,
6777  	   trio_pointer_t closure,
6778  	   TRIO_CONST char *format,
6779  	   va_list args)
6780  {
6781    trio_custom_t data;
6782  
6783    assert(VALID(stream));
6784    assert(VALID(format));
6785  
6786    data.stream.in = stream;
6787    data.closure = closure;
6788    return TrioScan(&data, 0, TrioInStreamCustom, format, TRIO_VA_LIST_ADDR(args), NULL);
6789  }
6790  
6791  TRIO_PUBLIC int
6792  trio_cscanfv
6793  TRIO_ARGS4((stream, closure, format, args),
6794  	   trio_instream_t stream,
6795  	   trio_pointer_t closure,
6796  	   TRIO_CONST char *format,
6797  	   trio_pointer_t *args)
6798  {
6799    trio_custom_t data;
6800  
6801    assert(VALID(stream));
6802    assert(VALID(format));
6803  
6804    data.stream.in = stream;
6805    data.closure = closure;
6806    return TrioScan(&data, 0, TrioInStreamCustom, format, NULL, args);
6807  }
6808  
6809  /*************************************************************************
6810   * sscanf
6811   */
6812  TRIO_PUBLIC int
6813  trio_sscanf
6814  TRIO_VARGS3((buffer, format, va_alist),
6815  	    TRIO_CONST char *buffer,
6816  	    TRIO_CONST char *format,
6817  	    TRIO_VA_DECL)
6818  {
6819    int status;
6820    va_list args;
6821  
6822    assert(VALID(buffer));
6823    assert(VALID(format));
6824  
6825    TRIO_VA_START(args, format);
6826    status = TrioScan((trio_pointer_t)&buffer, 0,
6827  		    TrioInStreamString,
6828  		    format, TRIO_VA_LIST_ADDR(args), NULL);
6829    TRIO_VA_END(args);
6830    return status;
6831  }
6832  
6833  TRIO_PUBLIC int
6834  trio_vsscanf
6835  TRIO_ARGS3((buffer, format, args),
6836  	   TRIO_CONST char *buffer,
6837  	   TRIO_CONST char *format,
6838  	   va_list args)
6839  {
6840    assert(VALID(buffer));
6841    assert(VALID(format));
6842  
6843    return TrioScan((trio_pointer_t)&buffer, 0,
6844  		  TrioInStreamString,
6845  		  format, TRIO_VA_LIST_ADDR(args), NULL);
6846  }
6847  
6848  TRIO_PUBLIC int
6849  trio_sscanfv
6850  TRIO_ARGS3((buffer, format, args),
6851  	   TRIO_CONST char *buffer,
6852  	   TRIO_CONST char *format,
6853  	   trio_pointer_t *args)
6854  {
6855    assert(VALID(buffer));
6856    assert(VALID(format));
6857  
6858    return TrioScan((trio_pointer_t)&buffer, 0,
6859  		  TrioInStreamString,
6860  		  format, NULL, args);
6861  }
6862  
6863  /** @} End of Scanf documentation module */
6864  
6865  /*************************************************************************
6866   * trio_strerror
6867   */
6868  TRIO_PUBLIC TRIO_CONST char *
6869  trio_strerror
6870  TRIO_ARGS1((errorcode),
6871  	   int errorcode)
6872  {
6873    /* Textual versions of the error codes */
6874    switch (TRIO_ERROR_CODE(errorcode))
6875      {
6876      case TRIO_EOF:
6877        return "End of file";
6878      case TRIO_EINVAL:
6879        return "Invalid argument";
6880      case TRIO_ETOOMANY:
6881        return "Too many arguments";
6882      case TRIO_EDBLREF:
6883        return "Double reference";
6884      case TRIO_EGAP:
6885        return "Reference gap";
6886      case TRIO_ENOMEM:
6887        return "Out of memory";
6888      case TRIO_ERANGE:
6889        return "Invalid range";
6890      case TRIO_ECUSTOM:
6891        return "Custom error";
6892      default:
6893        return "Unknown";
6894      }
6895  }