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