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