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