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