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