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