1/*************************************************************************
2 *
3 * $Id: trio.c,v 1.11 2003/04/03 15:28:27 veillard 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.11 2003/04/03 15:28:27 veillard 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}
6856