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