source: trunk/third/libxml2/trio.c @ 20735

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