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