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