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