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