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