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