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