trio.c revision 1b7783879f7122564e209c7124301e886079f393
1311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/*************************************************************************
2311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
3311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * $Id: trio.c 3600 2007-04-17 12:44:58Z veillard $
4732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com *
5732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com * Copyright (C) 1998 Bjorn Reese and Daniel Stenberg.
6311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
7732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com * Permission to use, copy, modify, and distribute this software for any
8311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * purpose with or without fee is hereby granted, provided that the above
9311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * copyright notice and this permission notice appear in all copies.
10311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
11311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
12311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
13311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
14311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
15311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
16311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *************************************************************************
17311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
18311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * A note to trio contributors:
19311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
20311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * Avoid heap allocation at all costs to ensure that the trio functions
21311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * are async-safe. The exceptions are the printf/fprintf functions, which
22311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * uses fputc, and the asprintf functions and the <alloc> modifier, which
23311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * by design are required to allocate form the heap.
24311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
25311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff ************************************************************************/
26311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
27311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/*
28311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * TODO:
29311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *  - Scan is probably too permissive about its modifiers.
30311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *  - C escapes in %#[] ?
31311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *  - Multibyte characters (done for format parsing, except scan groups)
32311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *  - Complex numbers? (C99 _Complex)
33311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *  - Boolean values? (C99 _Bool)
34311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *  - C99 NaN(n-char-sequence) missing. The n-char-sequence can be used
35311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *    to print the mantissa, e.g. NaN(0xc000000000000000)
36311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *  - Should we support the GNU %a alloc modifier? GNU has an ugly hack
37311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *    for %a, because C99 used %a for other purposes. If specified as
38311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *    %as or %a[ it is interpreted as the alloc modifier, otherwise as
39311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *    the C99 hex-float. This means that you cannot scan %as as a hex-float
40311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *    immediately followed by an 's'.
41311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *  - Scanning of collating symbols.
42311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff */
43311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
44311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/*************************************************************************
45311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * Trio include files
46311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff */
47311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#include "triodef.h"
48311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#include "trio.h"
49311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#include "triop.h"
50311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#include "trionan.h"
51311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if !defined(TRIO_MINIMAL)
52311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# include "triostr.h"
53311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
54311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
55311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/**************************************************************************
56311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
57311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * Definitions
58311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
59311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *************************************************************************/
60311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
61311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#include <math.h>
62311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#include <limits.h>
63311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#include <float.h>
64311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
65311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if (defined(__STDC_ISO_10646__) || defined(MB_LEN_MAX) \
66311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff     || defined(USE_MULTIBYTE) || TRIO_WIDECHAR) \
67311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    && !defined(_WIN32_WCE)
68311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define TRIO_COMPILER_SUPPORTS_MULTIBYTE
69311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# if !defined(MB_LEN_MAX)
70311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  define MB_LEN_MAX 6
71311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# endif
72311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
73311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
74311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if (defined(TRIO_COMPILER_MSVC) && (_MSC_VER >= 1100)) || defined(TRIO_COMPILER_BCB)
75732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com# define TRIO_COMPILER_SUPPORTS_MSVC_INT
76732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#endif
77311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
78311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(_WIN32_WCE)
79311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#include <wincecompat.h>
80311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
81311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
82311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/*************************************************************************
83311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * Generic definitions
84311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff */
85311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
86311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if !(defined(DEBUG) || defined(NDEBUG))
87311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define NDEBUG
88311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
89311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
90311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#include <assert.h>
91311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#include <ctype.h>
92311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if !defined(TRIO_COMPILER_SUPPORTS_C99)
93311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define isblank(x) (((x)==32) || ((x)==9))
94311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
95311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(TRIO_COMPILER_ANCIENT)
96311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# include <varargs.h>
97311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#else
98311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# include <stdarg.h>
99311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
100311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#include <stddef.h>
101311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
102311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#ifdef HAVE_ERRNO_H
103311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#include <errno.h>
104311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
105311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
106311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#ifndef NULL
107311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define NULL 0
108311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
109311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define NIL ((char)0)
110311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#ifndef FALSE
111311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define FALSE (1 == 0)
112311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define TRUE (! FALSE)
113311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
114311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define BOOLEAN_T int
115311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
116311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/* mincore() can be used for debugging purposes */
117311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define VALID(x) (NULL != (x))
118311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
119311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if TRIO_ERRORS
120311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /*
121311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   * Encode the error code and the position. This is decoded
122311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   * with TRIO_ERROR_CODE and TRIO_ERROR_POSITION.
123d18457863096b3685e56f5a8919959f6afbdb121openvcdiff   */
124d18457863096b3685e56f5a8919959f6afbdb121openvcdiff# define TRIO_ERROR_RETURN(x,y) (- ((x) + ((y) << 8)))
125732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#else
126d18457863096b3685e56f5a8919959f6afbdb121openvcdiff# define TRIO_ERROR_RETURN(x,y) (-1)
127311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
128311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
129311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef unsigned long trio_flags_t;
130311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
131311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
132311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/*************************************************************************
133311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * Platform specific definitions
134311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff */
135311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(TRIO_PLATFORM_UNIX)
136311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# include <unistd.h>
137311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# include <signal.h>
138311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# include <locale.h>
139311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define USE_LOCALE
140311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif /* TRIO_PLATFORM_UNIX */
141311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(TRIO_PLATFORM_VMS)
142311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# include <unistd.h>
143311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
144311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(TRIO_PLATFORM_WIN32)
145311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# if defined(_WIN32_WCE)
146311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  include <wincecompat.h>
147311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# else
148311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  include <io.h>
149311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  define read _read
150311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  define write _write
151311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# endif
152311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif /* TRIO_PLATFORM_WIN32 */
153311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
154311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if TRIO_WIDECHAR
155311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# if defined(TRIO_COMPILER_SUPPORTS_ISO94)
156732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#  include <wchar.h>
157732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#  include <wctype.h>
158732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.comtypedef wchar_t trio_wchar_t;
159311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef wint_t trio_wint_t;
160311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# else
161311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef char trio_wchar_t;
162311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef int trio_wint_t;
163311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  define WCONST(x) L ## x
164311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  define WEOF EOF
165311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  define iswalnum(x) isalnum(x)
166311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  define iswalpha(x) isalpha(x)
167311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  define iswblank(x) isblank(x)
168311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  define iswcntrl(x) iscntrl(x)
169311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  define iswdigit(x) isdigit(x)
170311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  define iswgraph(x) isgraph(x)
171311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  define iswlower(x) islower(x)
172311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  define iswprint(x) isprint(x)
173311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  define iswpunct(x) ispunct(x)
174311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  define iswspace(x) isspace(x)
175311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  define iswupper(x) isupper(x)
176311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  define iswxdigit(x) isxdigit(x)
177311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# endif
178311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
179311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
180d18457863096b3685e56f5a8919959f6afbdb121openvcdiff
181d18457863096b3685e56f5a8919959f6afbdb121openvcdiff/*************************************************************************
182d18457863096b3685e56f5a8919959f6afbdb121openvcdiff * Compiler dependent definitions
183d18457863096b3685e56f5a8919959f6afbdb121openvcdiff */
184311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
185311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/* Support for long long */
186311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#ifndef __cplusplus
187311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# if !defined(USE_LONGLONG)
188311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  if defined(TRIO_COMPILER_GCC) && !defined(__STRICT_ANSI__)
189311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#   define USE_LONGLONG
190311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  elif defined(TRIO_COMPILER_SUNPRO)
191311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#   define USE_LONGLONG
192311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  elif defined(_LONG_LONG) || defined(_LONGLONG)
193311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#   define USE_LONGLONG
194311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#  endif
195311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# endif
196311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
197311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
198311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/* The extra long numbers */
199311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(USE_LONGLONG)
200d18457863096b3685e56f5a8919959f6afbdb121openvcdifftypedef signed long long int trio_longlong_t;
201d18457863096b3685e56f5a8919959f6afbdb121openvcdifftypedef unsigned long long int trio_ulonglong_t;
202d18457863096b3685e56f5a8919959f6afbdb121openvcdiff#elif defined(TRIO_COMPILER_SUPPORTS_MSVC_INT)
203d18457863096b3685e56f5a8919959f6afbdb121openvcdifftypedef signed __int64 trio_longlong_t;
204311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef unsigned __int64 trio_ulonglong_t;
205311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#else
206311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef TRIO_SIGNED long int trio_longlong_t;
207311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef unsigned long int trio_ulonglong_t;
208311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
209311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
210311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/* Maximal and fixed integer types */
211311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(TRIO_COMPILER_SUPPORTS_C99)
212311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# include <stdint.h>
213311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef intmax_t trio_intmax_t;
214311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef uintmax_t trio_uintmax_t;
215311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef int8_t trio_int8_t;
216311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef int16_t trio_int16_t;
217311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef int32_t trio_int32_t;
218311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef int64_t trio_int64_t;
219311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#elif defined(TRIO_COMPILER_SUPPORTS_UNIX98)
220311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# include <inttypes.h>
221311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef intmax_t trio_intmax_t;
222311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef uintmax_t trio_uintmax_t;
223311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef int8_t trio_int8_t;
224311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef int16_t trio_int16_t;
225311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef int32_t trio_int32_t;
226311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef int64_t trio_int64_t;
227311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#elif defined(TRIO_COMPILER_SUPPORTS_MSVC_INT)
228311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef trio_longlong_t trio_intmax_t;
229311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef trio_ulonglong_t trio_uintmax_t;
230311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef __int8 trio_int8_t;
231311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef __int16 trio_int16_t;
232311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef __int32 trio_int32_t;
233311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef __int64 trio_int64_t;
234311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#else
235311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef trio_longlong_t trio_intmax_t;
236311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef trio_ulonglong_t trio_uintmax_t;
237311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# if defined(TRIO_INT8_T)
238311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef TRIO_INT8_T trio_int8_t;
239311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# else
240311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef TRIO_SIGNED char trio_int8_t;
241311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# endif
242311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# if defined(TRIO_INT16_T)
243311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef TRIO_INT16_T trio_int16_t;
244311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# else
245311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef TRIO_SIGNED short trio_int16_t;
246311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# endif
247311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# if defined(TRIO_INT32_T)
248d18457863096b3685e56f5a8919959f6afbdb121openvcdifftypedef TRIO_INT32_T trio_int32_t;
249311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# else
250311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef TRIO_SIGNED int trio_int32_t;
251311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# endif
252d18457863096b3685e56f5a8919959f6afbdb121openvcdiff# if defined(TRIO_INT64_T)
253311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef TRIO_INT64_T trio_int64_t;
254311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# else
255311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef trio_longlong_t trio_int64_t;
256732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com# endif
257d18457863096b3685e56f5a8919959f6afbdb121openvcdiff#endif
258732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com
259311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if (!(defined(TRIO_COMPILER_SUPPORTS_C99) \
260311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff || defined(TRIO_COMPILER_SUPPORTS_UNIX01))) \
261311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff && !defined(_WIN32_WCE)
262732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com# define floorl(x) floor((double)(x))
263311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define fmodl(x,y) fmod((double)(x),(double)(y))
264732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com# define powl(x,y) pow((double)(x),(double)(y))
265732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#endif
266311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
267311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define TRIO_FABS(x) (((x) < 0.0) ? -(x) : (x))
268311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
269311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/*************************************************************************
270311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * Internal Definitions
271311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff */
272311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
273311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#ifndef DECIMAL_DIG
274311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define DECIMAL_DIG DBL_DIG
275311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
276311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
277311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/* Long double sizes */
278732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#ifdef LDBL_DIG
279d18457863096b3685e56f5a8919959f6afbdb121openvcdiff# define MAX_MANTISSA_DIGITS LDBL_DIG
280311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define MAX_EXPONENT_DIGITS 4
281d18457863096b3685e56f5a8919959f6afbdb121openvcdiff# define MAX_DOUBLE_DIGITS LDBL_MAX_10_EXP
282311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#else
283311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define MAX_MANTISSA_DIGITS DECIMAL_DIG
284311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define MAX_EXPONENT_DIGITS 3
285311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define MAX_DOUBLE_DIGITS DBL_MAX_10_EXP
286311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
287d18457863096b3685e56f5a8919959f6afbdb121openvcdiff
288732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#if defined(TRIO_COMPILER_ANCIENT) || !defined(LDBL_DIG)
289311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# undef LDBL_DIG
290d18457863096b3685e56f5a8919959f6afbdb121openvcdiff# undef LDBL_MANT_DIG
291d18457863096b3685e56f5a8919959f6afbdb121openvcdiff# undef LDBL_EPSILON
292d18457863096b3685e56f5a8919959f6afbdb121openvcdiff# define LDBL_DIG DBL_DIG
293311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define LDBL_MANT_DIG DBL_MANT_DIG
294311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define LDBL_EPSILON DBL_EPSILON
295311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
296d18457863096b3685e56f5a8919959f6afbdb121openvcdiff
297732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com/* The maximal number of digits is for base 2 */
298311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define MAX_CHARS_IN(x) (sizeof(x) * CHAR_BIT)
299311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/* The width of a pointer. The number of bits in a hex digit is 4 */
300311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define POINTER_WIDTH ((sizeof("0x") - 1) + sizeof(trio_pointer_t) * CHAR_BIT / 4)
301311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
302311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/* Infinite and Not-A-Number for floating-point */
303311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define INFINITE_LOWER "inf"
304311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define INFINITE_UPPER "INF"
305311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define LONG_INFINITE_LOWER "infinite"
306311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define LONG_INFINITE_UPPER "INFINITE"
307d18457863096b3685e56f5a8919959f6afbdb121openvcdiff#define NAN_LOWER "nan"
308d18457863096b3685e56f5a8919959f6afbdb121openvcdiff#define NAN_UPPER "NAN"
309d18457863096b3685e56f5a8919959f6afbdb121openvcdiff
310311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/* Various constants */
311311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffenum {
312311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  TYPE_PRINT = 1,
313311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  TYPE_SCAN  = 2,
314311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
315311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /* Flags. FLAGS_LAST must be less than ULONG_MAX */
316311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_NEW                 = 0,
317311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_STICKY              = 1,
318311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_SPACE               = 2 * FLAGS_STICKY,
319311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_SHOWSIGN            = 2 * FLAGS_SPACE,
320311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_LEFTADJUST          = 2 * FLAGS_SHOWSIGN,
321311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_ALTERNATIVE         = 2 * FLAGS_LEFTADJUST,
322311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_SHORT               = 2 * FLAGS_ALTERNATIVE,
323311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_SHORTSHORT          = 2 * FLAGS_SHORT,
324311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_LONG                = 2 * FLAGS_SHORTSHORT,
325311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_QUAD                = 2 * FLAGS_LONG,
326311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_LONGDOUBLE          = 2 * FLAGS_QUAD,
327311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_SIZE_T              = 2 * FLAGS_LONGDOUBLE,
328311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_PTRDIFF_T           = 2 * FLAGS_SIZE_T,
329d18457863096b3685e56f5a8919959f6afbdb121openvcdiff  FLAGS_INTMAX_T            = 2 * FLAGS_PTRDIFF_T,
330311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_NILPADDING          = 2 * FLAGS_INTMAX_T,
331311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_UNSIGNED            = 2 * FLAGS_NILPADDING,
332311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_UPPER               = 2 * FLAGS_UNSIGNED,
333311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_WIDTH               = 2 * FLAGS_UPPER,
334311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_WIDTH_PARAMETER     = 2 * FLAGS_WIDTH,
335d18457863096b3685e56f5a8919959f6afbdb121openvcdiff  FLAGS_PRECISION           = 2 * FLAGS_WIDTH_PARAMETER,
336311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_PRECISION_PARAMETER = 2 * FLAGS_PRECISION,
337311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_BASE                = 2 * FLAGS_PRECISION_PARAMETER,
338311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_BASE_PARAMETER      = 2 * FLAGS_BASE,
339311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_FLOAT_E             = 2 * FLAGS_BASE_PARAMETER,
340732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com  FLAGS_FLOAT_G             = 2 * FLAGS_FLOAT_E,
341d18457863096b3685e56f5a8919959f6afbdb121openvcdiff  FLAGS_QUOTE               = 2 * FLAGS_FLOAT_G,
342311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_WIDECHAR            = 2 * FLAGS_QUOTE,
343732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com  FLAGS_ALLOC               = 2 * FLAGS_WIDECHAR,
344311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_IGNORE              = 2 * FLAGS_ALLOC,
345311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_IGNORE_PARAMETER    = 2 * FLAGS_IGNORE,
346311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_VARSIZE_PARAMETER   = 2 * FLAGS_IGNORE_PARAMETER,
347732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com  FLAGS_FIXED_SIZE          = 2 * FLAGS_VARSIZE_PARAMETER,
348311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_LAST                = FLAGS_FIXED_SIZE,
349732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com  /* Reused flags */
350732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com  FLAGS_EXCLUDE             = FLAGS_SHORT,
351311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_USER_DEFINED        = FLAGS_IGNORE,
352311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_ROUNDING            = FLAGS_INTMAX_T,
353311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /* Compounded flags */
354311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_ALL_VARSIZES        = FLAGS_LONG | FLAGS_QUAD | FLAGS_INTMAX_T | FLAGS_PTRDIFF_T | FLAGS_SIZE_T,
355311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  FLAGS_ALL_SIZES           = FLAGS_ALL_VARSIZES | FLAGS_SHORTSHORT | FLAGS_SHORT,
356311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
357311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  NO_POSITION  = -1,
358311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  NO_WIDTH     =  0,
359311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  NO_PRECISION = -1,
360311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  NO_SIZE      = -1,
361311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
362311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /* Do not change these */
363d18457863096b3685e56f5a8919959f6afbdb121openvcdiff  NO_BASE      = -1,
364311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  MIN_BASE     =  2,
365d18457863096b3685e56f5a8919959f6afbdb121openvcdiff  MAX_BASE     = 36,
366311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  BASE_BINARY  =  2,
367311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  BASE_OCTAL   =  8,
368311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  BASE_DECIMAL = 10,
369311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  BASE_HEX     = 16,
370311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
371311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /* Maximal number of allowed parameters */
372732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com  MAX_PARAMETERS = 64,
373311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /* Maximal number of characters in class */
374d18457863096b3685e56f5a8919959f6afbdb121openvcdiff  MAX_CHARACTER_CLASS = UCHAR_MAX + 1,
375311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
376d18457863096b3685e56f5a8919959f6afbdb121openvcdiff  /* Maximal string lengths for user-defined specifiers */
377311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  MAX_USER_NAME = 64,
378732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com  MAX_USER_DATA = 256,
379311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
380311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /* Maximal length of locale separator strings */
381311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  MAX_LOCALE_SEPARATOR_LENGTH = MB_LEN_MAX,
382d18457863096b3685e56f5a8919959f6afbdb121openvcdiff  /* Maximal number of integers in grouping */
383732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com  MAX_LOCALE_GROUPS = 64,
384311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
385732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com  /* Initial size of asprintf buffer */
386732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com  DYNAMIC_START_SIZE = 32
387732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com};
388732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com
389732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#define NO_GROUPING ((int)CHAR_MAX)
390311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
391311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/* Fundamental formatting parameter types */
392311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define FORMAT_UNKNOWN   0
393311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define FORMAT_INT       1
394311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define FORMAT_DOUBLE    2
395311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define FORMAT_CHAR      3
396311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define FORMAT_STRING    4
397311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define FORMAT_POINTER   5
398311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define FORMAT_COUNT     6
399311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define FORMAT_PARAMETER 7
400311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define FORMAT_GROUP     8
401311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if TRIO_GNU
402311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define FORMAT_ERRNO    9
403311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
404311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if TRIO_EXTENSION
405311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define FORMAT_USER_DEFINED 10
406311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
407311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
408311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/* Character constants */
409311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define CHAR_IDENTIFIER '%'
410311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define CHAR_BACKSLASH '\\'
411311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define CHAR_QUOTE '\"'
412311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define CHAR_ADJUST ' '
413311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
414311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/* Character class expressions */
415311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define CLASS_ALNUM "[:alnum:]"
416311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define CLASS_ALPHA "[:alpha:]"
417311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define CLASS_BLANK "[:blank:]"
418311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define CLASS_CNTRL "[:cntrl:]"
419311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define CLASS_DIGIT "[:digit:]"
420311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define CLASS_GRAPH "[:graph:]"
421311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define CLASS_LOWER "[:lower:]"
422311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define CLASS_PRINT "[:print:]"
423311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define CLASS_PUNCT "[:punct:]"
424311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define CLASS_SPACE "[:space:]"
425311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define CLASS_UPPER "[:upper:]"
426311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define CLASS_XDIGIT "[:xdigit:]"
427311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
428311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/*
429311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * SPECIFIERS:
430311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
431311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
432311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * a  Hex-float
433311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * A  Hex-float
434311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * c  Character
435311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * C  Widechar character (wint_t)
436311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * d  Decimal
437311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * e  Float
438311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * E  Float
439311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * F  Float
440311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * F  Float
441311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * g  Float
442311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * G  Float
443311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * i  Integer
444311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * m  Error message
445311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * n  Count
446311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * o  Octal
447311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * p  Pointer
448311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * s  String
449311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * S  Widechar string (wchar_t *)
450311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * u  Unsigned
451311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * x  Hex
452311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * X  Hex
453732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com * [] Group
454732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com * <> User-defined
455732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com *
456732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com * Reserved:
457311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
458311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * D  Binary Coded Decimal %D(length,precision) (OS/390)
459311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff */
460311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define SPECIFIER_CHAR 'c'
461311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define SPECIFIER_STRING 's'
462311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define SPECIFIER_DECIMAL 'd'
463311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define SPECIFIER_INTEGER 'i'
464311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define SPECIFIER_UNSIGNED 'u'
465732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#define SPECIFIER_OCTAL 'o'
466732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#define SPECIFIER_HEX 'x'
467732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#define SPECIFIER_HEX_UPPER 'X'
468732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#define SPECIFIER_FLOAT_E 'e'
469732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#define SPECIFIER_FLOAT_E_UPPER 'E'
470732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#define SPECIFIER_FLOAT_F 'f'
471732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#define SPECIFIER_FLOAT_F_UPPER 'F'
472732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#define SPECIFIER_FLOAT_G 'g'
473732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#define SPECIFIER_FLOAT_G_UPPER 'G'
474732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#define SPECIFIER_POINTER 'p'
475732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#define SPECIFIER_GROUP '['
476732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#define SPECIFIER_UNGROUP ']'
477311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define SPECIFIER_COUNT 'n'
478311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if TRIO_UNIX98
479311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define SPECIFIER_CHAR_UPPER 'C'
480311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define SPECIFIER_STRING_UPPER 'S'
481732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#endif
482732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#if TRIO_C99
483732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com# define SPECIFIER_HEXFLOAT 'a'
484732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com# define SPECIFIER_HEXFLOAT_UPPER 'A'
485311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
486311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if TRIO_GNU
487311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define SPECIFIER_ERRNO 'm'
488311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
489311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if TRIO_EXTENSION
490311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define SPECIFIER_BINARY 'b'
491311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define SPECIFIER_BINARY_UPPER 'B'
492311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define SPECIFIER_USER_DEFINED_BEGIN '<'
493311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define SPECIFIER_USER_DEFINED_END '>'
494311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define SPECIFIER_USER_DEFINED_SEPARATOR ':'
495311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
496311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
497311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/*
498311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * QUALIFIERS:
499311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
500311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
501311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * Numbers = d,i,o,u,x,X
502311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * Float = a,A,e,E,f,F,g,G
503311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * String = s
504311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * Char = c
505311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
506311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
507311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * 9$ Position
508311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *      Use the 9th parameter. 9 can be any number between 1 and
509311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *      the maximal argument
510311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
511311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * 9 Width
512311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *      Set width to 9. 9 can be any number, but must not be postfixed
513d18457863096b3685e56f5a8919959f6afbdb121openvcdiff *      by '$'
514d18457863096b3685e56f5a8919959f6afbdb121openvcdiff *
515311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * h  Short
516311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *    Numbers:
517311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *      (unsigned) short int
518311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
519311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * hh Short short
520311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *    Numbers:
521311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *      (unsigned) char
522311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
523311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * l  Long
524311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *    Numbers:
525311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *      (unsigned) long int
526311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *    String:
527311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *      as the S specifier
528311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *    Char:
529311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *      as the C specifier
530311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
531311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * ll Long Long
532311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *    Numbers:
533311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *      (unsigned) long long int
534311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
535311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * L  Long Double
536311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *    Float
537311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *      long double
538311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
539311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * #  Alternative
540311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *    Float:
541311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *      Decimal-point is always present
542311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *    String:
543311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *      non-printable characters are handled as \number
544311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
545311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *    Spacing
546311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
547311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * +  Sign
548311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
549311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * -  Alignment
550311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
551311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * .  Precision
552732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com *
553732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com * *  Parameter
554732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com *    print: use parameter
555732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com *    scan: no parameter (ignore)
556311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
557311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * q  Quad
558311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
559311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * Z  size_t
560311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
561311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * w  Widechar
562311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
563311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * '  Thousands/quote
564311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *    Numbers:
565311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *      Integer part grouped in thousands
566311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *    Binary numbers:
567311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *      Number grouped in nibbles (4 bits)
568311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *    String:
569311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *      Quoted string
570311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
571311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * j  intmax_t
572311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * t  prtdiff_t
573311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * z  size_t
574311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
575311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * !  Sticky
576311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * @  Parameter (for both print and scan)
577311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
578311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * I  n-bit Integer
579311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *    Numbers:
580311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *      The following options exists
581311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *        I8  = 8-bit integer
582311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *        I16 = 16-bit integer
583311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *        I32 = 32-bit integer
584311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *        I64 = 64-bit integer
585311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff */
586311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define QUALIFIER_POSITION '$'
587311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define QUALIFIER_SHORT 'h'
588311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define QUALIFIER_LONG 'l'
589311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define QUALIFIER_LONG_UPPER 'L'
590311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define QUALIFIER_ALTERNATIVE '#'
591311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define QUALIFIER_SPACE ' '
592311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define QUALIFIER_PLUS '+'
593311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define QUALIFIER_MINUS '-'
594311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define QUALIFIER_DOT '.'
595311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define QUALIFIER_STAR '*'
596311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#define QUALIFIER_CIRCUMFLEX '^' /* For scanlists */
597311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if TRIO_C99
598311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define QUALIFIER_SIZE_T 'z'
599311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define QUALIFIER_PTRDIFF_T 't'
600311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define QUALIFIER_INTMAX_T 'j'
601311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
602311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if TRIO_BSD || TRIO_GNU
603311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define QUALIFIER_QUAD 'q'
604311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
605311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if TRIO_GNU
606311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define QUALIFIER_SIZE_T_UPPER 'Z'
607311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
608311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if TRIO_MISC
609311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define QUALIFIER_WIDECHAR 'w'
610311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
611311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if TRIO_MICROSOFT
612311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define QUALIFIER_FIXED_SIZE 'I'
613311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
614311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if TRIO_EXTENSION
615311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define QUALIFIER_QUOTE '\''
616311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define QUALIFIER_STICKY '!'
617311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define QUALIFIER_VARSIZE '&' /* This should remain undocumented */
618311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define QUALIFIER_PARAM '@' /* Experimental */
619311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define QUALIFIER_COLON ':' /* For scanlists */
620311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define QUALIFIER_EQUAL '=' /* For scanlists */
621311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define QUALIFIER_ROUNDING_UPPER 'R'
622311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
623311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
624311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
625311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/*************************************************************************
626311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
627311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * Internal Structures
628311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
629311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *************************************************************************/
630311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
631311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/* Parameters */
632311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef struct {
633311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /* An indication of which entry in the data union is used */
634311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int type;
635311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /* The flags */
636311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  trio_flags_t flags;
637311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /* The width qualifier */
638311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int width;
639311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /* The precision qualifier */
640311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int precision;
641311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /* The base qualifier */
642311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int base;
643311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /* The size for the variable size qualifier */
644311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int varsize;
645311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /* The marker of the end of the specifier */
646311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int indexAfterSpecifier;
647311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /* The data from the argument list */
648311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  union {
649311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    char *string;
650311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if TRIO_WIDECHAR
651311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    trio_wchar_t *wstring;
652311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
653311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    trio_pointer_t pointer;
654311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    union {
655311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      trio_intmax_t as_signed;
656311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      trio_uintmax_t as_unsigned;
657311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    } number;
658311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    double doubleNumber;
659311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    double *doublePointer;
660311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    trio_long_double_t longdoubleNumber;
661311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    trio_long_double_t *longdoublePointer;
662311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    int errorNumber;
663311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  } data;
664311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /* For the user-defined specifier */
665311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  char user_name[MAX_USER_NAME];
666311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  char user_data[MAX_USER_DATA];
667311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff} trio_parameter_t;
668311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
669311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/* Container for customized functions */
670311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef struct {
671311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  union {
672311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    trio_outstream_t out;
673311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    trio_instream_t in;
674311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  } stream;
675311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  trio_pointer_t closure;
676311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff} trio_custom_t;
677311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
678311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/* General trio "class" */
679311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef struct _trio_class_t {
680311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /*
681311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   * The function to write characters to a stream.
682311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   */
683311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  void (*OutStream) TRIO_PROTO((struct _trio_class_t *, int));
684311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /*
685311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   * The function to read characters from a stream.
686311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   */
687311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  void (*InStream) TRIO_PROTO((struct _trio_class_t *, int *));
688311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /*
689311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   * The current location in the stream.
690311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   */
691311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  trio_pointer_t location;
692311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /*
693311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   * The character currently being processed.
694311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   */
695311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int current;
696311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /*
697311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   * The number of characters that would have been written/read
698311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   * if there had been sufficient space.
699311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   */
700311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int processed;
701311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /*
702311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   * The number of characters that are actually written/read.
703311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   * Processed and committed will only differ for the *nprintf
704311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   * and *nscanf functions.
705311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   */
706311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int committed;
707311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /*
708311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   * The upper limit of characters that may be written/read.
709311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   */
710732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com  int max;
711732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com  /*
712732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com   * The last output error that was detected.
713732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com   */
714732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com  int error;
715732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com} trio_class_t;
716732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com
717732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com/* References (for user-defined callbacks) */
718311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef struct _trio_reference_t {
719311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  trio_class_t *data;
720311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  trio_parameter_t *parameter;
721311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff} trio_reference_t;
722311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
723311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/* Registered entries (for user-defined callbacks) */
724311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdifftypedef struct _trio_userdef_t {
725311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  struct _trio_userdef_t *next;
726311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  trio_callback_t callback;
727311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  char *name;
728311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff} trio_userdef_t;
729311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
730311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/*************************************************************************
731311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
732311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * Internal Variables
733d18457863096b3685e56f5a8919959f6afbdb121openvcdiff *
734d18457863096b3685e56f5a8919959f6afbdb121openvcdiff *************************************************************************/
735d18457863096b3685e56f5a8919959f6afbdb121openvcdiff
736d18457863096b3685e56f5a8919959f6afbdb121openvcdiffstatic TRIO_CONST char rcsid[] = "@(#)$Id: trio.c 3600 2007-04-17 12:44:58Z veillard $";
737311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
738311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/*
739311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * Need this to workaround a parser bug in HP C/iX compiler that fails
740311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * to resolves macro definitions that includes type 'long double',
741311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * e.g: va_arg(arg_ptr, long double)
742311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff */
743311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(TRIO_PLATFORM_MPEIX)
744311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffstatic TRIO_CONST trio_long_double_t ___dummy_long_double = 0;
745311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
746311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
747311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffstatic TRIO_CONST char internalNullString[] = "(nil)";
748311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
749311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(USE_LOCALE)
750311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffstatic struct lconv *internalLocaleValues = NULL;
751311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
752311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
753311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/*
754311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * UNIX98 says "in a locale where the radix character is not defined,
755311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * the radix character defaults to a period (.)"
756311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff */
757311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffstatic int internalDecimalPointLength = 1;
758311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffstatic int internalThousandSeparatorLength = 1;
759311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffstatic char internalDecimalPoint = '.';
760311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffstatic char internalDecimalPointString[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ".";
761311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffstatic char internalThousandSeparator[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ",";
762d18457863096b3685e56f5a8919959f6afbdb121openvcdiffstatic char internalGrouping[MAX_LOCALE_GROUPS] = { (char)NO_GROUPING };
763d18457863096b3685e56f5a8919959f6afbdb121openvcdiff
764d18457863096b3685e56f5a8919959f6afbdb121openvcdiffstatic TRIO_CONST char internalDigitsLower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
765311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffstatic TRIO_CONST char internalDigitsUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
766311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffstatic BOOLEAN_T internalDigitsUnconverted = TRUE;
767311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffstatic int internalDigitArray[128];
768311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if TRIO_EXTENSION
769311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffstatic BOOLEAN_T internalCollationUnconverted = TRUE;
770311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffstatic char internalCollationArray[MAX_CHARACTER_CLASS][MAX_CHARACTER_CLASS];
771311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
772311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
773311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if TRIO_EXTENSION
774311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffstatic TRIO_VOLATILE trio_callback_t internalEnterCriticalRegion = NULL;
775311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffstatic TRIO_VOLATILE trio_callback_t internalLeaveCriticalRegion = NULL;
776311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffstatic trio_userdef_t *internalUserDef = NULL;
777311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
778311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
779311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
780311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/*************************************************************************
781311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
782311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * Internal Functions
783311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
784311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff ************************************************************************/
785311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
786311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(TRIO_MINIMAL)
787311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# define TRIO_STRING_PUBLIC static
788311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff# include "triostr.c"
789311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif /* defined(TRIO_MINIMAL) */
790311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
791311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/*************************************************************************
792311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * TrioIsQualifier
793311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
794311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * Description:
795311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *  Remember to add all new qualifiers to this function.
796311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *  QUALIFIER_POSITION must not be added.
797311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff */
798311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTRIO_PRIVATE BOOLEAN_T
799311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTrioIsQualifier
800311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTRIO_ARGS1((character),
801311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	   TRIO_CONST char character)
802311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff{
803311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /* QUALIFIER_POSITION is not included */
804311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  switch (character)
805311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    {
806311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case '0': case '1': case '2': case '3': case '4':
807311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case '5': case '6': case '7': case '8': case '9':
808311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case QUALIFIER_PLUS:
809311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case QUALIFIER_MINUS:
810311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case QUALIFIER_SPACE:
811311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case QUALIFIER_DOT:
812311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case QUALIFIER_STAR:
813311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case QUALIFIER_ALTERNATIVE:
814311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case QUALIFIER_SHORT:
815311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case QUALIFIER_LONG:
816311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case QUALIFIER_LONG_UPPER:
817311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case QUALIFIER_CIRCUMFLEX:
818311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_SIZE_T)
819311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case QUALIFIER_SIZE_T:
820311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
821311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_PTRDIFF_T)
822311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case QUALIFIER_PTRDIFF_T:
823311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
824311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_INTMAX_T)
825311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case QUALIFIER_INTMAX_T:
826311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
827311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_QUAD)
828311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case QUALIFIER_QUAD:
829311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
830311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_SIZE_T_UPPER)
831311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case QUALIFIER_SIZE_T_UPPER:
832311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
833311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_WIDECHAR)
834311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case QUALIFIER_WIDECHAR:
835311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
836311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_QUOTE)
837311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case QUALIFIER_QUOTE:
838311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
839311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_STICKY)
840311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case QUALIFIER_STICKY:
841311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
842311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_VARSIZE)
843311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case QUALIFIER_VARSIZE:
844311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
845311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_PARAM)
846311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case QUALIFIER_PARAM:
847311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
848311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_FIXED_SIZE)
849311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case QUALIFIER_FIXED_SIZE:
850311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
851311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_ROUNDING_UPPER)
852311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case QUALIFIER_ROUNDING_UPPER:
853311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
854311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      return TRUE;
855311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    default:
856311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      return FALSE;
857311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    }
858311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff}
859311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
860311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/*************************************************************************
861311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * TrioSetLocale
862311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff */
863732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com#if defined(USE_LOCALE)
864732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.comTRIO_PRIVATE void
865732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.comTrioSetLocale(TRIO_NOARGS)
866732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com{
867732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com  internalLocaleValues = (struct lconv *)localeconv();
868732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com  if (internalLocaleValues)
869732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com    {
870732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com      if ((internalLocaleValues->decimal_point) &&
871311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  (internalLocaleValues->decimal_point[0] != NIL))
872311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	{
873311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  internalDecimalPointLength = trio_length(internalLocaleValues->decimal_point);
874311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  if (internalDecimalPointLength == 1)
875311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    {
876311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      internalDecimalPoint = internalLocaleValues->decimal_point[0];
877311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    }
878311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  else
879311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    {
880d18457863096b3685e56f5a8919959f6afbdb121openvcdiff	      internalDecimalPoint = NIL;
881d18457863096b3685e56f5a8919959f6afbdb121openvcdiff	      trio_copy_max(internalDecimalPointString,
882d18457863096b3685e56f5a8919959f6afbdb121openvcdiff			    sizeof(internalDecimalPointString),
883d18457863096b3685e56f5a8919959f6afbdb121openvcdiff			    internalLocaleValues->decimal_point);
884d18457863096b3685e56f5a8919959f6afbdb121openvcdiff	    }
885d18457863096b3685e56f5a8919959f6afbdb121openvcdiff	}
886311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      if ((internalLocaleValues->thousands_sep) &&
887311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  (internalLocaleValues->thousands_sep[0] != NIL))
888311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	{
889311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  trio_copy_max(internalThousandSeparator,
890311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			sizeof(internalThousandSeparator),
891311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			internalLocaleValues->thousands_sep);
892311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  internalThousandSeparatorLength = trio_length(internalThousandSeparator);
893311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	}
894311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      if ((internalLocaleValues->grouping) &&
895311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  (internalLocaleValues->grouping[0] != NIL))
896311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	{
897311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  trio_copy_max(internalGrouping,
898311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			sizeof(internalGrouping),
899311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			internalLocaleValues->grouping);
900311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	}
901311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    }
902311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff}
903311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif /* defined(USE_LOCALE) */
904311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
905311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTRIO_PRIVATE int
906311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTrioCalcThousandSeparatorLength
907311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTRIO_ARGS1((digits),
908311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	   int digits)
909311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff{
910311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if TRIO_EXTENSION
911311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int count = 0;
912311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int step = NO_GROUPING;
913311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  char *groupingPointer = internalGrouping;
914311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
915311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  while (digits > 0)
916311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    {
917311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      if (*groupingPointer == CHAR_MAX)
918311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	{
919311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  /* Disable grouping */
920311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  break; /* while */
921311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	}
922311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      else if (*groupingPointer == 0)
923311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	{
924311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  /* Repeat last group */
925311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  if (step == NO_GROUPING)
926311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    {
927311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      /* Error in locale */
928311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      break; /* while */
929311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    }
930311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	}
931311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      else
932311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	{
933311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  step = *groupingPointer++;
934311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	}
935311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      if (digits > step)
936311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	count += internalThousandSeparatorLength;
937311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      digits -= step;
938311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    }
939311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  return count;
940311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#else
941311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  return 0;
942d18457863096b3685e56f5a8919959f6afbdb121openvcdiff#endif
943d18457863096b3685e56f5a8919959f6afbdb121openvcdiff}
944d18457863096b3685e56f5a8919959f6afbdb121openvcdiff
945d18457863096b3685e56f5a8919959f6afbdb121openvcdiffTRIO_PRIVATE BOOLEAN_T
946311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTrioFollowedBySeparator
947311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTRIO_ARGS1((position),
948311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	   int position)
949311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff{
950311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if TRIO_EXTENSION
951311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int step = 0;
952311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  char *groupingPointer = internalGrouping;
953311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
954311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  position--;
955311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  if (position == 0)
956311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    return FALSE;
957311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  while (position > 0)
958311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    {
959311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      if (*groupingPointer == CHAR_MAX)
960311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	{
961311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  /* Disable grouping */
962311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  break; /* while */
963311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	}
964311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      else if (*groupingPointer != 0)
965311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	{
966311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  step = *groupingPointer++;
967311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	}
968311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      if (step == 0)
969311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	break;
970311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      position -= step;
971311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    }
972d18457863096b3685e56f5a8919959f6afbdb121openvcdiff  return (position == 0);
973d18457863096b3685e56f5a8919959f6afbdb121openvcdiff#else
974d18457863096b3685e56f5a8919959f6afbdb121openvcdiff  return FALSE;
975d18457863096b3685e56f5a8919959f6afbdb121openvcdiff#endif
976311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff}
977311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
978311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/*************************************************************************
979311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * TrioGetPosition
980311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
981311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * Get the %n$ position.
982311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff */
983311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTRIO_PRIVATE int
984311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTrioGetPosition
985311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTRIO_ARGS2((format, indexPointer),
986311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	   TRIO_CONST char *format,
987d18457863096b3685e56f5a8919959f6afbdb121openvcdiff	   int *indexPointer)
988d18457863096b3685e56f5a8919959f6afbdb121openvcdiff{
989d18457863096b3685e56f5a8919959f6afbdb121openvcdiff#if TRIO_UNIX98
990311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  char *tmpformat;
991311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int number = 0;
992311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int index = *indexPointer;
993311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
994311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  number = (int)trio_to_long(&format[index], &tmpformat, BASE_DECIMAL);
995311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  index = (int)(tmpformat - format);
996311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  if ((number != 0) && (QUALIFIER_POSITION == format[index++]))
997311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    {
998311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      *indexPointer = index;
999311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      /*
1000311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff       * number is decreased by 1, because n$ starts from 1, whereas
1001311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff       * the array it is indexing starts from 0.
1002311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff       */
1003311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      return number - 1;
1004311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    }
1005311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
1006311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  return NO_POSITION;
1007311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff}
1008311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1009311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if TRIO_EXTENSION
1010311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/*************************************************************************
1011311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * TrioFindNamespace
1012311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
1013311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * Find registered user-defined specifier.
1014311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * The prev argument is used for optimization only.
1015311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff */
1016311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTRIO_PRIVATE trio_userdef_t *
1017311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTrioFindNamespace
1018311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTRIO_ARGS2((name, prev),
1019311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	   TRIO_CONST char *name,
1020311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	   trio_userdef_t **prev)
1021311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff{
1022311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  trio_userdef_t *def;
1023311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1024311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  if (internalEnterCriticalRegion)
1025311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    (void)internalEnterCriticalRegion(NULL);
1026311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1027311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  for (def = internalUserDef; def; def = def->next)
1028311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    {
1029311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      /* Case-sensitive string comparison */
1030311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      if (trio_equal_case(def->name, name))
1031311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	break;
1032311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1033311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      if (prev)
1034311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	*prev = def;
1035311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    }
1036311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1037311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  if (internalLeaveCriticalRegion)
1038311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    (void)internalLeaveCriticalRegion(NULL);
1039311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1040311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  return def;
1041311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff}
1042311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
1043311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1044311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/*************************************************************************
1045311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * TrioPower
1046311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
1047311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * Description:
1048311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *  Calculate pow(base, exponent), where number and exponent are integers.
1049311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff */
1050311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTRIO_PRIVATE trio_long_double_t
1051311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTrioPower
1052311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTRIO_ARGS2((number, exponent),
1053311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	   int number,
1054311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	   int exponent)
1055311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff{
1056311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  trio_long_double_t result;
1057311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1058311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  if (number == 10)
1059311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    {
1060311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      switch (exponent)
1061311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	{
1062311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  /* Speed up calculation of common cases */
1063311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	case 0:
1064311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E-1);
1065311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  break;
1066311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	case 1:
1067311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+0);
1068311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  break;
1069311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	case 2:
1070311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+1);
1071311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  break;
1072311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	case 3:
1073311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+2);
1074311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  break;
1075311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	case 4:
1076311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+3);
1077311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  break;
1078311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	case 5:
1079732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+4);
1080732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com	  break;
1081732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com	case 6:
1082732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+5);
1083311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  break;
1084311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	case 7:
1085311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+6);
1086311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  break;
1087311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	case 8:
1088311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+7);
1089311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  break;
1090311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	case 9:
1091311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+8);
1092311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  break;
1093311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	default:
1094311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  result = powl((trio_long_double_t)number,
1095311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			(trio_long_double_t)exponent);
1096311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  break;
1097311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	}
1098311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    }
1099311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  else
1100311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    {
1101311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      return powl((trio_long_double_t)number, (trio_long_double_t)exponent);
1102311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    }
1103311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  return result;
1104311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff}
1105311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1106311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/*************************************************************************
1107311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * TrioLogarithm
1108311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff */
1109311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTRIO_PRIVATE double
1110311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTrioLogarithm
1111311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTRIO_ARGS2((number, base),
1112311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	   double number,
1113311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	   int base)
1114311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff{
1115311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  double result;
1116311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1117311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  if (number <= 0.0)
1118311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    {
1119311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      /* xlC crashes on log(0) */
1120311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      result = (number == 0.0) ? trio_ninf() : trio_nan();
1121311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    }
1122311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  else
1123311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    {
1124311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      if (base == 10)
1125311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	{
1126311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  result = log10(number);
1127311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	}
1128311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      else
1129311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	{
1130311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  result = log10(number) / log10((double)base);
1131311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	}
1132311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    }
1133311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  return result;
1134311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff}
1135311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1136311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/*************************************************************************
1137311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * TrioLogarithmBase
1138311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff */
1139311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTRIO_PRIVATE double
1140311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTrioLogarithmBase
1141311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTRIO_ARGS1((base),
1142311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	   int base)
1143311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff{
1144311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  switch (base)
1145311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    {
1146311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case BASE_BINARY : return 1.0;
1147311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case BASE_OCTAL  : return 3.0;
1148311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case BASE_DECIMAL: return 3.321928094887362345;
1149311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    case BASE_HEX    : return 4.0;
1150311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    default          : return TrioLogarithm((double)base, 2);
1151311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    }
1152311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff}
1153311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1154311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff/*************************************************************************
1155311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * TrioParse
1156311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff *
1157311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff * Description:
1158732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com *  Parse the format string
1159732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com */
1160732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.comTRIO_PRIVATE int
1161732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.comTrioParse
1162311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiffTRIO_ARGS5((type, format, parameters, arglist, argarray),
1163311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	   int type,
1164311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	   TRIO_CONST char *format,
1165311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	   trio_parameter_t *parameters,
1166311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	   va_list *arglist,
1167311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	   trio_pointer_t *argarray)
1168311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff{
1169311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /* Count the number of times a parameter is referenced */
1170311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  unsigned short usedEntries[MAX_PARAMETERS];
1171311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /* Parameter counters */
1172311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int parameterPosition;
1173311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int currentParam;
1174311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int maxParam = -1;
1175311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /* Utility variables */
1176311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  trio_flags_t flags;
1177311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int width;
1178311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int precision;
1179311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int varsize;
1180311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int base;
1181311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int index;  /* Index into formatting string */
1182311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int dots;  /* Count number of dots in modifier part */
1183311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  BOOLEAN_T positional;  /* Does the specifier have a positional? */
1184311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  BOOLEAN_T gotSticky = FALSE;  /* Are there any sticky modifiers at all? */
1185311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /*
1186311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   * indices specifies the order in which the parameters must be
1187311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   * read from the va_args (this is necessary to handle positionals)
1188311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   */
1189311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int indices[MAX_PARAMETERS];
1190311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int pos = 0;
1191311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /* Various variables */
1192311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  char ch;
1193311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
1194311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int charlen;
1195311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
1196311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int save_errno;
1197311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int i = -1;
1198311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  int num;
1199311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  char *tmpformat;
1200732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com
1201311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /* One and only one of arglist and argarray must be used */
1202311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  assert((arglist != NULL) ^ (argarray != NULL));
1203d18457863096b3685e56f5a8919959f6afbdb121openvcdiff
1204311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  /*
1205311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   * The 'parameters' array is not initialized, but we need to
1206311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   * know which entries we have used.
1207311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff   */
1208311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  memset(usedEntries, 0, sizeof(usedEntries));
1209311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1210311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  save_errno = errno;
1211311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  index = 0;
1212311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  parameterPosition = 0;
1213311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
1214311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  (void)mblen(NULL, 0);
1215311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
1216311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1217311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff  while (format[index])
1218311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff    {
1219311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
1220311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      if (! isascii(format[index]))
1221311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	{
1222311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  /*
1223311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	   * Multibyte characters cannot be legal specifiers or
1224311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	   * modifiers, so we skip over them.
1225311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	   */
1226311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  charlen = mblen(&format[index], MB_LEN_MAX);
1227311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  index += (charlen > 0) ? charlen : 1;
1228311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  continue; /* while */
1229311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	}
1230311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
1231311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff      if (CHAR_IDENTIFIER == format[index++])
1232311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	{
1233311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  if (CHAR_IDENTIFIER == format[index])
1234311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    {
1235311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      index++;
1236311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      continue; /* while */
1237311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    }
1238311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1239311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  flags = FLAGS_NEW;
1240311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  dots = 0;
1241311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  currentParam = TrioGetPosition(format, &index);
1242311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  positional = (NO_POSITION != currentParam);
1243311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  if (!positional)
1244311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    {
1245311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      /* We have no positional, get the next counter */
1246311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      currentParam = parameterPosition;
1247311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    }
1248311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff          if(currentParam >= MAX_PARAMETERS)
1249311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    {
1250311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      /* Bail out completely to make the error more obvious */
1251311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      return TRIO_ERROR_RETURN(TRIO_ETOOMANY, index);
1252311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    }
1253311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1254311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  if (currentParam > maxParam)
1255311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    maxParam = currentParam;
1256311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1257311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  /* Default values */
1258311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  width = NO_WIDTH;
1259311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  precision = NO_PRECISION;
1260311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  base = NO_BASE;
1261311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  varsize = NO_SIZE;
1262311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1263311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  while (TrioIsQualifier(format[index]))
1264311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    {
1265311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      ch = format[index++];
1266311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1267311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      switch (ch)
1268311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		{
1269311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		case QUALIFIER_SPACE:
1270732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com		  flags |= FLAGS_SPACE;
1271311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  break;
1272732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com
1273311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		case QUALIFIER_PLUS:
1274732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com		  flags |= FLAGS_SHOWSIGN;
1275311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  break;
1276311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1277d18457863096b3685e56f5a8919959f6afbdb121openvcdiff		case QUALIFIER_MINUS:
1278d18457863096b3685e56f5a8919959f6afbdb121openvcdiff		  flags |= FLAGS_LEFTADJUST;
1279311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  flags &= ~FLAGS_NILPADDING;
1280311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  break;
1281311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1282311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		case QUALIFIER_ALTERNATIVE:
1283732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com		  flags |= FLAGS_ALTERNATIVE;
1284311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  break;
1285d18457863096b3685e56f5a8919959f6afbdb121openvcdiff
1286d18457863096b3685e56f5a8919959f6afbdb121openvcdiff		case QUALIFIER_DOT:
1287311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  if (dots == 0) /* Precision */
1288311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    {
1289311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      dots++;
1290311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1291311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      /* Skip if no precision */
1292311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      if (QUALIFIER_DOT == format[index])
1293d18457863096b3685e56f5a8919959f6afbdb121openvcdiff			break;
1294311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1295311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      /* After the first dot we have the precision */
1296311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      flags |= FLAGS_PRECISION;
1297311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      if ((QUALIFIER_STAR == format[index])
1298311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_PARAM)
1299311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  || (QUALIFIER_PARAM == format[index])
1300311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
1301311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  )
1302311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			{
1303311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  index++;
1304311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  flags |= FLAGS_PRECISION_PARAMETER;
1305311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1306311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  precision = TrioGetPosition(format, &index);
1307311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  if (precision == NO_POSITION)
1308311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			    {
1309311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			      parameterPosition++;
1310311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			      if (positional)
1311311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff				precision = parameterPosition;
1312311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			      else
1313311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff				{
1314311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff				  precision = currentParam;
1315311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff				  currentParam = precision + 1;
1316311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff				}
1317311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			    }
1318311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  else
1319311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			    {
1320311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			      if (! positional)
1321311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff				currentParam = precision + 1;
1322311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			      if (width > maxParam)
1323311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff				maxParam = precision;
1324311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			    }
1325311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  if (currentParam > maxParam)
1326311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			    maxParam = currentParam;
1327311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			}
1328311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      else
1329311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			{
1330311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  precision = trio_to_long(&format[index],
1331311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff						   &tmpformat,
1332311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff						   BASE_DECIMAL);
1333311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  index = (int)(tmpformat - format);
1334311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			}
1335311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    }
1336311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  else if (dots == 1) /* Base */
1337311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    {
1338311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      dots++;
1339311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1340311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      /* After the second dot we have the base */
1341311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      flags |= FLAGS_BASE;
1342311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      if ((QUALIFIER_STAR == format[index])
1343311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_PARAM)
1344311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  || (QUALIFIER_PARAM == format[index])
1345311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
1346311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  )
1347311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			{
1348311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  index++;
1349311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  flags |= FLAGS_BASE_PARAMETER;
1350311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  base = TrioGetPosition(format, &index);
1351311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  if (base == NO_POSITION)
1352311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			    {
1353311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			      parameterPosition++;
1354311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			      if (positional)
1355311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff				base = parameterPosition;
1356311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			      else
1357311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff				{
1358311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff				  base = currentParam;
1359311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff				  currentParam = base + 1;
1360311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff				}
1361311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			    }
1362311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  else
1363311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			    {
1364311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			      if (! positional)
1365311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff				currentParam = base + 1;
1366311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			      if (base > maxParam)
1367311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff				maxParam = base;
1368311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			    }
1369311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  if (currentParam > maxParam)
1370311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			    maxParam = currentParam;
1371311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			}
1372311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      else
1373311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			{
1374311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  base = trio_to_long(&format[index],
1375311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff					      &tmpformat,
1376311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff					      BASE_DECIMAL);
1377311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  if (base > MAX_BASE)
1378311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1379311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  index = (int)(tmpformat - format);
1380311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			}
1381311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    }
1382311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  else
1383311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    {
1384311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1385311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    }
1386311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  break; /* QUALIFIER_DOT */
1387311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1388311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_PARAM)
1389311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		case QUALIFIER_PARAM:
1390311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  type = TYPE_PRINT;
1391311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  /* FALLTHROUGH */
1392311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
1393311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		case QUALIFIER_STAR:
1394311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  /* This has different meanings for print and scan */
1395311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  if (TYPE_PRINT == type)
1396311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    {
1397311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      /* Read with from parameter */
1398311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      flags |= (FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER);
1399311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      width = TrioGetPosition(format, &index);
1400311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      if (width == NO_POSITION)
1401311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			{
1402311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  parameterPosition++;
1403311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  if (positional)
1404311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			    width = parameterPosition;
1405311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  else
1406311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			    {
1407311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			      width = currentParam;
1408311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			      currentParam = width + 1;
1409311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			    }
1410311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			}
1411311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      else
1412311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			{
1413311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  if (! positional)
1414311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			    currentParam = width + 1;
1415311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  if (width > maxParam)
1416311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			    maxParam = width;
1417311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			}
1418311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      if (currentParam > maxParam)
1419311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			maxParam = currentParam;
1420311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    }
1421311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  else
1422311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    {
1423732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com		      /* Scan, but do not store result */
1424732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com		      flags |= FLAGS_IGNORE;
1425732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com		    }
1426311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1427311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  break; /* QUALIFIER_STAR */
1428311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1429311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		case '0':
1430311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  if (! (flags & FLAGS_LEFTADJUST))
1431311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    flags |= FLAGS_NILPADDING;
1432311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  /* FALLTHROUGH */
1433311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		case '1': case '2': case '3': case '4':
1434311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		case '5': case '6': case '7': case '8': case '9':
1435311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  flags |= FLAGS_WIDTH;
1436311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  /* &format[index - 1] is used to "rewind" the read
1437311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		   * character from format
1438311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		   */
1439311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  width = trio_to_long(&format[index - 1],
1440311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff				       &tmpformat,
1441311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff				       BASE_DECIMAL);
1442311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  index = (int)(tmpformat - format);
1443311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  break;
1444311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1445311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		case QUALIFIER_SHORT:
1446311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  if (flags & FLAGS_SHORTSHORT)
1447311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1448d18457863096b3685e56f5a8919959f6afbdb121openvcdiff		  else if (flags & FLAGS_SHORT)
1449d18457863096b3685e56f5a8919959f6afbdb121openvcdiff		    flags |= FLAGS_SHORTSHORT;
1450d18457863096b3685e56f5a8919959f6afbdb121openvcdiff		  else
1451d18457863096b3685e56f5a8919959f6afbdb121openvcdiff		    flags |= FLAGS_SHORT;
1452d18457863096b3685e56f5a8919959f6afbdb121openvcdiff		  break;
1453d18457863096b3685e56f5a8919959f6afbdb121openvcdiff
1454311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		case QUALIFIER_LONG:
1455311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  if (flags & FLAGS_QUAD)
1456311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1457311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  else if (flags & FLAGS_LONG)
1458311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    flags |= FLAGS_QUAD;
1459311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  else
1460311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    flags |= FLAGS_LONG;
1461311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  break;
1462311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1463d18457863096b3685e56f5a8919959f6afbdb121openvcdiff		case QUALIFIER_LONG_UPPER:
1464d18457863096b3685e56f5a8919959f6afbdb121openvcdiff		  flags |= FLAGS_LONGDOUBLE;
1465d18457863096b3685e56f5a8919959f6afbdb121openvcdiff		  break;
1466311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1467311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_SIZE_T)
1468311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		case QUALIFIER_SIZE_T:
1469311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  flags |= FLAGS_SIZE_T;
1470311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  /* Modify flags for later truncation of number */
1471311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  if (sizeof(size_t) == sizeof(trio_ulonglong_t))
1472311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    flags |= FLAGS_QUAD;
1473311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  else if (sizeof(size_t) == sizeof(long))
1474311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    flags |= FLAGS_LONG;
1475311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  break;
1476311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
1477311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1478311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_PTRDIFF_T)
1479311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		case QUALIFIER_PTRDIFF_T:
1480311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  flags |= FLAGS_PTRDIFF_T;
1481311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  if (sizeof(ptrdiff_t) == sizeof(trio_ulonglong_t))
1482311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    flags |= FLAGS_QUAD;
1483311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  else if (sizeof(ptrdiff_t) == sizeof(long))
1484311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    flags |= FLAGS_LONG;
1485311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  break;
1486311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
1487311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1488311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_INTMAX_T)
1489311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		case QUALIFIER_INTMAX_T:
1490311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  flags |= FLAGS_INTMAX_T;
1491d18457863096b3685e56f5a8919959f6afbdb121openvcdiff		  if (sizeof(trio_intmax_t) == sizeof(trio_ulonglong_t))
1492d18457863096b3685e56f5a8919959f6afbdb121openvcdiff		    flags |= FLAGS_QUAD;
1493d18457863096b3685e56f5a8919959f6afbdb121openvcdiff		  else if (sizeof(trio_intmax_t) == sizeof(long))
1494311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    flags |= FLAGS_LONG;
1495311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  break;
1496311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
1497311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1498311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_QUAD)
1499311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		case QUALIFIER_QUAD:
1500311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  flags |= FLAGS_QUAD;
1501311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  break;
1502311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
1503311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1504311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_FIXED_SIZE)
1505311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		case QUALIFIER_FIXED_SIZE:
1506311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  if (flags & FLAGS_FIXED_SIZE)
1507311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1508311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1509311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  if (flags & (FLAGS_ALL_SIZES | FLAGS_LONGDOUBLE |
1510311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			       FLAGS_WIDECHAR | FLAGS_VARSIZE_PARAMETER))
1511311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1512311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1513311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  if ((format[index] == '6') &&
1514311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      (format[index + 1] == '4'))
1515311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    {
1516311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      varsize = sizeof(trio_int64_t);
1517311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      index += 2;
1518311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    }
1519311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  else if ((format[index] == '3') &&
1520311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			   (format[index + 1] == '2'))
1521311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    {
1522311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      varsize = sizeof(trio_int32_t);
1523311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      index += 2;
1524311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    }
1525311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  else if ((format[index] == '1') &&
1526311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			   (format[index + 1] == '6'))
1527311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    {
1528311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      varsize = sizeof(trio_int16_t);
1529311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      index += 2;
1530311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    }
1531311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  else if (format[index] == '8')
1532311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    {
1533311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      varsize = sizeof(trio_int8_t);
1534311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      index++;
1535311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    }
1536311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  else
1537311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1538311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1539311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  flags |= FLAGS_FIXED_SIZE;
1540311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  break;
1541311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
1542311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1543311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_WIDECHAR)
1544311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		case QUALIFIER_WIDECHAR:
1545311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  flags |= FLAGS_WIDECHAR;
1546311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  break;
1547311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
1548311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1549311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_SIZE_T_UPPER)
1550311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		case QUALIFIER_SIZE_T_UPPER:
1551311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  break;
1552311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
1553311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1554311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_QUOTE)
1555311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		case QUALIFIER_QUOTE:
1556311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  flags |= FLAGS_QUOTE;
1557311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  break;
1558311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
1559311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1560311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_STICKY)
1561311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		case QUALIFIER_STICKY:
1562311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  flags |= FLAGS_STICKY;
1563311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  gotSticky = TRUE;
1564311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  break;
1565311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
1566311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1567311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_VARSIZE)
1568311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		case QUALIFIER_VARSIZE:
1569311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  flags |= FLAGS_VARSIZE_PARAMETER;
1570311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  parameterPosition++;
1571311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  if (positional)
1572311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    varsize = parameterPosition;
1573311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  else
1574311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    {
1575311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      varsize = currentParam;
1576311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      currentParam = varsize + 1;
1577311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    }
1578311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  if (currentParam > maxParam)
1579311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    maxParam = currentParam;
1580311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  break;
1581311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
1582311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1583311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(QUALIFIER_ROUNDING_UPPER)
1584311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		case QUALIFIER_ROUNDING_UPPER:
1585311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  flags |= FLAGS_ROUNDING;
1586311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  break;
1587311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
1588311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1589311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		default:
1590311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  /* Bail out completely to make the error more obvious */
1591311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff                  return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1592311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		}
1593311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    } /* while qualifier */
1594311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1595311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  /*
1596311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	   * Parameters only need the type and value. The value is
1597311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	   * read later.
1598311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	   */
1599311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  if (flags & FLAGS_WIDTH_PARAMETER)
1600311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    {
1601311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      usedEntries[width] += 1;
1602311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      parameters[pos].type = FORMAT_PARAMETER;
1603311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      parameters[pos].flags = 0;
1604311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      indices[width] = pos;
1605311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      width = pos++;
1606311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    }
1607311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  if (flags & FLAGS_PRECISION_PARAMETER)
1608311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    {
1609311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      usedEntries[precision] += 1;
1610311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      parameters[pos].type = FORMAT_PARAMETER;
1611311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      parameters[pos].flags = 0;
1612311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      indices[precision] = pos;
1613311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      precision = pos++;
1614311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    }
1615311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  if (flags & FLAGS_BASE_PARAMETER)
1616311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    {
1617311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      usedEntries[base] += 1;
1618311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      parameters[pos].type = FORMAT_PARAMETER;
1619311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      parameters[pos].flags = 0;
1620311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      indices[base] = pos;
1621311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      base = pos++;
1622311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    }
1623732fff248e662ec47aa27c124632f406f27b6c8dopenvcdiff@gmail.com	  if (flags & FLAGS_VARSIZE_PARAMETER)
1624311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    {
1625311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      usedEntries[varsize] += 1;
1626311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      parameters[pos].type = FORMAT_PARAMETER;
1627311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      parameters[pos].flags = 0;
1628311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      indices[varsize] = pos;
1629311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      varsize = pos++;
1630311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    }
1631311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1632311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  indices[currentParam] = pos;
1633311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1634311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	  switch (format[index++])
1635311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    {
1636311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(SPECIFIER_CHAR_UPPER)
1637311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    case SPECIFIER_CHAR_UPPER:
1638311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      flags |= FLAGS_WIDECHAR;
1639311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      /* FALLTHROUGH */
1640311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
1641311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    case SPECIFIER_CHAR:
1642311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      if (flags & FLAGS_LONG)
1643311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		flags |= FLAGS_WIDECHAR;
1644311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      else if (flags & FLAGS_SHORT)
1645311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		flags &= ~FLAGS_WIDECHAR;
1646311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      parameters[pos].type = FORMAT_CHAR;
1647311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      break;
1648311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1649311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#if defined(SPECIFIER_STRING_UPPER)
1650311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    case SPECIFIER_STRING_UPPER:
1651311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      flags |= FLAGS_WIDECHAR;
1652311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      /* FALLTHROUGH */
1653311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff#endif
1654311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    case SPECIFIER_STRING:
1655311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      if (flags & FLAGS_LONG)
1656311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		flags |= FLAGS_WIDECHAR;
1657311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      else if (flags & FLAGS_SHORT)
1658311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		flags &= ~FLAGS_WIDECHAR;
1659311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      parameters[pos].type = FORMAT_STRING;
1660311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      break;
1661311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1662311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    case SPECIFIER_GROUP:
1663311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      if (TYPE_SCAN == type)
1664311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		{
1665311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  int depth = 1;
1666311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  parameters[pos].type = FORMAT_GROUP;
1667311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  if (format[index] == QUALIFIER_CIRCUMFLEX)
1668311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    index++;
1669311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  if (format[index] == SPECIFIER_UNGROUP)
1670311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    index++;
1671311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  if (format[index] == QUALIFIER_MINUS)
1672311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    index++;
1673311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  /* Skip nested brackets */
1674311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		  while (format[index] != NIL)
1675311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    {
1676311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      if (format[index] == SPECIFIER_GROUP)
1677311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			{
1678311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  depth++;
1679311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			}
1680311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      else if (format[index] == SPECIFIER_UNGROUP)
1681311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			{
1682311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			  if (--depth <= 0)
1683311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			    {
1684311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			      index++;
1685311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			      break;
1686311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			    }
1687311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff			}
1688311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		      index++;
1689311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		    }
1690311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff		}
1691311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	      break;
1692311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff
1693311c71486f5f6074e5ba62a7f4c5397c8700b868openvcdiff	    case SPECIFIER_INTEGER:
1694	      parameters[pos].type = FORMAT_INT;
1695	      break;
1696
1697	    case SPECIFIER_UNSIGNED:
1698	      flags |= FLAGS_UNSIGNED;
1699	      parameters[pos].type = FORMAT_INT;
1700	      break;
1701
1702	    case SPECIFIER_DECIMAL:
1703	      /* Disable base modifier */
1704	      flags &= ~FLAGS_BASE_PARAMETER;
1705	      base = BASE_DECIMAL;
1706	      parameters[pos].type = FORMAT_INT;
1707	      break;
1708
1709	    case SPECIFIER_OCTAL:
1710	      flags |= FLAGS_UNSIGNED;
1711	      flags &= ~FLAGS_BASE_PARAMETER;
1712	      base = BASE_OCTAL;
1713	      parameters[pos].type = FORMAT_INT;
1714	      break;
1715
1716#if defined(SPECIFIER_BINARY)
1717	    case SPECIFIER_BINARY_UPPER:
1718	      flags |= FLAGS_UPPER;
1719	      /* FALLTHROUGH */
1720	    case SPECIFIER_BINARY:
1721	      flags |= FLAGS_NILPADDING;
1722	      flags &= ~FLAGS_BASE_PARAMETER;
1723	      base = BASE_BINARY;
1724	      parameters[pos].type = FORMAT_INT;
1725	      break;
1726#endif
1727
1728	    case SPECIFIER_HEX_UPPER:
1729	      flags |= FLAGS_UPPER;
1730	      /* FALLTHROUGH */
1731	    case SPECIFIER_HEX:
1732	      flags |= FLAGS_UNSIGNED;
1733	      flags &= ~FLAGS_BASE_PARAMETER;
1734	      base = BASE_HEX;
1735	      parameters[pos].type = FORMAT_INT;
1736	      break;
1737
1738	    case SPECIFIER_FLOAT_E_UPPER:
1739	      flags |= FLAGS_UPPER;
1740	      /* FALLTHROUGH */
1741	    case SPECIFIER_FLOAT_E:
1742	      flags |= FLAGS_FLOAT_E;
1743	      parameters[pos].type = FORMAT_DOUBLE;
1744	      break;
1745
1746	    case SPECIFIER_FLOAT_G_UPPER:
1747	      flags |= FLAGS_UPPER;
1748	      /* FALLTHROUGH */
1749	    case SPECIFIER_FLOAT_G:
1750	      flags |= FLAGS_FLOAT_G;
1751	      parameters[pos].type = FORMAT_DOUBLE;
1752	      break;
1753
1754	    case SPECIFIER_FLOAT_F_UPPER:
1755	      flags |= FLAGS_UPPER;
1756	      /* FALLTHROUGH */
1757	    case SPECIFIER_FLOAT_F:
1758	      parameters[pos].type = FORMAT_DOUBLE;
1759	      break;
1760
1761	    case SPECIFIER_POINTER:
1762	      if (sizeof(trio_pointer_t) == sizeof(trio_ulonglong_t))
1763		flags |= FLAGS_QUAD;
1764	      else if (sizeof(trio_pointer_t) == sizeof(long))
1765		flags |= FLAGS_LONG;
1766	      parameters[pos].type = FORMAT_POINTER;
1767	      break;
1768
1769	    case SPECIFIER_COUNT:
1770	      parameters[pos].type = FORMAT_COUNT;
1771	      break;
1772
1773#if defined(SPECIFIER_HEXFLOAT)
1774# if defined(SPECIFIER_HEXFLOAT_UPPER)
1775	    case SPECIFIER_HEXFLOAT_UPPER:
1776	      flags |= FLAGS_UPPER;
1777	      /* FALLTHROUGH */
1778# endif
1779	    case SPECIFIER_HEXFLOAT:
1780	      base = BASE_HEX;
1781	      parameters[pos].type = FORMAT_DOUBLE;
1782	      break;
1783#endif
1784
1785#if defined(FORMAT_ERRNO)
1786	    case SPECIFIER_ERRNO:
1787	      parameters[pos].type = FORMAT_ERRNO;
1788	      break;
1789#endif
1790
1791#if defined(SPECIFIER_USER_DEFINED_BEGIN)
1792	    case SPECIFIER_USER_DEFINED_BEGIN:
1793	      {
1794		unsigned int max;
1795		int without_namespace = TRUE;
1796
1797		parameters[pos].type = FORMAT_USER_DEFINED;
1798		parameters[pos].user_name[0] = NIL;
1799		tmpformat = (char *)&format[index];
1800
1801		while ((ch = format[index]))
1802		  {
1803		    index++;
1804		    if (ch == SPECIFIER_USER_DEFINED_END)
1805		      {
1806			if (without_namespace)
1807			  {
1808			    /* We must get the handle first */
1809			    parameters[pos].type = FORMAT_PARAMETER;
1810			    parameters[pos].indexAfterSpecifier = index;
1811			    parameters[pos].flags = FLAGS_USER_DEFINED;
1812			    /* Adjust parameters for insertion of new one */
1813			    pos++;
1814			    usedEntries[currentParam] += 1;
1815			    parameters[pos].type = FORMAT_USER_DEFINED;
1816			    currentParam++;
1817			    indices[currentParam] = pos;
1818			    if (currentParam > maxParam)
1819			      maxParam = currentParam;
1820			  }
1821			/* Copy the user data */
1822			max = (unsigned int)(&format[index] - tmpformat);
1823			if (max > MAX_USER_DATA)
1824			  max = MAX_USER_DATA;
1825			trio_copy_max(parameters[pos].user_data,
1826				      max,
1827				      tmpformat);
1828			break; /* while */
1829		      }
1830		    if (ch == SPECIFIER_USER_DEFINED_SEPARATOR)
1831		      {
1832			without_namespace = FALSE;
1833			/* Copy the namespace for later looking-up */
1834			max = (int)(&format[index] - tmpformat);
1835			if (max > MAX_USER_NAME)
1836			  max = MAX_USER_NAME;
1837			trio_copy_max(parameters[pos].user_name,
1838				      max,
1839				      tmpformat);
1840			tmpformat = (char *)&format[index];
1841		      }
1842		  }
1843		if (ch != SPECIFIER_USER_DEFINED_END)
1844		  return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1845	      }
1846	      break;
1847#endif /* defined(SPECIFIER_USER_DEFINED_BEGIN) */
1848
1849	    default:
1850	      /* Bail out completely to make the error more obvious */
1851              return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1852	    }
1853
1854	  /*  Count the number of times this entry has been used */
1855	  usedEntries[currentParam] += 1;
1856
1857	  /* Find last sticky parameters */
1858	  if (gotSticky && !(flags & FLAGS_STICKY))
1859	    {
1860	      for (i = pos - 1; i >= 0; i--)
1861		{
1862		  if (parameters[i].type == FORMAT_PARAMETER)
1863		    continue;
1864		  if ((parameters[i].flags & FLAGS_STICKY) &&
1865		      (parameters[i].type == parameters[pos].type))
1866		    {
1867		      /* Do not overwrite current qualifiers */
1868		      flags |= (parameters[i].flags & (unsigned long)~FLAGS_STICKY);
1869		      if (width == NO_WIDTH)
1870			width = parameters[i].width;
1871		      if (precision == NO_PRECISION)
1872			precision = parameters[i].precision;
1873		      if (base == NO_BASE)
1874			base = parameters[i].base;
1875		      break;
1876		    }
1877		}
1878	    }
1879
1880	  parameters[pos].indexAfterSpecifier = index;
1881	  parameters[pos].flags = flags;
1882	  parameters[pos].width = width;
1883	  parameters[pos].precision = precision;
1884	  parameters[pos].base = (base == NO_BASE) ? BASE_DECIMAL : base;
1885	  parameters[pos].varsize = varsize;
1886	  pos++;
1887
1888	  if (! positional)
1889	    parameterPosition++;
1890
1891	} /* if identifier */
1892
1893    } /* while format characters left */
1894
1895  for (num = 0; num <= maxParam; num++)
1896    {
1897      if (usedEntries[num] != 1)
1898	{
1899	  if (usedEntries[num] == 0) /* gap detected */
1900	    return TRIO_ERROR_RETURN(TRIO_EGAP, num);
1901	  else /* double references detected */
1902	    return TRIO_ERROR_RETURN(TRIO_EDBLREF, num);
1903	}
1904
1905      i = indices[num];
1906
1907      /*
1908       * FORMAT_PARAMETERS are only present if they must be read,
1909       * so it makes no sense to check the ignore flag (besides,
1910       * the flags variable is not set for that particular type)
1911       */
1912      if ((parameters[i].type != FORMAT_PARAMETER) &&
1913	  (parameters[i].flags & FLAGS_IGNORE))
1914	continue; /* for all arguments */
1915
1916      /*
1917       * The stack arguments are read according to ANSI C89
1918       * default argument promotions:
1919       *
1920       *  char           = int
1921       *  short          = int
1922       *  unsigned char  = unsigned int
1923       *  unsigned short = unsigned int
1924       *  float          = double
1925       *
1926       * In addition to the ANSI C89 these types are read (the
1927       * default argument promotions of C99 has not been
1928       * considered yet)
1929       *
1930       *  long long
1931       *  long double
1932       *  size_t
1933       *  ptrdiff_t
1934       *  intmax_t
1935       */
1936      switch (parameters[i].type)
1937	{
1938	case FORMAT_GROUP:
1939	case FORMAT_STRING:
1940#if TRIO_WIDECHAR
1941	  if (flags & FLAGS_WIDECHAR)
1942	    {
1943	      parameters[i].data.wstring = (argarray == NULL)
1944		? va_arg(*arglist, trio_wchar_t *)
1945		: (trio_wchar_t *)(argarray[num]);
1946	    }
1947	  else
1948#endif
1949	    {
1950	      parameters[i].data.string = (argarray == NULL)
1951		? va_arg(*arglist, char *)
1952		: (char *)(argarray[num]);
1953	    }
1954	  break;
1955
1956#if defined(FORMAT_USER_DEFINED)
1957	case FORMAT_USER_DEFINED:
1958#endif
1959	case FORMAT_POINTER:
1960	case FORMAT_COUNT:
1961	case FORMAT_UNKNOWN:
1962	  parameters[i].data.pointer = (argarray == NULL)
1963	    ? va_arg(*arglist, trio_pointer_t )
1964	    : argarray[num];
1965	  break;
1966
1967	case FORMAT_CHAR:
1968	case FORMAT_INT:
1969	  if (TYPE_SCAN == type)
1970	    {
1971              if (argarray == NULL)
1972                parameters[i].data.pointer =
1973                  (trio_pointer_t)va_arg(*arglist, trio_pointer_t);
1974              else
1975                {
1976                  if (parameters[i].type == FORMAT_CHAR)
1977                    parameters[i].data.pointer =
1978                      (trio_pointer_t)((char *)argarray[num]);
1979                  else if (parameters[i].flags & FLAGS_SHORT)
1980                    parameters[i].data.pointer =
1981                      (trio_pointer_t)((short *)argarray[num]);
1982                  else
1983                    parameters[i].data.pointer =
1984                      (trio_pointer_t)((int *)argarray[num]);
1985                }
1986	    }
1987	  else
1988	    {
1989#if defined(QUALIFIER_VARSIZE) || defined(QUALIFIER_FIXED_SIZE)
1990	      if (parameters[i].flags
1991		  & (FLAGS_VARSIZE_PARAMETER | FLAGS_FIXED_SIZE))
1992		{
1993		  if (parameters[i].flags & FLAGS_VARSIZE_PARAMETER)
1994		    {
1995		      /*
1996		       * Variable sizes are mapped onto the fixed sizes, in
1997		       * accordance with integer promotion.
1998		       *
1999		       * Please note that this may not be portable, as we
2000		       * only guess the size, not the layout of the numbers.
2001		       * For example, if int is little-endian, and long is
2002		       * big-endian, then this will fail.
2003		       */
2004		      varsize = (int)parameters[parameters[i].varsize].data.number.as_unsigned;
2005		    }
2006		  else
2007		    {
2008		      /* Used for the I<bits> modifiers */
2009		      varsize = parameters[i].varsize;
2010		    }
2011		  parameters[i].flags &= ~FLAGS_ALL_VARSIZES;
2012
2013		  if (varsize <= (int)sizeof(int))
2014		    ;
2015		  else if (varsize <= (int)sizeof(long))
2016		    parameters[i].flags |= FLAGS_LONG;
2017#if defined(QUALIFIER_INTMAX_T)
2018		  else if (varsize <= (int)sizeof(trio_longlong_t))
2019		    parameters[i].flags |= FLAGS_QUAD;
2020		  else
2021		    parameters[i].flags |= FLAGS_INTMAX_T;
2022#else
2023		  else
2024		    parameters[i].flags |= FLAGS_QUAD;
2025#endif
2026		}
2027#endif /* defined(QUALIFIER_VARSIZE) */
2028#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
2029	      if (parameters[i].flags & FLAGS_SIZE_T)
2030		parameters[i].data.number.as_unsigned = (argarray == NULL)
2031		  ? (trio_uintmax_t)va_arg(*arglist, size_t)
2032		  : (trio_uintmax_t)(*((size_t *)argarray[num]));
2033	      else
2034#endif
2035#if defined(QUALIFIER_PTRDIFF_T)
2036	      if (parameters[i].flags & FLAGS_PTRDIFF_T)
2037		parameters[i].data.number.as_unsigned = (argarray == NULL)
2038		  ? (trio_uintmax_t)va_arg(*arglist, ptrdiff_t)
2039		  : (trio_uintmax_t)(*((ptrdiff_t *)argarray[num]));
2040	      else
2041#endif
2042#if defined(QUALIFIER_INTMAX_T)
2043	      if (parameters[i].flags & FLAGS_INTMAX_T)
2044		parameters[i].data.number.as_unsigned = (argarray == NULL)
2045		  ? (trio_uintmax_t)va_arg(*arglist, trio_intmax_t)
2046		  : (trio_uintmax_t)(*((trio_intmax_t *)argarray[num]));
2047	      else
2048#endif
2049	      if (parameters[i].flags & FLAGS_QUAD)
2050		parameters[i].data.number.as_unsigned = (argarray == NULL)
2051		  ? (trio_uintmax_t)va_arg(*arglist, trio_ulonglong_t)
2052		  : (trio_uintmax_t)(*((trio_ulonglong_t *)argarray[num]));
2053	      else if (parameters[i].flags & FLAGS_LONG)
2054		parameters[i].data.number.as_unsigned = (argarray == NULL)
2055		  ? (trio_uintmax_t)va_arg(*arglist, long)
2056		  : (trio_uintmax_t)(*((long *)argarray[num]));
2057	      else
2058		{
2059		  if (argarray == NULL)
2060		    parameters[i].data.number.as_unsigned = (trio_uintmax_t)va_arg(*arglist, int);
2061		  else
2062		    {
2063		      if (parameters[i].type == FORMAT_CHAR)
2064			parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((char *)argarray[num]));
2065		      else if (parameters[i].flags & FLAGS_SHORT)
2066			parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((short *)argarray[num]));
2067		      else
2068			parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((int *)argarray[num]));
2069		    }
2070		}
2071	    }
2072	  break;
2073
2074	case FORMAT_PARAMETER:
2075	  /*
2076	   * The parameter for the user-defined specifier is a pointer,
2077	   * whereas the rest (width, precision, base) uses an integer.
2078	   */
2079	  if (parameters[i].flags & FLAGS_USER_DEFINED)
2080	    parameters[i].data.pointer = (argarray == NULL)
2081	      ? va_arg(*arglist, trio_pointer_t )
2082	      : argarray[num];
2083	  else
2084	    parameters[i].data.number.as_unsigned = (argarray == NULL)
2085	      ? (trio_uintmax_t)va_arg(*arglist, int)
2086	      : (trio_uintmax_t)(*((int *)argarray[num]));
2087	  break;
2088
2089	case FORMAT_DOUBLE:
2090	  if (TYPE_SCAN == type)
2091	    {
2092	      if (parameters[i].flags & FLAGS_LONGDOUBLE)
2093		parameters[i].data.longdoublePointer = (argarray == NULL)
2094		  ? va_arg(*arglist, trio_long_double_t *)
2095		  : (trio_long_double_t *)argarray[num];
2096	      else
2097                {
2098		  if (parameters[i].flags & FLAGS_LONG)
2099		    parameters[i].data.doublePointer = (argarray == NULL)
2100		      ? va_arg(*arglist, double *)
2101		      : (double *)argarray[num];
2102		  else
2103		    parameters[i].data.doublePointer = (argarray == NULL)
2104		      ? (double *)va_arg(*arglist, float *)
2105		      : (double *)((float *)argarray[num]);
2106                }
2107	    }
2108	  else
2109	    {
2110	      if (parameters[i].flags & FLAGS_LONGDOUBLE)
2111		parameters[i].data.longdoubleNumber = (argarray == NULL)
2112		  ? va_arg(*arglist, trio_long_double_t)
2113		  : (trio_long_double_t)(*((trio_long_double_t *)argarray[num]));
2114	      else
2115		{
2116		  if (argarray == NULL)
2117		    parameters[i].data.longdoubleNumber =
2118		      (trio_long_double_t)va_arg(*arglist, double);
2119		  else
2120		    {
2121		      if (parameters[i].flags & FLAGS_SHORT)
2122			parameters[i].data.longdoubleNumber =
2123			  (trio_long_double_t)(*((float *)argarray[num]));
2124		      else
2125			parameters[i].data.longdoubleNumber =
2126			  (trio_long_double_t)(*((double *)argarray[num]));
2127		    }
2128		}
2129	    }
2130	  break;
2131
2132#if defined(FORMAT_ERRNO)
2133	case FORMAT_ERRNO:
2134	  parameters[i].data.errorNumber = save_errno;
2135	  break;
2136#endif
2137
2138	default:
2139	  break;
2140	}
2141    } /* for all specifiers */
2142  return num;
2143}
2144
2145
2146/*************************************************************************
2147 *
2148 * FORMATTING
2149 *
2150 ************************************************************************/
2151
2152
2153/*************************************************************************
2154 * TrioWriteNumber
2155 *
2156 * Description:
2157 *  Output a number.
2158 *  The complexity of this function is a result of the complexity
2159 *  of the dependencies of the flags.
2160 */
2161TRIO_PRIVATE void
2162TrioWriteNumber
2163TRIO_ARGS6((self, number, flags, width, precision, base),
2164	   trio_class_t *self,
2165	   trio_uintmax_t number,
2166	   trio_flags_t flags,
2167	   int width,
2168	   int precision,
2169	   int base)
2170{
2171  BOOLEAN_T isNegative;
2172  BOOLEAN_T isNumberZero;
2173  BOOLEAN_T isPrecisionZero;
2174  BOOLEAN_T ignoreNumber;
2175  char buffer[MAX_CHARS_IN(trio_uintmax_t) * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1];
2176  char *bufferend;
2177  char *pointer;
2178  TRIO_CONST char *digits;
2179  int i;
2180  int length;
2181  char *p;
2182  int count;
2183
2184  assert(VALID(self));
2185  assert(VALID(self->OutStream));
2186  assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE));
2187
2188  digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
2189  if (base == NO_BASE)
2190    base = BASE_DECIMAL;
2191
2192  isNumberZero = (number == 0);
2193  isPrecisionZero = (precision == 0);
2194  ignoreNumber = (isNumberZero
2195		  && isPrecisionZero
2196		  && !((flags & FLAGS_ALTERNATIVE) && (base == BASE_OCTAL)));
2197
2198  if (flags & FLAGS_UNSIGNED)
2199    {
2200      isNegative = FALSE;
2201      flags &= ~FLAGS_SHOWSIGN;
2202    }
2203  else
2204    {
2205      isNegative = ((trio_intmax_t)number < 0);
2206      if (isNegative)
2207	number = -((trio_intmax_t)number);
2208    }
2209
2210  if (flags & FLAGS_QUAD)
2211    number &= (trio_ulonglong_t)-1;
2212  else if (flags & FLAGS_LONG)
2213    number &= (unsigned long)-1;
2214  else
2215    number &= (unsigned int)-1;
2216
2217  /* Build number */
2218  pointer = bufferend = &buffer[sizeof(buffer) - 1];
2219  *pointer-- = NIL;
2220  for (i = 1; i < (int)sizeof(buffer); i++)
2221    {
2222      *pointer-- = digits[number % base];
2223      number /= base;
2224      if (number == 0)
2225	break;
2226
2227      if ((flags & FLAGS_QUOTE) && TrioFollowedBySeparator(i + 1))
2228	{
2229	  /*
2230	   * We are building the number from the least significant
2231	   * to the most significant digit, so we have to copy the
2232	   * thousand separator backwards
2233	   */
2234	  length = internalThousandSeparatorLength;
2235	  if (((int)(pointer - buffer) - length) > 0)
2236	    {
2237	      p = &internalThousandSeparator[length - 1];
2238	      while (length-- > 0)
2239		*pointer-- = *p--;
2240	    }
2241	}
2242    }
2243
2244  if (! ignoreNumber)
2245    {
2246      /* Adjust width */
2247      width -= (bufferend - pointer) - 1;
2248    }
2249
2250  /* Adjust precision */
2251  if (NO_PRECISION != precision)
2252    {
2253      precision -= (bufferend - pointer) - 1;
2254      if (precision < 0)
2255	precision = 0;
2256      flags |= FLAGS_NILPADDING;
2257    }
2258
2259  /* Calculate padding */
2260  count = (! ((flags & FLAGS_LEFTADJUST) || (precision == NO_PRECISION)))
2261    ? precision
2262    : 0;
2263
2264  /* Adjust width further */
2265  if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
2266    width--;
2267  if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero)
2268    {
2269      switch (base)
2270	{
2271	case BASE_BINARY:
2272	case BASE_HEX:
2273	  width -= 2;
2274	  break;
2275	case BASE_OCTAL:
2276	  if (!(flags & FLAGS_NILPADDING) || (count == 0))
2277	    width--;
2278	  break;
2279	default:
2280	  break;
2281	}
2282    }
2283
2284  /* Output prefixes spaces if needed */
2285  if (! ((flags & FLAGS_LEFTADJUST) ||
2286	 ((flags & FLAGS_NILPADDING) && (precision == NO_PRECISION))))
2287    {
2288      while (width-- > count)
2289	self->OutStream(self, CHAR_ADJUST);
2290    }
2291
2292  /* width has been adjusted for signs and alternatives */
2293  if (isNegative)
2294    self->OutStream(self, '-');
2295  else if (flags & FLAGS_SHOWSIGN)
2296    self->OutStream(self, '+');
2297  else if (flags & FLAGS_SPACE)
2298    self->OutStream(self, ' ');
2299
2300  /* Prefix is not written when the value is zero */
2301  if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero)
2302    {
2303      switch (base)
2304	{
2305	case BASE_BINARY:
2306	  self->OutStream(self, '0');
2307	  self->OutStream(self, (flags & FLAGS_UPPER) ? 'B' : 'b');
2308	  break;
2309
2310	case BASE_OCTAL:
2311	  if (!(flags & FLAGS_NILPADDING) || (count == 0))
2312	    self->OutStream(self, '0');
2313	  break;
2314
2315	case BASE_HEX:
2316	  self->OutStream(self, '0');
2317	  self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2318	  break;
2319
2320	default:
2321	  break;
2322	} /* switch base */
2323    }
2324
2325  /* Output prefixed zero padding if needed */
2326  if (flags & FLAGS_NILPADDING)
2327    {
2328      if (precision == NO_PRECISION)
2329	precision = width;
2330      while (precision-- > 0)
2331	{
2332	  self->OutStream(self, '0');
2333	  width--;
2334	}
2335    }
2336
2337  if (! ignoreNumber)
2338    {
2339      /* Output the number itself */
2340      while (*(++pointer))
2341	{
2342	  self->OutStream(self, *pointer);
2343	}
2344    }
2345
2346  /* Output trailing spaces if needed */
2347  if (flags & FLAGS_LEFTADJUST)
2348    {
2349      while (width-- > 0)
2350	self->OutStream(self, CHAR_ADJUST);
2351    }
2352}
2353
2354/*************************************************************************
2355 * TrioWriteStringCharacter
2356 *
2357 * Description:
2358 *  Output a single character of a string
2359 */
2360TRIO_PRIVATE void
2361TrioWriteStringCharacter
2362TRIO_ARGS3((self, ch, flags),
2363	   trio_class_t *self,
2364	   int ch,
2365	   trio_flags_t flags)
2366{
2367  if (flags & FLAGS_ALTERNATIVE)
2368    {
2369      if (! isprint(ch))
2370	{
2371	  /*
2372	   * Non-printable characters are converted to C escapes or
2373	   * \number, if no C escape exists.
2374	   */
2375	  self->OutStream(self, CHAR_BACKSLASH);
2376	  switch (ch)
2377	    {
2378	    case '\007': self->OutStream(self, 'a'); break;
2379	    case '\b': self->OutStream(self, 'b'); break;
2380	    case '\f': self->OutStream(self, 'f'); break;
2381	    case '\n': self->OutStream(self, 'n'); break;
2382	    case '\r': self->OutStream(self, 'r'); break;
2383	    case '\t': self->OutStream(self, 't'); break;
2384	    case '\v': self->OutStream(self, 'v'); break;
2385	    case '\\': self->OutStream(self, '\\'); break;
2386	    default:
2387	      self->OutStream(self, 'x');
2388	      TrioWriteNumber(self, (trio_uintmax_t)ch,
2389			      FLAGS_UNSIGNED | FLAGS_NILPADDING,
2390			      2, 2, BASE_HEX);
2391	      break;
2392	    }
2393	}
2394      else if (ch == CHAR_BACKSLASH)
2395	{
2396	  self->OutStream(self, CHAR_BACKSLASH);
2397	  self->OutStream(self, CHAR_BACKSLASH);
2398	}
2399      else
2400	{
2401	  self->OutStream(self, ch);
2402	}
2403    }
2404  else
2405    {
2406      self->OutStream(self, ch);
2407    }
2408}
2409
2410/*************************************************************************
2411 * TrioWriteString
2412 *
2413 * Description:
2414 *  Output a string
2415 */
2416TRIO_PRIVATE void
2417TrioWriteString
2418TRIO_ARGS5((self, string, flags, width, precision),
2419	   trio_class_t *self,
2420	   TRIO_CONST char *string,
2421	   trio_flags_t flags,
2422	   int width,
2423	   int precision)
2424{
2425  int length;
2426  int ch;
2427
2428  assert(VALID(self));
2429  assert(VALID(self->OutStream));
2430
2431  if (string == NULL)
2432    {
2433      string = internalNullString;
2434      length = sizeof(internalNullString) - 1;
2435      /* Disable quoting for the null pointer */
2436      flags &= (~FLAGS_QUOTE);
2437      width = 0;
2438    }
2439  else
2440    {
2441      length = trio_length(string);
2442    }
2443  if ((NO_PRECISION != precision) &&
2444      (precision < length))
2445    {
2446      length = precision;
2447    }
2448  width -= length;
2449
2450  if (flags & FLAGS_QUOTE)
2451    self->OutStream(self, CHAR_QUOTE);
2452
2453  if (! (flags & FLAGS_LEFTADJUST))
2454    {
2455      while (width-- > 0)
2456	self->OutStream(self, CHAR_ADJUST);
2457    }
2458
2459  while (length-- > 0)
2460    {
2461      /* The ctype parameters must be an unsigned char (or EOF) */
2462      ch = (int)((unsigned char)(*string++));
2463      TrioWriteStringCharacter(self, ch, flags);
2464    }
2465
2466  if (flags & FLAGS_LEFTADJUST)
2467    {
2468      while (width-- > 0)
2469	self->OutStream(self, CHAR_ADJUST);
2470    }
2471  if (flags & FLAGS_QUOTE)
2472    self->OutStream(self, CHAR_QUOTE);
2473}
2474
2475/*************************************************************************
2476 * TrioWriteWideStringCharacter
2477 *
2478 * Description:
2479 *  Output a wide string as a multi-byte sequence
2480 */
2481#if TRIO_WIDECHAR
2482TRIO_PRIVATE int
2483TrioWriteWideStringCharacter
2484TRIO_ARGS4((self, wch, flags, width),
2485	   trio_class_t *self,
2486	   trio_wchar_t wch,
2487	   trio_flags_t flags,
2488	   int width)
2489{
2490  int size;
2491  int i;
2492  int ch;
2493  char *string;
2494  char buffer[MB_LEN_MAX + 1];
2495
2496  if (width == NO_WIDTH)
2497    width = sizeof(buffer);
2498
2499  size = wctomb(buffer, wch);
2500  if ((size <= 0) || (size > width) || (buffer[0] == NIL))
2501    return 0;
2502
2503  string = buffer;
2504  i = size;
2505  while ((width >= i) && (width-- > 0) && (i-- > 0))
2506    {
2507      /* The ctype parameters must be an unsigned char (or EOF) */
2508      ch = (int)((unsigned char)(*string++));
2509      TrioWriteStringCharacter(self, ch, flags);
2510    }
2511  return size;
2512}
2513#endif /* TRIO_WIDECHAR */
2514
2515/*************************************************************************
2516 * TrioWriteWideString
2517 *
2518 * Description:
2519 *  Output a wide character string as a multi-byte string
2520 */
2521#if TRIO_WIDECHAR
2522TRIO_PRIVATE void
2523TrioWriteWideString
2524TRIO_ARGS5((self, wstring, flags, width, precision),
2525	   trio_class_t *self,
2526	   TRIO_CONST trio_wchar_t *wstring,
2527	   trio_flags_t flags,
2528	   int width,
2529	   int precision)
2530{
2531  int length;
2532  int size;
2533
2534  assert(VALID(self));
2535  assert(VALID(self->OutStream));
2536
2537#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
2538  (void)mblen(NULL, 0);
2539#endif
2540
2541  if (wstring == NULL)
2542    {
2543      TrioWriteString(self, NULL, flags, width, precision);
2544      return;
2545    }
2546
2547  if (NO_PRECISION == precision)
2548    {
2549      length = INT_MAX;
2550    }
2551  else
2552    {
2553      length = precision;
2554      width -= length;
2555    }
2556
2557  if (flags & FLAGS_QUOTE)
2558    self->OutStream(self, CHAR_QUOTE);
2559
2560  if (! (flags & FLAGS_LEFTADJUST))
2561    {
2562      while (width-- > 0)
2563	self->OutStream(self, CHAR_ADJUST);
2564    }
2565
2566  while (length > 0)
2567    {
2568      size = TrioWriteWideStringCharacter(self, *wstring++, flags, length);
2569      if (size == 0)
2570	break; /* while */
2571      length -= size;
2572    }
2573
2574  if (flags & FLAGS_LEFTADJUST)
2575    {
2576      while (width-- > 0)
2577	self->OutStream(self, CHAR_ADJUST);
2578    }
2579  if (flags & FLAGS_QUOTE)
2580    self->OutStream(self, CHAR_QUOTE);
2581}
2582#endif /* TRIO_WIDECHAR */
2583
2584/*************************************************************************
2585 * TrioWriteDouble
2586 *
2587 * http://wwwold.dkuug.dk/JTC1/SC22/WG14/www/docs/dr_211.htm
2588 *
2589 * "5.2.4.2.2 paragraph #4
2590 *
2591 *  The accuracy [...] is implementation defined, as is the accuracy
2592 *  of the conversion between floating-point internal representations
2593 *  and string representations performed by the libray routine in
2594 *  <stdio.h>"
2595 */
2596/* FIXME: handle all instances of constant long-double number (L)
2597 *   and *l() math functions.
2598 */
2599TRIO_PRIVATE void
2600TrioWriteDouble
2601TRIO_ARGS6((self, number, flags, width, precision, base),
2602	   trio_class_t *self,
2603	   trio_long_double_t number,
2604	   trio_flags_t flags,
2605	   int width,
2606	   int precision,
2607	   int base)
2608{
2609  trio_long_double_t integerNumber;
2610  trio_long_double_t fractionNumber;
2611  trio_long_double_t workNumber;
2612  int integerDigits;
2613  int fractionDigits;
2614  int exponentDigits;
2615  int baseDigits;
2616  int integerThreshold;
2617  int fractionThreshold;
2618  int expectedWidth;
2619  int exponent = 0;
2620  unsigned int uExponent = 0;
2621  int exponentBase;
2622  trio_long_double_t dblBase;
2623  trio_long_double_t dblIntegerBase;
2624  trio_long_double_t dblFractionBase;
2625  trio_long_double_t integerAdjust;
2626  trio_long_double_t fractionAdjust;
2627  BOOLEAN_T isNegative;
2628  BOOLEAN_T isExponentNegative = FALSE;
2629  BOOLEAN_T requireTwoDigitExponent;
2630  BOOLEAN_T isHex;
2631  TRIO_CONST char *digits;
2632  char *groupingPointer;
2633  int i;
2634  int index;
2635  BOOLEAN_T hasOnlyZeroes;
2636  int zeroes = 0;
2637  register int trailingZeroes;
2638  BOOLEAN_T keepTrailingZeroes;
2639  BOOLEAN_T keepDecimalPoint;
2640  trio_long_double_t epsilon;
2641
2642  assert(VALID(self));
2643  assert(VALID(self->OutStream));
2644  assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE));
2645
2646  /* Determine sign and look for special quantities */
2647  switch (trio_fpclassify_and_signbit(number, &isNegative))
2648    {
2649    case TRIO_FP_NAN:
2650      TrioWriteString(self,
2651		      (flags & FLAGS_UPPER)
2652		      ? NAN_UPPER
2653		      : NAN_LOWER,
2654		      flags, width, precision);
2655      return;
2656
2657    case TRIO_FP_INFINITE:
2658      if (isNegative)
2659	{
2660	  /* Negative infinity */
2661	  TrioWriteString(self,
2662			  (flags & FLAGS_UPPER)
2663			  ? "-" INFINITE_UPPER
2664			  : "-" INFINITE_LOWER,
2665			  flags, width, precision);
2666	  return;
2667	}
2668      else
2669	{
2670	  /* Positive infinity */
2671	  TrioWriteString(self,
2672			  (flags & FLAGS_UPPER)
2673			  ? INFINITE_UPPER
2674			  : INFINITE_LOWER,
2675			  flags, width, precision);
2676	  return;
2677	}
2678
2679    default:
2680      /* Finitude */
2681      break;
2682    }
2683
2684  /* Normal numbers */
2685  if (flags & FLAGS_LONGDOUBLE)
2686    {
2687      baseDigits = (base == 10)
2688	? LDBL_DIG
2689	: (int)floor(LDBL_MANT_DIG / TrioLogarithmBase(base));
2690      epsilon = LDBL_EPSILON;
2691    }
2692  else if (flags & FLAGS_SHORT)
2693    {
2694      baseDigits = (base == BASE_DECIMAL)
2695	? FLT_DIG
2696	: (int)floor(FLT_MANT_DIG / TrioLogarithmBase(base));
2697      epsilon = FLT_EPSILON;
2698    }
2699  else
2700    {
2701      baseDigits = (base == BASE_DECIMAL)
2702	? DBL_DIG
2703	: (int)floor(DBL_MANT_DIG / TrioLogarithmBase(base));
2704      epsilon = DBL_EPSILON;
2705    }
2706
2707  digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
2708  isHex = (base == BASE_HEX);
2709  if (base == NO_BASE)
2710    base = BASE_DECIMAL;
2711  dblBase = (trio_long_double_t)base;
2712  keepTrailingZeroes = !( (flags & FLAGS_ROUNDING) ||
2713			  ( (flags & FLAGS_FLOAT_G) &&
2714			    !(flags & FLAGS_ALTERNATIVE) ) );
2715
2716  if (flags & FLAGS_ROUNDING)
2717    precision = baseDigits;
2718
2719  if (precision == NO_PRECISION)
2720    {
2721      if (isHex)
2722	{
2723	  keepTrailingZeroes = FALSE;
2724	  precision = FLT_MANT_DIG;
2725	}
2726      else
2727	{
2728	  precision = FLT_DIG;
2729	}
2730    }
2731
2732  if (isNegative)
2733    number = -number;
2734
2735  if (isHex)
2736    flags |= FLAGS_FLOAT_E;
2737
2738  if (flags & FLAGS_FLOAT_G)
2739    {
2740      if (precision == 0)
2741	precision = 1;
2742
2743      if ((number < 1.0E-4) || (number > powl(base,
2744					      (trio_long_double_t)precision)))
2745	{
2746	  /* Use scientific notation */
2747	  flags |= FLAGS_FLOAT_E;
2748	}
2749      else if (number < 1.0)
2750	{
2751	  /*
2752	   * Use normal notation. If the integer part of the number is
2753	   * zero, then adjust the precision to include leading fractional
2754	   * zeros.
2755	   */
2756	  workNumber = TrioLogarithm(number, base);
2757	  workNumber = TRIO_FABS(workNumber);
2758	  if (workNumber - floorl(workNumber) < 0.001)
2759	    workNumber--;
2760	  zeroes = (int)floorl(workNumber);
2761	}
2762    }
2763
2764  if (flags & FLAGS_FLOAT_E)
2765    {
2766      /* Scale the number */
2767      workNumber = TrioLogarithm(number, base);
2768      if (trio_isinf(workNumber) == -1)
2769	{
2770	  exponent = 0;
2771	  /* Undo setting */
2772	  if (flags & FLAGS_FLOAT_G)
2773	    flags &= ~FLAGS_FLOAT_E;
2774	}
2775      else
2776	{
2777	  exponent = (int)floorl(workNumber);
2778	  number /= powl(dblBase, (trio_long_double_t)exponent);
2779	  isExponentNegative = (exponent < 0);
2780	  uExponent = (isExponentNegative) ? -exponent : exponent;
2781	  if (isHex)
2782	    uExponent *= 4; /* log16(2) */
2783	  /* No thousand separators */
2784	  flags &= ~FLAGS_QUOTE;
2785	}
2786    }
2787
2788  integerNumber = floorl(number);
2789  fractionNumber = number - integerNumber;
2790
2791  /*
2792   * Truncated number.
2793   *
2794   * Precision is number of significant digits for FLOAT_G
2795   * and number of fractional digits for others.
2796   */
2797  integerDigits = (integerNumber > epsilon)
2798    ? 1 + (int)TrioLogarithm(integerNumber, base)
2799    : 1;
2800  fractionDigits = ((flags & FLAGS_FLOAT_G) && (zeroes == 0))
2801    ? precision - integerDigits
2802    : zeroes + precision;
2803
2804  dblFractionBase = TrioPower(base, fractionDigits);
2805
2806  workNumber = number + 0.5 / dblFractionBase;
2807  if (floorl(number) != floorl(workNumber))
2808    {
2809      if (flags & FLAGS_FLOAT_E)
2810	{
2811	  /* Adjust if number was rounded up one digit (ie. 0.99 to 1.00) */
2812	  exponent++;
2813	  isExponentNegative = (exponent < 0);
2814	  uExponent = (isExponentNegative) ? -exponent : exponent;
2815	  if (isHex)
2816	    uExponent *= 4; /* log16(2) */
2817	  workNumber = (number + 0.5 / dblFractionBase) / dblBase;
2818	  integerNumber = floorl(workNumber);
2819	  fractionNumber = workNumber - integerNumber;
2820	}
2821      else
2822	{
2823	  /* Adjust if number was rounded up one digit (ie. 99 to 100) */
2824	  integerNumber = floorl(number + 0.5);
2825	  fractionNumber = 0.0;
2826	  integerDigits = (integerNumber > epsilon)
2827	    ? 1 + (int)TrioLogarithm(integerNumber, base)
2828	    : 1;
2829	}
2830    }
2831
2832  /* Estimate accuracy */
2833  integerAdjust = fractionAdjust = 0.5;
2834  if (flags & FLAGS_ROUNDING)
2835    {
2836      if (integerDigits > baseDigits)
2837	{
2838	  integerThreshold = baseDigits;
2839	  fractionDigits = 0;
2840	  dblFractionBase = 1.0;
2841	  fractionThreshold = 0;
2842	  precision = 0; /* Disable decimal-point */
2843	  integerAdjust = TrioPower(base, integerDigits - integerThreshold - 1);
2844	  fractionAdjust = 0.0;
2845	}
2846      else
2847	{
2848	  integerThreshold = integerDigits;
2849	  fractionThreshold = fractionDigits - integerThreshold;
2850	  fractionAdjust = 1.0;
2851	}
2852    }
2853  else
2854    {
2855      integerThreshold = INT_MAX;
2856      fractionThreshold = INT_MAX;
2857    }
2858
2859  /*
2860   * Calculate expected width.
2861   *  sign + integer part + thousands separators + decimal point
2862   *  + fraction + exponent
2863   */
2864  fractionAdjust /= dblFractionBase;
2865  hasOnlyZeroes = (floorl((fractionNumber + fractionAdjust) * dblFractionBase) < epsilon);
2866  keepDecimalPoint = ( (flags & FLAGS_ALTERNATIVE) ||
2867		       !((precision == 0) ||
2868			 (!keepTrailingZeroes && hasOnlyZeroes)) );
2869  if (flags & FLAGS_FLOAT_E)
2870    {
2871      exponentDigits = (uExponent == 0)
2872	? 1
2873	: (int)ceil(TrioLogarithm((double)(uExponent + 1),
2874				  (isHex) ? 10.0 : base));
2875    }
2876  else
2877    exponentDigits = 0;
2878  requireTwoDigitExponent = ((base == BASE_DECIMAL) && (exponentDigits == 1));
2879
2880  expectedWidth = integerDigits + fractionDigits
2881    + (keepDecimalPoint
2882       ? internalDecimalPointLength
2883       : 0)
2884    + ((flags & FLAGS_QUOTE)
2885       ? TrioCalcThousandSeparatorLength(integerDigits)
2886       : 0);
2887  if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
2888    expectedWidth += sizeof("-") - 1;
2889  if (exponentDigits > 0)
2890    expectedWidth += exponentDigits +
2891      ((requireTwoDigitExponent ? sizeof("E+0") : sizeof("E+")) - 1);
2892  if (isHex)
2893    expectedWidth += sizeof("0X") - 1;
2894
2895  /* Output prefixing */
2896  if (flags & FLAGS_NILPADDING)
2897    {
2898      /* Leading zeros must be after sign */
2899      if (isNegative)
2900	self->OutStream(self, '-');
2901      else if (flags & FLAGS_SHOWSIGN)
2902	self->OutStream(self, '+');
2903      else if (flags & FLAGS_SPACE)
2904	self->OutStream(self, ' ');
2905      if (isHex)
2906	{
2907	  self->OutStream(self, '0');
2908	  self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2909	}
2910      if (!(flags & FLAGS_LEFTADJUST))
2911	{
2912	  for (i = expectedWidth; i < width; i++)
2913	    {
2914	      self->OutStream(self, '0');
2915	    }
2916	}
2917    }
2918  else
2919    {
2920      /* Leading spaces must be before sign */
2921      if (!(flags & FLAGS_LEFTADJUST))
2922	{
2923	  for (i = expectedWidth; i < width; i++)
2924	    {
2925	      self->OutStream(self, CHAR_ADJUST);
2926	    }
2927	}
2928      if (isNegative)
2929	self->OutStream(self, '-');
2930      else if (flags & FLAGS_SHOWSIGN)
2931	self->OutStream(self, '+');
2932      else if (flags & FLAGS_SPACE)
2933	self->OutStream(self, ' ');
2934      if (isHex)
2935	{
2936	  self->OutStream(self, '0');
2937	  self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2938	}
2939    }
2940
2941  /* Output the integer part and thousand separators */
2942  dblIntegerBase = 1.0 / TrioPower(base, integerDigits - 1);
2943  for (i = 0; i < integerDigits; i++)
2944    {
2945      workNumber = floorl(((integerNumber + integerAdjust) * dblIntegerBase));
2946      if (i > integerThreshold)
2947	{
2948	  /* Beyond accuracy */
2949	  self->OutStream(self, digits[0]);
2950	}
2951      else
2952	{
2953	  self->OutStream(self, digits[(int)fmodl(workNumber, dblBase)]);
2954	}
2955      dblIntegerBase *= dblBase;
2956
2957      if (((flags & (FLAGS_FLOAT_E | FLAGS_QUOTE)) == FLAGS_QUOTE)
2958	  && TrioFollowedBySeparator(integerDigits - i))
2959	{
2960	  for (groupingPointer = internalThousandSeparator;
2961	       *groupingPointer != NIL;
2962	       groupingPointer++)
2963	    {
2964	      self->OutStream(self, *groupingPointer);
2965	    }
2966	}
2967    }
2968
2969  /* Insert decimal point and build the fraction part */
2970  trailingZeroes = 0;
2971
2972  if (keepDecimalPoint)
2973    {
2974      if (internalDecimalPoint)
2975	{
2976	  self->OutStream(self, internalDecimalPoint);
2977	}
2978      else
2979	{
2980	  for (i = 0; i < internalDecimalPointLength; i++)
2981	    {
2982	      self->OutStream(self, internalDecimalPointString[i]);
2983	    }
2984	}
2985    }
2986
2987  for (i = 0; i < fractionDigits; i++)
2988    {
2989      if ((integerDigits > integerThreshold) || (i > fractionThreshold))
2990	{
2991	  /* Beyond accuracy */
2992	  trailingZeroes++;
2993	}
2994      else
2995	{
2996	  fractionNumber *= dblBase;
2997	  fractionAdjust *= dblBase;
2998	  workNumber = floorl(fractionNumber + fractionAdjust);
2999	  fractionNumber -= workNumber;
3000	  index = (int)fmodl(workNumber, dblBase);
3001	  if (index == 0)
3002	    {
3003	      trailingZeroes++;
3004	    }
3005	  else
3006	    {
3007	      while (trailingZeroes > 0)
3008		{
3009		  /* Not trailing zeroes after all */
3010		  self->OutStream(self, digits[0]);
3011		  trailingZeroes--;
3012		}
3013	      self->OutStream(self, digits[index]);
3014	    }
3015	}
3016    }
3017
3018  if (keepTrailingZeroes)
3019    {
3020      while (trailingZeroes > 0)
3021	{
3022	  self->OutStream(self, digits[0]);
3023	  trailingZeroes--;
3024	}
3025    }
3026
3027  /* Output exponent */
3028  if (exponentDigits > 0)
3029    {
3030      self->OutStream(self,
3031		      isHex
3032		      ? ((flags & FLAGS_UPPER) ? 'P' : 'p')
3033		      : ((flags & FLAGS_UPPER) ? 'E' : 'e'));
3034      self->OutStream(self, (isExponentNegative) ? '-' : '+');
3035
3036      /* The exponent must contain at least two digits */
3037      if (requireTwoDigitExponent)
3038        self->OutStream(self, '0');
3039
3040      if (isHex)
3041	base = 10.0;
3042      exponentBase = (int)TrioPower(base, exponentDigits - 1);
3043      for (i = 0; i < exponentDigits; i++)
3044	{
3045	  self->OutStream(self, digits[(uExponent / exponentBase) % base]);
3046	  exponentBase /= base;
3047	}
3048    }
3049  /* Output trailing spaces */
3050  if (flags & FLAGS_LEFTADJUST)
3051    {
3052      for (i = expectedWidth; i < width; i++)
3053	{
3054	  self->OutStream(self, CHAR_ADJUST);
3055	}
3056    }
3057}
3058
3059/*************************************************************************
3060 * TrioFormatProcess
3061 *
3062 * Description:
3063 *  This is the main engine for formatting output
3064 */
3065TRIO_PRIVATE int
3066TrioFormatProcess
3067TRIO_ARGS3((data, format, parameters),
3068	   trio_class_t *data,
3069	   TRIO_CONST char *format,
3070	   trio_parameter_t *parameters)
3071{
3072#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
3073  int charlen;
3074#endif
3075  int i;
3076  TRIO_CONST char *string;
3077  trio_pointer_t pointer;
3078  trio_flags_t flags;
3079  int width;
3080  int precision;
3081  int base;
3082  int index;
3083
3084  index = 0;
3085  i = 0;
3086#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
3087  (void)mblen(NULL, 0);
3088#endif
3089
3090  while (format[index])
3091    {
3092#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
3093      if (! isascii(format[index]))
3094	{
3095	  charlen = mblen(&format[index], MB_LEN_MAX);
3096	  /*
3097	   * Only valid multibyte characters are handled here. Invalid
3098	   * multibyte characters (charlen == -1) are handled as normal
3099	   * characters.
3100	   */
3101	  if (charlen != -1)
3102	    {
3103	      while (charlen-- > 0)
3104		{
3105		  data->OutStream(data, format[index++]);
3106		}
3107	      continue; /* while characters left in formatting string */
3108	    }
3109	}
3110#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
3111      if (CHAR_IDENTIFIER == format[index])
3112	{
3113	  if (CHAR_IDENTIFIER == format[index + 1])
3114	    {
3115	      data->OutStream(data, CHAR_IDENTIFIER);
3116	      index += 2;
3117	    }
3118	  else
3119	    {
3120	      /* Skip the parameter entries */
3121	      while (parameters[i].type == FORMAT_PARAMETER)
3122		i++;
3123
3124	      flags = parameters[i].flags;
3125
3126	      /* Find width */
3127	      width = parameters[i].width;
3128	      if (flags & FLAGS_WIDTH_PARAMETER)
3129		{
3130		  /* Get width from parameter list */
3131		  width = (int)parameters[width].data.number.as_signed;
3132		  if (width < 0)
3133		    {
3134		      /*
3135		       * A negative width is the same as the - flag and
3136		       * a positive width.
3137		       */
3138		      flags |= FLAGS_LEFTADJUST;
3139		      flags &= ~FLAGS_NILPADDING;
3140		      width = -width;
3141		    }
3142		}
3143
3144	      /* Find precision */
3145	      if (flags & FLAGS_PRECISION)
3146		{
3147		  precision = parameters[i].precision;
3148		  if (flags & FLAGS_PRECISION_PARAMETER)
3149		    {
3150		      /* Get precision from parameter list */
3151		      precision = (int)parameters[precision].data.number.as_signed;
3152		      if (precision < 0)
3153			{
3154			  /*
3155			   * A negative precision is the same as no
3156			   * precision
3157			   */
3158			  precision = NO_PRECISION;
3159			}
3160		    }
3161		}
3162	      else
3163		{
3164		  precision = NO_PRECISION;
3165		}
3166
3167	      /* Find base */
3168	      base = parameters[i].base;
3169	      if (flags & FLAGS_BASE_PARAMETER)
3170		{
3171		  /* Get base from parameter list */
3172		  base = (int)parameters[base].data.number.as_signed;
3173		}
3174
3175	      switch (parameters[i].type)
3176		{
3177		case FORMAT_CHAR:
3178		  if (flags & FLAGS_QUOTE)
3179		    data->OutStream(data, CHAR_QUOTE);
3180		  if (! (flags & FLAGS_LEFTADJUST))
3181		    {
3182		      while (--width > 0)
3183			data->OutStream(data, CHAR_ADJUST);
3184		    }
3185#if TRIO_WIDECHAR
3186		  if (flags & FLAGS_WIDECHAR)
3187		    {
3188		      TrioWriteWideStringCharacter(data,
3189						   (trio_wchar_t)parameters[i].data.number.as_signed,
3190						   flags,
3191						   NO_WIDTH);
3192		    }
3193		  else
3194#endif
3195		    {
3196		      TrioWriteStringCharacter(data,
3197					       (int)parameters[i].data.number.as_signed,
3198					       flags);
3199		    }
3200
3201		  if (flags & FLAGS_LEFTADJUST)
3202		    {
3203		      while(--width > 0)
3204			data->OutStream(data, CHAR_ADJUST);
3205		    }
3206		  if (flags & FLAGS_QUOTE)
3207		    data->OutStream(data, CHAR_QUOTE);
3208
3209		  break; /* FORMAT_CHAR */
3210
3211		case FORMAT_INT:
3212		  TrioWriteNumber(data,
3213				  parameters[i].data.number.as_unsigned,
3214				  flags,
3215				  width,
3216				  precision,
3217				  base);
3218
3219		  break; /* FORMAT_INT */
3220
3221		case FORMAT_DOUBLE:
3222		  TrioWriteDouble(data,
3223				  parameters[i].data.longdoubleNumber,
3224				  flags,
3225				  width,
3226				  precision,
3227				  base);
3228		  break; /* FORMAT_DOUBLE */
3229
3230		case FORMAT_STRING:
3231#if TRIO_WIDECHAR
3232		  if (flags & FLAGS_WIDECHAR)
3233		    {
3234		      TrioWriteWideString(data,
3235					  parameters[i].data.wstring,
3236					  flags,
3237					  width,
3238					  precision);
3239		    }
3240		  else
3241#endif
3242		    {
3243		      TrioWriteString(data,
3244				      parameters[i].data.string,
3245				      flags,
3246				      width,
3247				      precision);
3248		    }
3249		  break; /* FORMAT_STRING */
3250
3251		case FORMAT_POINTER:
3252		  {
3253		    trio_reference_t reference;
3254
3255		    reference.data = data;
3256		    reference.parameter = &parameters[i];
3257		    trio_print_pointer(&reference, parameters[i].data.pointer);
3258		  }
3259		  break; /* FORMAT_POINTER */
3260
3261		case FORMAT_COUNT:
3262		  pointer = parameters[i].data.pointer;
3263		  if (NULL != pointer)
3264		    {
3265		      /*
3266		       * C99 paragraph 7.19.6.1.8 says "the number of
3267		       * characters written to the output stream so far by
3268		       * this call", which is data->committed
3269		       */
3270#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
3271		      if (flags & FLAGS_SIZE_T)
3272			*(size_t *)pointer = (size_t)data->committed;
3273		      else
3274#endif
3275#if defined(QUALIFIER_PTRDIFF_T)
3276		      if (flags & FLAGS_PTRDIFF_T)
3277			*(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
3278		      else
3279#endif
3280#if defined(QUALIFIER_INTMAX_T)
3281		      if (flags & FLAGS_INTMAX_T)
3282			*(trio_intmax_t *)pointer = (trio_intmax_t)data->committed;
3283		      else
3284#endif
3285		      if (flags & FLAGS_QUAD)
3286			{
3287			  *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->committed;
3288			}
3289		      else if (flags & FLAGS_LONG)
3290			{
3291			  *(long int *)pointer = (long int)data->committed;
3292			}
3293		      else if (flags & FLAGS_SHORT)
3294			{
3295			  *(short int *)pointer = (short int)data->committed;
3296			}
3297		      else
3298			{
3299			  *(int *)pointer = (int)data->committed;
3300			}
3301		    }
3302		  break; /* FORMAT_COUNT */
3303
3304		case FORMAT_PARAMETER:
3305		  break; /* FORMAT_PARAMETER */
3306
3307#if defined(FORMAT_ERRNO)
3308		case FORMAT_ERRNO:
3309		  string = trio_error(parameters[i].data.errorNumber);
3310		  if (string)
3311		    {
3312		      TrioWriteString(data,
3313				      string,
3314				      flags,
3315				      width,
3316				      precision);
3317		    }
3318		  else
3319		    {
3320		      data->OutStream(data, '#');
3321		      TrioWriteNumber(data,
3322				      (trio_uintmax_t)parameters[i].data.errorNumber,
3323				      flags,
3324				      width,
3325				      precision,
3326				      BASE_DECIMAL);
3327		    }
3328		  break; /* FORMAT_ERRNO */
3329#endif /* defined(FORMAT_ERRNO) */
3330
3331#if defined(FORMAT_USER_DEFINED)
3332		case FORMAT_USER_DEFINED:
3333		  {
3334		    trio_reference_t reference;
3335		    trio_userdef_t *def = NULL;
3336
3337		    if (parameters[i].user_name[0] == NIL)
3338		      {
3339			/* Use handle */
3340			if ((i > 0) ||
3341			    (parameters[i - 1].type == FORMAT_PARAMETER))
3342			  def = (trio_userdef_t *)parameters[i - 1].data.pointer;
3343		      }
3344		    else
3345		      {
3346			/* Look up namespace */
3347			def = TrioFindNamespace(parameters[i].user_name, NULL);
3348		      }
3349		    if (def) {
3350		      reference.data = data;
3351		      reference.parameter = &parameters[i];
3352		      def->callback(&reference);
3353		    }
3354		  }
3355		  break;
3356#endif /* defined(FORMAT_USER_DEFINED) */
3357
3358		default:
3359		  break;
3360		} /* switch parameter type */
3361
3362	      /* Prepare for next */
3363	      index = parameters[i].indexAfterSpecifier;
3364	      i++;
3365	    }
3366	}
3367      else /* not identifier */
3368	{
3369	  data->OutStream(data, format[index++]);
3370	}
3371    }
3372  return data->processed;
3373}
3374
3375/*************************************************************************
3376 * TrioFormatRef
3377 */
3378TRIO_PRIVATE int
3379TrioFormatRef
3380TRIO_ARGS4((reference, format, arglist, argarray),
3381	   trio_reference_t *reference,
3382	   TRIO_CONST char *format,
3383	   va_list *arglist,
3384	   trio_pointer_t *argarray)
3385{
3386  int status;
3387  trio_parameter_t parameters[MAX_PARAMETERS];
3388
3389  status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray);
3390  if (status < 0)
3391    return status;
3392
3393  status = TrioFormatProcess(reference->data, format, parameters);
3394  if (reference->data->error != 0)
3395    {
3396      status = reference->data->error;
3397    }
3398  return status;
3399}
3400
3401/*************************************************************************
3402 * TrioFormat
3403 */
3404TRIO_PRIVATE int
3405TrioFormat
3406TRIO_ARGS6((destination, destinationSize, OutStream, format, arglist, argarray),
3407	   trio_pointer_t destination,
3408	   size_t destinationSize,
3409	   void (*OutStream) TRIO_PROTO((trio_class_t *, int)),
3410	   TRIO_CONST char *format,
3411	   va_list *arglist,
3412	   trio_pointer_t *argarray)
3413{
3414  int status;
3415  trio_class_t data;
3416  trio_parameter_t parameters[MAX_PARAMETERS];
3417
3418  assert(VALID(OutStream));
3419  assert(VALID(format));
3420
3421  memset(&data, 0, sizeof(data));
3422  data.OutStream = OutStream;
3423  data.location = destination;
3424  data.max = destinationSize;
3425  data.error = 0;
3426
3427#if defined(USE_LOCALE)
3428  if (NULL == internalLocaleValues)
3429    {
3430      TrioSetLocale();
3431    }
3432#endif
3433
3434  status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray);
3435  if (status < 0)
3436    return status;
3437
3438  status = TrioFormatProcess(&data, format, parameters);
3439  if (data.error != 0)
3440    {
3441      status = data.error;
3442    }
3443  return status;
3444}
3445
3446/*************************************************************************
3447 * TrioOutStreamFile
3448 */
3449TRIO_PRIVATE void
3450TrioOutStreamFile
3451TRIO_ARGS2((self, output),
3452	   trio_class_t *self,
3453	   int output)
3454{
3455  FILE *file;
3456
3457  assert(VALID(self));
3458  assert(VALID(self->location));
3459
3460  file = (FILE *)self->location;
3461  self->processed++;
3462  if (fputc(output, file) == EOF)
3463    {
3464      self->error = TRIO_ERROR_RETURN(TRIO_EOF, 0);
3465    }
3466  else
3467    {
3468      self->committed++;
3469    }
3470}
3471
3472/*************************************************************************
3473 * TrioOutStreamFileDescriptor
3474 */
3475TRIO_PRIVATE void
3476TrioOutStreamFileDescriptor
3477TRIO_ARGS2((self, output),
3478	   trio_class_t *self,
3479	   int output)
3480{
3481  int fd;
3482  char ch;
3483
3484  assert(VALID(self));
3485
3486  fd = *((int *)self->location);
3487  ch = (char)output;
3488  self->processed++;
3489  if (write(fd, &ch, sizeof(char)) == -1)
3490    {
3491      self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0);
3492    }
3493  else
3494    {
3495      self->committed++;
3496    }
3497}
3498
3499/*************************************************************************
3500 * TrioOutStreamCustom
3501 */
3502TRIO_PRIVATE void
3503TrioOutStreamCustom
3504TRIO_ARGS2((self, output),
3505	   trio_class_t *self,
3506	   int output)
3507{
3508  int status;
3509  trio_custom_t *data;
3510
3511  assert(VALID(self));
3512  assert(VALID(self->location));
3513
3514  data = (trio_custom_t *)self->location;
3515  if (data->stream.out)
3516    {
3517      status = (data->stream.out)(data->closure, output);
3518      if (status >= 0)
3519	{
3520	  self->committed++;
3521	}
3522      else
3523	{
3524	  if (self->error == 0)
3525	    {
3526	      self->error = TRIO_ERROR_RETURN(TRIO_ECUSTOM, -status);
3527	    }
3528	}
3529    }
3530  self->processed++;
3531}
3532
3533/*************************************************************************
3534 * TrioOutStreamString
3535 */
3536TRIO_PRIVATE void
3537TrioOutStreamString
3538TRIO_ARGS2((self, output),
3539	   trio_class_t *self,
3540	   int output)
3541{
3542  char **buffer;
3543
3544  assert(VALID(self));
3545  assert(VALID(self->location));
3546
3547  buffer = (char **)self->location;
3548  **buffer = (char)output;
3549  (*buffer)++;
3550  self->processed++;
3551  self->committed++;
3552}
3553
3554/*************************************************************************
3555 * TrioOutStreamStringMax
3556 */
3557TRIO_PRIVATE void
3558TrioOutStreamStringMax
3559TRIO_ARGS2((self, output),
3560	   trio_class_t *self,
3561	   int output)
3562{
3563  char **buffer;
3564
3565  assert(VALID(self));
3566  assert(VALID(self->location));
3567
3568  buffer = (char **)self->location;
3569
3570  if (self->processed < self->max)
3571    {
3572      **buffer = (char)output;
3573      (*buffer)++;
3574      self->committed++;
3575    }
3576  self->processed++;
3577}
3578
3579/*************************************************************************
3580 * TrioOutStreamStringDynamic
3581 */
3582TRIO_PRIVATE void
3583TrioOutStreamStringDynamic
3584TRIO_ARGS2((self, output),
3585	   trio_class_t *self,
3586	   int output)
3587{
3588  assert(VALID(self));
3589  assert(VALID(self->location));
3590
3591  if (self->error == 0)
3592    {
3593      trio_xstring_append_char((trio_string_t *)self->location,
3594			       (char)output);
3595      self->committed++;
3596    }
3597  /* The processed variable must always be increased */
3598  self->processed++;
3599}
3600
3601/*************************************************************************
3602 *
3603 * Formatted printing functions
3604 *
3605 ************************************************************************/
3606
3607#if defined(TRIO_DOCUMENTATION)
3608# include "doc/doc_printf.h"
3609#endif
3610/** @addtogroup Printf
3611    @{
3612*/
3613
3614/*************************************************************************
3615 * printf
3616 */
3617
3618/**
3619   Print to standard output stream.
3620
3621   @param format Formatting string.
3622   @param ... Arguments.
3623   @return Number of printed characters.
3624 */
3625TRIO_PUBLIC int
3626trio_printf
3627TRIO_VARGS2((format, va_alist),
3628	    TRIO_CONST char *format,
3629	    TRIO_VA_DECL)
3630{
3631  int status;
3632  va_list args;
3633
3634  assert(VALID(format));
3635
3636  TRIO_VA_START(args, format);
3637  status = TrioFormat(stdout, 0, TrioOutStreamFile, format, &args, NULL);
3638  TRIO_VA_END(args);
3639  return status;
3640}
3641
3642/**
3643   Print to standard output stream.
3644
3645   @param format Formatting string.
3646   @param args Arguments.
3647   @return Number of printed characters.
3648 */
3649TRIO_PUBLIC int
3650trio_vprintf
3651TRIO_ARGS2((format, args),
3652	   TRIO_CONST char *format,
3653	   va_list args)
3654{
3655  assert(VALID(format));
3656
3657  return TrioFormat(stdout, 0, TrioOutStreamFile, format, &args, NULL);
3658}
3659
3660/**
3661   Print to standard output stream.
3662
3663   @param format Formatting string.
3664   @param args Arguments.
3665   @return Number of printed characters.
3666 */
3667TRIO_PUBLIC int
3668trio_printfv
3669TRIO_ARGS2((format, args),
3670	   TRIO_CONST char *format,
3671	   trio_pointer_t * args)
3672{
3673  assert(VALID(format));
3674
3675  return TrioFormat(stdout, 0, TrioOutStreamFile, format, NULL, args);
3676}
3677
3678/*************************************************************************
3679 * fprintf
3680 */
3681
3682/**
3683   Print to file.
3684
3685   @param file File pointer.
3686   @param format Formatting string.
3687   @param ... Arguments.
3688   @return Number of printed characters.
3689 */
3690TRIO_PUBLIC int
3691trio_fprintf
3692TRIO_VARGS3((file, format, va_alist),
3693	    FILE *file,
3694	    TRIO_CONST char *format,
3695	    TRIO_VA_DECL)
3696{
3697  int status;
3698  va_list args;
3699
3700  assert(VALID(file));
3701  assert(VALID(format));
3702
3703  TRIO_VA_START(args, format);
3704  status = TrioFormat(file, 0, TrioOutStreamFile, format, &args, NULL);
3705  TRIO_VA_END(args);
3706  return status;
3707}
3708
3709/**
3710   Print to file.
3711
3712   @param file File pointer.
3713   @param format Formatting string.
3714   @param args Arguments.
3715   @return Number of printed characters.
3716 */
3717TRIO_PUBLIC int
3718trio_vfprintf
3719TRIO_ARGS3((file, format, args),
3720	   FILE *file,
3721	   TRIO_CONST char *format,
3722	   va_list args)
3723{
3724  assert(VALID(file));
3725  assert(VALID(format));
3726
3727  return TrioFormat(file, 0, TrioOutStreamFile, format, &args, NULL);
3728}
3729
3730/**
3731   Print to file.
3732
3733   @param file File pointer.
3734   @param format Formatting string.
3735   @param args Arguments.
3736   @return Number of printed characters.
3737 */
3738TRIO_PUBLIC int
3739trio_fprintfv
3740TRIO_ARGS3((file, format, args),
3741	   FILE *file,
3742	   TRIO_CONST char *format,
3743	   trio_pointer_t * args)
3744{
3745  assert(VALID(file));
3746  assert(VALID(format));
3747
3748  return TrioFormat(file, 0, TrioOutStreamFile, format, NULL, args);
3749}
3750
3751/*************************************************************************
3752 * dprintf
3753 */
3754
3755/**
3756   Print to file descriptor.
3757
3758   @param fd File descriptor.
3759   @param format Formatting string.
3760   @param ... Arguments.
3761   @return Number of printed characters.
3762 */
3763TRIO_PUBLIC int
3764trio_dprintf
3765TRIO_VARGS3((fd, format, va_alist),
3766	    int fd,
3767	    TRIO_CONST char *format,
3768	    TRIO_VA_DECL)
3769{
3770  int status;
3771  va_list args;
3772
3773  assert(VALID(format));
3774
3775  TRIO_VA_START(args, format);
3776  status = TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, &args, NULL);
3777  TRIO_VA_END(args);
3778  return status;
3779}
3780
3781/**
3782   Print to file descriptor.
3783
3784   @param fd File descriptor.
3785   @param format Formatting string.
3786   @param args Arguments.
3787   @return Number of printed characters.
3788 */
3789TRIO_PUBLIC int
3790trio_vdprintf
3791TRIO_ARGS3((fd, format, args),
3792	   int fd,
3793	   TRIO_CONST char *format,
3794	   va_list args)
3795{
3796  assert(VALID(format));
3797
3798  return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, &args, NULL);
3799}
3800
3801/**
3802   Print to file descriptor.
3803
3804   @param fd File descriptor.
3805   @param format Formatting string.
3806   @param args Arguments.
3807   @return Number of printed characters.
3808 */
3809TRIO_PUBLIC int
3810trio_dprintfv
3811TRIO_ARGS3((fd, format, args),
3812	   int fd,
3813	   TRIO_CONST char *format,
3814	   trio_pointer_t *args)
3815{
3816  assert(VALID(format));
3817
3818  return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, NULL, args);
3819}
3820
3821/*************************************************************************
3822 * cprintf
3823 */
3824TRIO_PUBLIC int
3825trio_cprintf
3826TRIO_VARGS4((stream, closure, format, va_alist),
3827	    trio_outstream_t stream,
3828	    trio_pointer_t closure,
3829	    TRIO_CONST char *format,
3830	    TRIO_VA_DECL)
3831{
3832  int status;
3833  va_list args;
3834  trio_custom_t data;
3835
3836  assert(VALID(stream));
3837  assert(VALID(format));
3838
3839  TRIO_VA_START(args, format);
3840  data.stream.out = stream;
3841  data.closure = closure;
3842  status = TrioFormat(&data, 0, TrioOutStreamCustom, format, &args, NULL);
3843  TRIO_VA_END(args);
3844  return status;
3845}
3846
3847TRIO_PUBLIC int
3848trio_vcprintf
3849TRIO_ARGS4((stream, closure, format, args),
3850	   trio_outstream_t stream,
3851	   trio_pointer_t closure,
3852	   TRIO_CONST char *format,
3853	   va_list args)
3854{
3855  trio_custom_t data;
3856
3857  assert(VALID(stream));
3858  assert(VALID(format));
3859
3860  data.stream.out = stream;
3861  data.closure = closure;
3862  return TrioFormat(&data, 0, TrioOutStreamCustom, format, &args, NULL);
3863}
3864
3865TRIO_PUBLIC int
3866trio_cprintfv
3867TRIO_ARGS4((stream, closure, format, args),
3868	   trio_outstream_t stream,
3869	   trio_pointer_t closure,
3870	   TRIO_CONST char *format,
3871	   void **args)
3872{
3873  trio_custom_t data;
3874
3875  assert(VALID(stream));
3876  assert(VALID(format));
3877
3878  data.stream.out = stream;
3879  data.closure = closure;
3880  return TrioFormat(&data, 0, TrioOutStreamCustom, format, NULL, args);
3881}
3882
3883/*************************************************************************
3884 * sprintf
3885 */
3886
3887/**
3888   Print to string.
3889
3890   @param buffer Output string.
3891   @param format Formatting string.
3892   @param ... Arguments.
3893   @return Number of printed characters.
3894 */
3895TRIO_PUBLIC int
3896trio_sprintf
3897TRIO_VARGS3((buffer, format, va_alist),
3898	    char *buffer,
3899	    TRIO_CONST char *format,
3900	    TRIO_VA_DECL)
3901{
3902  int status;
3903  va_list args;
3904
3905  assert(VALID(buffer));
3906  assert(VALID(format));
3907
3908  TRIO_VA_START(args, format);
3909  status = TrioFormat(&buffer, 0, TrioOutStreamString, format, &args, NULL);
3910  *buffer = NIL; /* Terminate with NIL character */
3911  TRIO_VA_END(args);
3912  return status;
3913}
3914
3915/**
3916   Print to string.
3917
3918   @param buffer Output string.
3919   @param format Formatting string.
3920   @param args Arguments.
3921   @return Number of printed characters.
3922 */
3923TRIO_PUBLIC int
3924trio_vsprintf
3925TRIO_ARGS3((buffer, format, args),
3926	   char *buffer,
3927	   TRIO_CONST char *format,
3928	   va_list args)
3929{
3930  int status;
3931
3932  assert(VALID(buffer));
3933  assert(VALID(format));
3934
3935  status = TrioFormat(&buffer, 0, TrioOutStreamString, format, &args, NULL);
3936  *buffer = NIL;
3937  return status;
3938}
3939
3940/**
3941   Print to string.
3942
3943   @param buffer Output string.
3944   @param format Formatting string.
3945   @param args Arguments.
3946   @return Number of printed characters.
3947 */
3948TRIO_PUBLIC int
3949trio_sprintfv
3950TRIO_ARGS3((buffer, format, args),
3951	   char *buffer,
3952	   TRIO_CONST char *format,
3953	   trio_pointer_t *args)
3954{
3955  int status;
3956
3957  assert(VALID(buffer));
3958  assert(VALID(format));
3959
3960  status = TrioFormat(&buffer, 0, TrioOutStreamString, format, NULL, args);
3961  *buffer = NIL;
3962  return status;
3963}
3964
3965/*************************************************************************
3966 * snprintf
3967 */
3968
3969/**
3970   Print at most @p max characters to string.
3971
3972   @param buffer Output string.
3973   @param max Maximum number of characters to print.
3974   @param format Formatting string.
3975   @param ... Arguments.
3976   @return Number of printed characters.
3977 */
3978TRIO_PUBLIC int
3979trio_snprintf
3980TRIO_VARGS4((buffer, max, format, va_alist),
3981	    char *buffer,
3982	    size_t max,
3983	    TRIO_CONST char *format,
3984	    TRIO_VA_DECL)
3985{
3986  int status;
3987  va_list args;
3988
3989  assert(VALID(buffer));
3990  assert(VALID(format));
3991
3992  TRIO_VA_START(args, format);
3993  status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
3994		      TrioOutStreamStringMax, format, &args, NULL);
3995  if (max > 0)
3996    *buffer = NIL;
3997  TRIO_VA_END(args);
3998  return status;
3999}
4000
4001/**
4002   Print at most @p max characters to string.
4003
4004   @param buffer Output string.
4005   @param max Maximum number of characters to print.
4006   @param format Formatting string.
4007   @param args Arguments.
4008   @return Number of printed characters.
4009 */
4010TRIO_PUBLIC int
4011trio_vsnprintf
4012TRIO_ARGS4((buffer, max, format, args),
4013	   char *buffer,
4014	   size_t max,
4015	   TRIO_CONST char *format,
4016	   va_list args)
4017{
4018  int status;
4019
4020  assert(VALID(buffer));
4021  assert(VALID(format));
4022
4023  status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
4024		      TrioOutStreamStringMax, format, &args, NULL);
4025  if (max > 0)
4026    *buffer = NIL;
4027  return status;
4028}
4029
4030/**
4031   Print at most @p max characters to string.
4032
4033   @param buffer Output string.
4034   @param max Maximum number of characters to print.
4035   @param format Formatting string.
4036   @param args Arguments.
4037   @return Number of printed characters.
4038 */
4039TRIO_PUBLIC int
4040trio_snprintfv
4041TRIO_ARGS4((buffer, max, format, args),
4042	   char *buffer,
4043	   size_t max,
4044	   TRIO_CONST char *format,
4045	   trio_pointer_t *args)
4046{
4047  int status;
4048
4049  assert(VALID(buffer));
4050  assert(VALID(format));
4051
4052  status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
4053		      TrioOutStreamStringMax, format, NULL, args);
4054  if (max > 0)
4055    *buffer = NIL;
4056  return status;
4057}
4058
4059/*************************************************************************
4060 * snprintfcat
4061 * Appends the new string to the buffer string overwriting the '\0'
4062 * character at the end of buffer.
4063 */
4064TRIO_PUBLIC int
4065trio_snprintfcat
4066TRIO_VARGS4((buffer, max, format, va_alist),
4067	    char *buffer,
4068	    size_t max,
4069	    TRIO_CONST char *format,
4070	    TRIO_VA_DECL)
4071{
4072  int status;
4073  va_list args;
4074  size_t buf_len;
4075
4076  TRIO_VA_START(args, format);
4077
4078  assert(VALID(buffer));
4079  assert(VALID(format));
4080
4081  buf_len = trio_length(buffer);
4082  buffer = &buffer[buf_len];
4083
4084  status = TrioFormat(&buffer, max - 1 - buf_len,
4085		      TrioOutStreamStringMax, format, &args, NULL);
4086  TRIO_VA_END(args);
4087  *buffer = NIL;
4088  return status;
4089}
4090
4091TRIO_PUBLIC int
4092trio_vsnprintfcat
4093TRIO_ARGS4((buffer, max, format, args),
4094	   char *buffer,
4095	   size_t max,
4096	   TRIO_CONST char *format,
4097	   va_list args)
4098{
4099  int status;
4100  size_t buf_len;
4101
4102  assert(VALID(buffer));
4103  assert(VALID(format));
4104
4105  buf_len = trio_length(buffer);
4106  buffer = &buffer[buf_len];
4107  status = TrioFormat(&buffer, max - 1 - buf_len,
4108		      TrioOutStreamStringMax, format, &args, NULL);
4109  *buffer = NIL;
4110  return status;
4111}
4112
4113/*************************************************************************
4114 * trio_aprintf
4115 */
4116
4117/* Deprecated */
4118TRIO_PUBLIC char *
4119trio_aprintf
4120TRIO_VARGS2((format, va_alist),
4121	    TRIO_CONST char *format,
4122	    TRIO_VA_DECL)
4123{
4124  va_list args;
4125  trio_string_t *info;
4126  char *result = NULL;
4127
4128  assert(VALID(format));
4129
4130  info = trio_xstring_duplicate("");
4131  if (info)
4132    {
4133      TRIO_VA_START(args, format);
4134      (void)TrioFormat(info, 0, TrioOutStreamStringDynamic,
4135		       format, &args, NULL);
4136      TRIO_VA_END(args);
4137
4138      trio_string_terminate(info);
4139      result = trio_string_extract(info);
4140      trio_string_destroy(info);
4141    }
4142  return result;
4143}
4144
4145/* Deprecated */
4146TRIO_PUBLIC char *
4147trio_vaprintf
4148TRIO_ARGS2((format, args),
4149	   TRIO_CONST char *format,
4150	   va_list args)
4151{
4152  trio_string_t *info;
4153  char *result = NULL;
4154
4155  assert(VALID(format));
4156
4157  info = trio_xstring_duplicate("");
4158  if (info)
4159    {
4160      (void)TrioFormat(info, 0, TrioOutStreamStringDynamic,
4161		       format, &args, NULL);
4162      trio_string_terminate(info);
4163      result = trio_string_extract(info);
4164      trio_string_destroy(info);
4165    }
4166  return result;
4167}
4168
4169TRIO_PUBLIC int
4170trio_asprintf
4171TRIO_VARGS3((result, format, va_alist),
4172	    char **result,
4173	    TRIO_CONST char *format,
4174	    TRIO_VA_DECL)
4175{
4176  va_list args;
4177  int status;
4178  trio_string_t *info;
4179
4180  assert(VALID(format));
4181
4182  *result = NULL;
4183
4184  info = trio_xstring_duplicate("");
4185  if (info == NULL)
4186    {
4187      status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
4188    }
4189  else
4190    {
4191      TRIO_VA_START(args, format);
4192      status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
4193			  format, &args, NULL);
4194      TRIO_VA_END(args);
4195      if (status >= 0)
4196	{
4197	  trio_string_terminate(info);
4198	  *result = trio_string_extract(info);
4199	}
4200      trio_string_destroy(info);
4201    }
4202  return status;
4203}
4204
4205TRIO_PUBLIC int
4206trio_vasprintf
4207TRIO_ARGS3((result, format, args),
4208	   char **result,
4209	   TRIO_CONST char *format,
4210	   va_list args)
4211{
4212  int status;
4213  trio_string_t *info;
4214
4215  assert(VALID(format));
4216
4217  *result = NULL;
4218
4219  info = trio_xstring_duplicate("");
4220  if (info == NULL)
4221    {
4222      status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
4223    }
4224  else
4225    {
4226      status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
4227			  format, &args, NULL);
4228      if (status >= 0)
4229	{
4230	  trio_string_terminate(info);
4231	  *result = trio_string_extract(info);
4232	}
4233      trio_string_destroy(info);
4234    }
4235  return status;
4236}
4237
4238/** @} End of Printf documentation module */
4239
4240/*************************************************************************
4241 *
4242 * CALLBACK
4243 *
4244 ************************************************************************/
4245
4246#if defined(TRIO_DOCUMENTATION)
4247# include "doc/doc_register.h"
4248#endif
4249/**
4250   @addtogroup UserDefined
4251   @{
4252*/
4253
4254#if TRIO_EXTENSION
4255
4256/*************************************************************************
4257 * trio_register
4258 */
4259
4260/**
4261   Register new user-defined specifier.
4262
4263   @param callback
4264   @param name
4265   @return Handle.
4266 */
4267TRIO_PUBLIC trio_pointer_t
4268trio_register
4269TRIO_ARGS2((callback, name),
4270	   trio_callback_t callback,
4271	   TRIO_CONST char *name)
4272{
4273  trio_userdef_t *def;
4274  trio_userdef_t *prev = NULL;
4275
4276  if (callback == NULL)
4277    return NULL;
4278
4279  if (name)
4280    {
4281      /* Handle built-in namespaces */
4282      if (name[0] == ':')
4283	{
4284	  if (trio_equal(name, ":enter"))
4285	    {
4286	      internalEnterCriticalRegion = callback;
4287	    }
4288	  else if (trio_equal(name, ":leave"))
4289	    {
4290	      internalLeaveCriticalRegion = callback;
4291	    }
4292	  return NULL;
4293	}
4294
4295      /* Bail out if namespace is too long */
4296      if (trio_length(name) >= MAX_USER_NAME)
4297	return NULL;
4298
4299      /* Bail out if namespace already is registered */
4300      def = TrioFindNamespace(name, &prev);
4301      if (def)
4302	return NULL;
4303    }
4304
4305  def = (trio_userdef_t *)TRIO_MALLOC(sizeof(trio_userdef_t));
4306  if (def)
4307    {
4308      if (internalEnterCriticalRegion)
4309	(void)internalEnterCriticalRegion(NULL);
4310
4311      if (name)
4312	{
4313	  /* Link into internal list */
4314	  if (prev == NULL)
4315	    internalUserDef = def;
4316	  else
4317	    prev->next = def;
4318	}
4319      /* Initialize */
4320      def->callback = callback;
4321      def->name = (name == NULL)
4322	? NULL
4323	: trio_duplicate(name);
4324      def->next = NULL;
4325
4326      if (internalLeaveCriticalRegion)
4327	(void)internalLeaveCriticalRegion(NULL);
4328    }
4329  return (trio_pointer_t)def;
4330}
4331
4332/**
4333   Unregister an existing user-defined specifier.
4334
4335   @param handle
4336 */
4337void
4338trio_unregister
4339TRIO_ARGS1((handle),
4340	   trio_pointer_t handle)
4341{
4342  trio_userdef_t *self = (trio_userdef_t *)handle;
4343  trio_userdef_t *def;
4344  trio_userdef_t *prev = NULL;
4345
4346  assert(VALID(self));
4347
4348  if (self->name)
4349    {
4350      def = TrioFindNamespace(self->name, &prev);
4351      if (def)
4352	{
4353	  if (internalEnterCriticalRegion)
4354	    (void)internalEnterCriticalRegion(NULL);
4355
4356	  if (prev == NULL)
4357	    internalUserDef = NULL;
4358	  else
4359	    prev->next = def->next;
4360
4361	  if (internalLeaveCriticalRegion)
4362	    (void)internalLeaveCriticalRegion(NULL);
4363	}
4364      trio_destroy(self->name);
4365    }
4366  TRIO_FREE(self);
4367}
4368
4369/*************************************************************************
4370 * trio_get_format [public]
4371 */
4372TRIO_CONST char *
4373trio_get_format
4374TRIO_ARGS1((ref),
4375	   trio_pointer_t ref)
4376{
4377#if defined(FORMAT_USER_DEFINED)
4378  assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED);
4379#endif
4380
4381  return (((trio_reference_t *)ref)->parameter->user_data);
4382}
4383
4384/*************************************************************************
4385 * trio_get_argument [public]
4386 */
4387trio_pointer_t
4388trio_get_argument
4389TRIO_ARGS1((ref),
4390	   trio_pointer_t ref)
4391{
4392#if defined(FORMAT_USER_DEFINED)
4393  assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED);
4394#endif
4395
4396  return ((trio_reference_t *)ref)->parameter->data.pointer;
4397}
4398
4399/*************************************************************************
4400 * trio_get_width / trio_set_width [public]
4401 */
4402int
4403trio_get_width
4404TRIO_ARGS1((ref),
4405	   trio_pointer_t ref)
4406{
4407  return ((trio_reference_t *)ref)->parameter->width;
4408}
4409
4410void
4411trio_set_width
4412TRIO_ARGS2((ref, width),
4413	   trio_pointer_t ref,
4414	   int width)
4415{
4416  ((trio_reference_t *)ref)->parameter->width = width;
4417}
4418
4419/*************************************************************************
4420 * trio_get_precision / trio_set_precision [public]
4421 */
4422int
4423trio_get_precision
4424TRIO_ARGS1((ref),
4425	   trio_pointer_t ref)
4426{
4427  return (((trio_reference_t *)ref)->parameter->precision);
4428}
4429
4430void
4431trio_set_precision
4432TRIO_ARGS2((ref, precision),
4433	   trio_pointer_t ref,
4434	   int precision)
4435{
4436  ((trio_reference_t *)ref)->parameter->precision = precision;
4437}
4438
4439/*************************************************************************
4440 * trio_get_base / trio_set_base [public]
4441 */
4442int
4443trio_get_base
4444TRIO_ARGS1((ref),
4445	   trio_pointer_t ref)
4446{
4447  return (((trio_reference_t *)ref)->parameter->base);
4448}
4449
4450void
4451trio_set_base
4452TRIO_ARGS2((ref, base),
4453	   trio_pointer_t ref,
4454	   int base)
4455{
4456  ((trio_reference_t *)ref)->parameter->base = base;
4457}
4458
4459/*************************************************************************
4460 * trio_get_long / trio_set_long [public]
4461 */
4462int
4463trio_get_long
4464TRIO_ARGS1((ref),
4465	   trio_pointer_t ref)
4466{
4467  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONG)
4468    ? TRUE
4469    : FALSE;
4470}
4471
4472void
4473trio_set_long
4474TRIO_ARGS2((ref, is_long),
4475	   trio_pointer_t ref,
4476	   int is_long)
4477{
4478  if (is_long)
4479    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONG;
4480  else
4481    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONG;
4482}
4483
4484/*************************************************************************
4485 * trio_get_longlong / trio_set_longlong [public]
4486 */
4487int
4488trio_get_longlong
4489TRIO_ARGS1((ref),
4490	   trio_pointer_t ref)
4491{
4492  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUAD)
4493    ? TRUE
4494    : FALSE;
4495}
4496
4497void
4498trio_set_longlong
4499TRIO_ARGS2((ref, is_longlong),
4500	   trio_pointer_t ref,
4501	   int is_longlong)
4502{
4503  if (is_longlong)
4504    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUAD;
4505  else
4506    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUAD;
4507}
4508
4509/*************************************************************************
4510 * trio_get_longdouble / trio_set_longdouble [public]
4511 */
4512int
4513trio_get_longdouble
4514TRIO_ARGS1((ref),
4515	   trio_pointer_t ref)
4516{
4517  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONGDOUBLE)
4518    ? TRUE
4519    : FALSE;
4520}
4521
4522void
4523trio_set_longdouble
4524TRIO_ARGS2((ref, is_longdouble),
4525	   trio_pointer_t ref,
4526	   int is_longdouble)
4527{
4528  if (is_longdouble)
4529    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONGDOUBLE;
4530  else
4531    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONGDOUBLE;
4532}
4533
4534/*************************************************************************
4535 * trio_get_short / trio_set_short [public]
4536 */
4537int
4538trio_get_short
4539TRIO_ARGS1((ref),
4540	   trio_pointer_t ref)
4541{
4542  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORT)
4543    ? TRUE
4544    : FALSE;
4545}
4546
4547void
4548trio_set_short
4549TRIO_ARGS2((ref, is_short),
4550	   trio_pointer_t ref,
4551	   int is_short)
4552{
4553  if (is_short)
4554    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORT;
4555  else
4556    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORT;
4557}
4558
4559/*************************************************************************
4560 * trio_get_shortshort / trio_set_shortshort [public]
4561 */
4562int
4563trio_get_shortshort
4564TRIO_ARGS1((ref),
4565	   trio_pointer_t ref)
4566{
4567  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORTSHORT)
4568    ? TRUE
4569    : FALSE;
4570}
4571
4572void
4573trio_set_shortshort
4574TRIO_ARGS2((ref, is_shortshort),
4575	   trio_pointer_t ref,
4576	   int is_shortshort)
4577{
4578  if (is_shortshort)
4579    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORTSHORT;
4580  else
4581    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORTSHORT;
4582}
4583
4584/*************************************************************************
4585 * trio_get_alternative / trio_set_alternative [public]
4586 */
4587int
4588trio_get_alternative
4589TRIO_ARGS1((ref),
4590	   trio_pointer_t ref)
4591{
4592  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_ALTERNATIVE)
4593    ? TRUE
4594    : FALSE;
4595}
4596
4597void
4598trio_set_alternative
4599TRIO_ARGS2((ref, is_alternative),
4600	   trio_pointer_t ref,
4601	   int is_alternative)
4602{
4603  if (is_alternative)
4604    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_ALTERNATIVE;
4605  else
4606    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_ALTERNATIVE;
4607}
4608
4609/*************************************************************************
4610 * trio_get_alignment / trio_set_alignment [public]
4611 */
4612int
4613trio_get_alignment
4614TRIO_ARGS1((ref),
4615	   trio_pointer_t ref)
4616{
4617  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LEFTADJUST)
4618    ? TRUE
4619    : FALSE;
4620}
4621
4622void
4623trio_set_alignment
4624TRIO_ARGS2((ref, is_leftaligned),
4625	   trio_pointer_t ref,
4626	   int is_leftaligned)
4627{
4628  if (is_leftaligned)
4629    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LEFTADJUST;
4630  else
4631    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LEFTADJUST;
4632}
4633
4634/*************************************************************************
4635 * trio_get_spacing /trio_set_spacing [public]
4636 */
4637int
4638trio_get_spacing
4639TRIO_ARGS1((ref),
4640	   trio_pointer_t ref)
4641{
4642  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SPACE)
4643    ? TRUE
4644    : FALSE;
4645}
4646
4647void
4648trio_set_spacing
4649TRIO_ARGS2((ref, is_space),
4650	   trio_pointer_t ref,
4651	   int is_space)
4652{
4653  if (is_space)
4654    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SPACE;
4655  else
4656    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SPACE;
4657}
4658
4659/*************************************************************************
4660 * trio_get_sign / trio_set_sign [public]
4661 */
4662int
4663trio_get_sign
4664TRIO_ARGS1((ref),
4665	   trio_pointer_t ref)
4666{
4667  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHOWSIGN)
4668    ? TRUE
4669    : FALSE;
4670}
4671
4672void
4673trio_set_sign
4674TRIO_ARGS2((ref, is_sign),
4675	   trio_pointer_t ref,
4676	   int is_sign)
4677{
4678  if (is_sign)
4679    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHOWSIGN;
4680  else
4681    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHOWSIGN;
4682}
4683
4684/*************************************************************************
4685 * trio_get_padding / trio_set_padding [public]
4686 */
4687int
4688trio_get_padding
4689TRIO_ARGS1((ref),
4690	   trio_pointer_t ref)
4691{
4692  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_NILPADDING)
4693    ? TRUE
4694    : FALSE;
4695}
4696
4697void
4698trio_set_padding
4699TRIO_ARGS2((ref, is_padding),
4700	   trio_pointer_t ref,
4701	   int is_padding)
4702{
4703  if (is_padding)
4704    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_NILPADDING;
4705  else
4706    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_NILPADDING;
4707}
4708
4709/*************************************************************************
4710 * trio_get_quote / trio_set_quote [public]
4711 */
4712int
4713trio_get_quote
4714TRIO_ARGS1((ref),
4715	   trio_pointer_t ref)
4716{
4717  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUOTE)
4718    ? TRUE
4719    : FALSE;
4720}
4721
4722void
4723trio_set_quote
4724TRIO_ARGS2((ref, is_quote),
4725	   trio_pointer_t ref,
4726	   int is_quote)
4727{
4728  if (is_quote)
4729    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUOTE;
4730  else
4731    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUOTE;
4732}
4733
4734/*************************************************************************
4735 * trio_get_upper / trio_set_upper [public]
4736 */
4737int
4738trio_get_upper
4739TRIO_ARGS1((ref),
4740	   trio_pointer_t ref)
4741{
4742  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_UPPER)
4743    ? TRUE
4744    : FALSE;
4745}
4746
4747void
4748trio_set_upper
4749TRIO_ARGS2((ref, is_upper),
4750	   trio_pointer_t ref,
4751	   int is_upper)
4752{
4753  if (is_upper)
4754    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_UPPER;
4755  else
4756    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_UPPER;
4757}
4758
4759/*************************************************************************
4760 * trio_get_largest / trio_set_largest [public]
4761 */
4762#if TRIO_C99
4763int
4764trio_get_largest
4765TRIO_ARGS1((ref),
4766	   trio_pointer_t ref)
4767{
4768  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_INTMAX_T)
4769    ? TRUE
4770    : FALSE;
4771}
4772
4773void
4774trio_set_largest
4775TRIO_ARGS2((ref, is_largest),
4776	   trio_pointer_t ref,
4777	   int is_largest)
4778{
4779  if (is_largest)
4780    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_INTMAX_T;
4781  else
4782    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_INTMAX_T;
4783}
4784#endif
4785
4786/*************************************************************************
4787 * trio_get_ptrdiff / trio_set_ptrdiff [public]
4788 */
4789int
4790trio_get_ptrdiff
4791TRIO_ARGS1((ref),
4792	   trio_pointer_t ref)
4793{
4794  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_PTRDIFF_T)
4795    ? TRUE
4796    : FALSE;
4797}
4798
4799void
4800trio_set_ptrdiff
4801TRIO_ARGS2((ref, is_ptrdiff),
4802	   trio_pointer_t ref,
4803	   int is_ptrdiff)
4804{
4805  if (is_ptrdiff)
4806    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_PTRDIFF_T;
4807  else
4808    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_PTRDIFF_T;
4809}
4810
4811/*************************************************************************
4812 * trio_get_size / trio_set_size [public]
4813 */
4814#if TRIO_C99
4815int
4816trio_get_size
4817TRIO_ARGS1((ref),
4818	   trio_pointer_t ref)
4819{
4820  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SIZE_T)
4821    ? TRUE
4822    : FALSE;
4823}
4824
4825void
4826trio_set_size
4827TRIO_ARGS2((ref, is_size),
4828	   trio_pointer_t ref,
4829	   int is_size)
4830{
4831  if (is_size)
4832    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SIZE_T;
4833  else
4834    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SIZE_T;
4835}
4836#endif
4837
4838/*************************************************************************
4839 * trio_print_int [public]
4840 */
4841void
4842trio_print_int
4843TRIO_ARGS2((ref, number),
4844	   trio_pointer_t ref,
4845	   int number)
4846{
4847  trio_reference_t *self = (trio_reference_t *)ref;
4848
4849  TrioWriteNumber(self->data,
4850		  (trio_uintmax_t)number,
4851		  self->parameter->flags,
4852		  self->parameter->width,
4853		  self->parameter->precision,
4854		  self->parameter->base);
4855}
4856
4857/*************************************************************************
4858 * trio_print_uint [public]
4859 */
4860void
4861trio_print_uint
4862TRIO_ARGS2((ref, number),
4863	   trio_pointer_t ref,
4864	   unsigned int number)
4865{
4866  trio_reference_t *self = (trio_reference_t *)ref;
4867
4868  TrioWriteNumber(self->data,
4869		  (trio_uintmax_t)number,
4870		  self->parameter->flags | FLAGS_UNSIGNED,
4871		  self->parameter->width,
4872		  self->parameter->precision,
4873		  self->parameter->base);
4874}
4875
4876/*************************************************************************
4877 * trio_print_double [public]
4878 */
4879void
4880trio_print_double
4881TRIO_ARGS2((ref, number),
4882	   trio_pointer_t ref,
4883	   double number)
4884{
4885  trio_reference_t *self = (trio_reference_t *)ref;
4886
4887  TrioWriteDouble(self->data,
4888		  number,
4889		  self->parameter->flags,
4890		  self->parameter->width,
4891		  self->parameter->precision,
4892		  self->parameter->base);
4893}
4894
4895/*************************************************************************
4896 * trio_print_string [public]
4897 */
4898void
4899trio_print_string
4900TRIO_ARGS2((ref, string),
4901	   trio_pointer_t ref,
4902	   char *string)
4903{
4904  trio_reference_t *self = (trio_reference_t *)ref;
4905
4906  TrioWriteString(self->data,
4907		  string,
4908		  self->parameter->flags,
4909		  self->parameter->width,
4910		  self->parameter->precision);
4911}
4912
4913/*************************************************************************
4914 * trio_print_ref [public]
4915 */
4916int
4917trio_print_ref
4918TRIO_VARGS3((ref, format, va_alist),
4919	    trio_pointer_t ref,
4920	    TRIO_CONST char *format,
4921	    TRIO_VA_DECL)
4922{
4923  int status;
4924  va_list arglist;
4925
4926  assert(VALID(format));
4927
4928  TRIO_VA_START(arglist, format);
4929  status = TrioFormatRef((trio_reference_t *)ref, format, &arglist, NULL);
4930  TRIO_VA_END(arglist);
4931  return status;
4932}
4933
4934/*************************************************************************
4935 * trio_vprint_ref [public]
4936 */
4937int
4938trio_vprint_ref
4939TRIO_ARGS3((ref, format, arglist),
4940	   trio_pointer_t ref,
4941	   TRIO_CONST char *format,
4942	   va_list arglist)
4943{
4944  assert(VALID(format));
4945
4946  return TrioFormatRef((trio_reference_t *)ref, format, &arglist, NULL);
4947}
4948
4949/*************************************************************************
4950 * trio_printv_ref [public]
4951 */
4952int
4953trio_printv_ref
4954TRIO_ARGS3((ref, format, argarray),
4955	   trio_pointer_t ref,
4956	   TRIO_CONST char *format,
4957	   trio_pointer_t *argarray)
4958{
4959  assert(VALID(format));
4960
4961  return TrioFormatRef((trio_reference_t *)ref, format, NULL, argarray);
4962}
4963
4964#endif /* TRIO_EXTENSION */
4965
4966/*************************************************************************
4967 * trio_print_pointer [public]
4968 */
4969void
4970trio_print_pointer
4971TRIO_ARGS2((ref, pointer),
4972	   trio_pointer_t ref,
4973	   trio_pointer_t pointer)
4974{
4975  trio_reference_t *self = (trio_reference_t *)ref;
4976  trio_flags_t flags;
4977  trio_uintmax_t number;
4978
4979  if (NULL == pointer)
4980    {
4981      TRIO_CONST char *string = internalNullString;
4982      while (*string)
4983	self->data->OutStream(self->data, *string++);
4984    }
4985  else
4986    {
4987      /*
4988       * The subtraction of the null pointer is a workaround
4989       * to avoid a compiler warning. The performance overhead
4990       * is negligible (and likely to be removed by an
4991       * optimizing compiler). The (char *) casting is done
4992       * to please ANSI C++.
4993       */
4994      number = (trio_uintmax_t)((char *)pointer - (char *)0);
4995      /* Shrink to size of pointer */
4996      number &= (trio_uintmax_t)-1;
4997      flags = self->parameter->flags;
4998      flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE |
4999	        FLAGS_NILPADDING);
5000      TrioWriteNumber(self->data,
5001		      number,
5002		      flags,
5003		      POINTER_WIDTH,
5004		      NO_PRECISION,
5005		      BASE_HEX);
5006    }
5007}
5008
5009/** @} End of UserDefined documentation module */
5010
5011/*************************************************************************
5012 *
5013 * LOCALES
5014 *
5015 ************************************************************************/
5016
5017/*************************************************************************
5018 * trio_locale_set_decimal_point
5019 *
5020 * Decimal point can only be one character. The input argument is a
5021 * string to enable multibyte characters. At most MB_LEN_MAX characters
5022 * will be used.
5023 */
5024TRIO_PUBLIC void
5025trio_locale_set_decimal_point
5026TRIO_ARGS1((decimalPoint),
5027	   char *decimalPoint)
5028{
5029#if defined(USE_LOCALE)
5030  if (NULL == internalLocaleValues)
5031    {
5032      TrioSetLocale();
5033    }
5034#endif
5035  internalDecimalPointLength = trio_length(decimalPoint);
5036  if (internalDecimalPointLength == 1)
5037    {
5038      internalDecimalPoint = *decimalPoint;
5039    }
5040  else
5041    {
5042      internalDecimalPoint = NIL;
5043      trio_copy_max(internalDecimalPointString,
5044		    sizeof(internalDecimalPointString),
5045		    decimalPoint);
5046    }
5047}
5048
5049/*************************************************************************
5050 * trio_locale_set_thousand_separator
5051 *
5052 * See trio_locale_set_decimal_point
5053 */
5054TRIO_PUBLIC void
5055trio_locale_set_thousand_separator
5056TRIO_ARGS1((thousandSeparator),
5057	   char *thousandSeparator)
5058{
5059#if defined(USE_LOCALE)
5060  if (NULL == internalLocaleValues)
5061    {
5062      TrioSetLocale();
5063    }
5064#endif
5065  trio_copy_max(internalThousandSeparator,
5066		sizeof(internalThousandSeparator),
5067		thousandSeparator);
5068  internalThousandSeparatorLength = trio_length(internalThousandSeparator);
5069}
5070
5071/*************************************************************************
5072 * trio_locale_set_grouping
5073 *
5074 * Array of bytes. Reversed order.
5075 *
5076 *  CHAR_MAX : No further grouping
5077 *  0        : Repeat last group for the remaining digits (not necessary
5078 *             as C strings are zero-terminated)
5079 *  n        : Set current group to n
5080 *
5081 * Same order as the grouping attribute in LC_NUMERIC.
5082 */
5083TRIO_PUBLIC void
5084trio_locale_set_grouping
5085TRIO_ARGS1((grouping),
5086	   char *grouping)
5087{
5088#if defined(USE_LOCALE)
5089  if (NULL == internalLocaleValues)
5090    {
5091      TrioSetLocale();
5092    }
5093#endif
5094  trio_copy_max(internalGrouping,
5095		sizeof(internalGrouping),
5096		grouping);
5097}
5098
5099
5100/*************************************************************************
5101 *
5102 * SCANNING
5103 *
5104 ************************************************************************/
5105
5106/*************************************************************************
5107 * TrioSkipWhitespaces
5108 */
5109TRIO_PRIVATE int
5110TrioSkipWhitespaces
5111TRIO_ARGS1((self),
5112	   trio_class_t *self)
5113{
5114  int ch;
5115
5116  ch = self->current;
5117  while (isspace(ch))
5118    {
5119      self->InStream(self, &ch);
5120    }
5121  return ch;
5122}
5123
5124/*************************************************************************
5125 * TrioGetCollation
5126 */
5127#if TRIO_EXTENSION
5128TRIO_PRIVATE void
5129TrioGetCollation(TRIO_NOARGS)
5130{
5131  int i;
5132  int j;
5133  int k;
5134  char first[2];
5135  char second[2];
5136
5137  /* This is computationally expensive */
5138  first[1] = NIL;
5139  second[1] = NIL;
5140  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5141    {
5142      k = 0;
5143      first[0] = (char)i;
5144      for (j = 0; j < MAX_CHARACTER_CLASS; j++)
5145	{
5146	  second[0] = (char)j;
5147	  if (trio_equal_locale(first, second))
5148	    internalCollationArray[i][k++] = (char)j;
5149	}
5150      internalCollationArray[i][k] = NIL;
5151    }
5152}
5153#endif
5154
5155/*************************************************************************
5156 * TrioGetCharacterClass
5157 *
5158 * FIXME:
5159 *  multibyte
5160 */
5161TRIO_PRIVATE int
5162TrioGetCharacterClass
5163TRIO_ARGS4((format, indexPointer, flagsPointer, characterclass),
5164	   TRIO_CONST char *format,
5165	   int *indexPointer,
5166	   trio_flags_t *flagsPointer,
5167	   int *characterclass)
5168{
5169  int index = *indexPointer;
5170  int i;
5171  char ch;
5172  char range_begin;
5173  char range_end;
5174
5175  *flagsPointer &= ~FLAGS_EXCLUDE;
5176
5177  if (format[index] == QUALIFIER_CIRCUMFLEX)
5178    {
5179      *flagsPointer |= FLAGS_EXCLUDE;
5180      index++;
5181    }
5182  /*
5183   * If the ungroup character is at the beginning of the scanlist,
5184   * it will be part of the class, and a second ungroup character
5185   * must follow to end the group.
5186   */
5187  if (format[index] == SPECIFIER_UNGROUP)
5188    {
5189      characterclass[(int)SPECIFIER_UNGROUP]++;
5190      index++;
5191    }
5192  /*
5193   * Minus is used to specify ranges. To include minus in the class,
5194   * it must be at the beginning of the list
5195   */
5196  if (format[index] == QUALIFIER_MINUS)
5197    {
5198      characterclass[(int)QUALIFIER_MINUS]++;
5199      index++;
5200    }
5201  /* Collect characters */
5202  for (ch = format[index];
5203       (ch != SPECIFIER_UNGROUP) && (ch != NIL);
5204       ch = format[++index])
5205    {
5206      switch (ch)
5207	{
5208	case QUALIFIER_MINUS: /* Scanlist ranges */
5209
5210	  /*
5211	   * Both C99 and UNIX98 describes ranges as implementation-
5212	   * defined.
5213	   *
5214	   * We support the following behaviour (although this may
5215	   * change as we become wiser)
5216	   * - only increasing ranges, ie. [a-b] but not [b-a]
5217	   * - transitive ranges, ie. [a-b-c] == [a-c]
5218	   * - trailing minus, ie. [a-] is interpreted as an 'a'
5219	   *   and a '-'
5220	   * - duplicates (although we can easily convert these
5221	   *   into errors)
5222	   */
5223	  range_begin = format[index - 1];
5224	  range_end = format[++index];
5225	  if (range_end == SPECIFIER_UNGROUP)
5226	    {
5227	      /* Trailing minus is included */
5228	      characterclass[(int)ch]++;
5229	      ch = range_end;
5230	      break; /* for */
5231	    }
5232	  if (range_end == NIL)
5233	    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5234	  if (range_begin > range_end)
5235	    return TRIO_ERROR_RETURN(TRIO_ERANGE, index);
5236
5237	  for (i = (int)range_begin; i <= (int)range_end; i++)
5238	    characterclass[i]++;
5239
5240	  ch = range_end;
5241	  break;
5242
5243#if TRIO_EXTENSION
5244
5245	case SPECIFIER_GROUP:
5246
5247	  switch (format[index + 1])
5248	    {
5249	    case QUALIFIER_DOT: /* Collating symbol */
5250	      /*
5251	       * FIXME: This will be easier to implement when multibyte
5252	       * characters have been implemented. Until now, we ignore
5253	       * this feature.
5254	       */
5255	      for (i = index + 2; ; i++)
5256		{
5257		  if (format[i] == NIL)
5258		    /* Error in syntax */
5259		    return -1;
5260		  else if (format[i] == QUALIFIER_DOT)
5261		    break; /* for */
5262		}
5263	      if (format[++i] != SPECIFIER_UNGROUP)
5264		return -1;
5265
5266	      index = i;
5267	      break;
5268
5269	    case QUALIFIER_EQUAL: /* Equivalence class expressions */
5270	      {
5271		unsigned int j;
5272		unsigned int k;
5273
5274		if (internalCollationUnconverted)
5275		  {
5276		    /* Lazy evaluation of collation array */
5277		    TrioGetCollation();
5278		    internalCollationUnconverted = FALSE;
5279		  }
5280		for (i = index + 2; ; i++)
5281		  {
5282		    if (format[i] == NIL)
5283		      /* Error in syntax */
5284		      return -1;
5285		    else if (format[i] == QUALIFIER_EQUAL)
5286		      break; /* for */
5287		    else
5288		      {
5289			/* Mark any equivalent character */
5290			k = (unsigned int)format[i];
5291			for (j = 0; internalCollationArray[k][j] != NIL; j++)
5292			  characterclass[(int)internalCollationArray[k][j]]++;
5293		      }
5294		  }
5295		if (format[++i] != SPECIFIER_UNGROUP)
5296		  return -1;
5297
5298		index = i;
5299	      }
5300	      break;
5301
5302	    case QUALIFIER_COLON: /* Character class expressions */
5303
5304	      if (trio_equal_max(CLASS_ALNUM, sizeof(CLASS_ALNUM) - 1,
5305				 &format[index]))
5306		{
5307		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5308		    if (isalnum(i))
5309		      characterclass[i]++;
5310		  index += sizeof(CLASS_ALNUM) - 1;
5311		}
5312	      else if (trio_equal_max(CLASS_ALPHA, sizeof(CLASS_ALPHA) - 1,
5313				      &format[index]))
5314		{
5315		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5316		    if (isalpha(i))
5317		      characterclass[i]++;
5318		  index += sizeof(CLASS_ALPHA) - 1;
5319		}
5320	      else if (trio_equal_max(CLASS_CNTRL, sizeof(CLASS_CNTRL) - 1,
5321				      &format[index]))
5322		{
5323		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5324		    if (iscntrl(i))
5325		      characterclass[i]++;
5326		  index += sizeof(CLASS_CNTRL) - 1;
5327		}
5328	      else if (trio_equal_max(CLASS_DIGIT, sizeof(CLASS_DIGIT) - 1,
5329				      &format[index]))
5330		{
5331		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5332		    if (isdigit(i))
5333		      characterclass[i]++;
5334		  index += sizeof(CLASS_DIGIT) - 1;
5335		}
5336	      else if (trio_equal_max(CLASS_GRAPH, sizeof(CLASS_GRAPH) - 1,
5337				      &format[index]))
5338		{
5339		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5340		    if (isgraph(i))
5341		      characterclass[i]++;
5342		  index += sizeof(CLASS_GRAPH) - 1;
5343		}
5344	      else if (trio_equal_max(CLASS_LOWER, sizeof(CLASS_LOWER) - 1,
5345				      &format[index]))
5346		{
5347		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5348		    if (islower(i))
5349		      characterclass[i]++;
5350		  index += sizeof(CLASS_LOWER) - 1;
5351		}
5352	      else if (trio_equal_max(CLASS_PRINT, sizeof(CLASS_PRINT) - 1,
5353				      &format[index]))
5354		{
5355		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5356		    if (isprint(i))
5357		      characterclass[i]++;
5358		  index += sizeof(CLASS_PRINT) - 1;
5359		}
5360	      else if (trio_equal_max(CLASS_PUNCT, sizeof(CLASS_PUNCT) - 1,
5361				      &format[index]))
5362		{
5363		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5364		    if (ispunct(i))
5365		      characterclass[i]++;
5366		  index += sizeof(CLASS_PUNCT) - 1;
5367		}
5368	      else if (trio_equal_max(CLASS_SPACE, sizeof(CLASS_SPACE) - 1,
5369				      &format[index]))
5370		{
5371		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5372		    if (isspace(i))
5373		      characterclass[i]++;
5374		  index += sizeof(CLASS_SPACE) - 1;
5375		}
5376	      else if (trio_equal_max(CLASS_UPPER, sizeof(CLASS_UPPER) - 1,
5377				      &format[index]))
5378		{
5379		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5380		    if (isupper(i))
5381		      characterclass[i]++;
5382		  index += sizeof(CLASS_UPPER) - 1;
5383		}
5384	      else if (trio_equal_max(CLASS_XDIGIT, sizeof(CLASS_XDIGIT) - 1,
5385				      &format[index]))
5386		{
5387		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5388		    if (isxdigit(i))
5389		      characterclass[i]++;
5390		  index += sizeof(CLASS_XDIGIT) - 1;
5391		}
5392	      else
5393		{
5394		  characterclass[(int)ch]++;
5395		}
5396	      break;
5397
5398	    default:
5399	      characterclass[(int)ch]++;
5400	      break;
5401	    }
5402	  break;
5403
5404#endif /* TRIO_EXTENSION */
5405
5406	default:
5407	  characterclass[(int)ch]++;
5408	  break;
5409	}
5410    }
5411  return 0;
5412}
5413
5414/*************************************************************************
5415 * TrioReadNumber
5416 *
5417 * We implement our own number conversion in preference of strtol and
5418 * strtoul, because we must handle 'long long' and thousand separators.
5419 */
5420TRIO_PRIVATE BOOLEAN_T
5421TrioReadNumber
5422TRIO_ARGS5((self, target, flags, width, base),
5423	   trio_class_t *self,
5424	   trio_uintmax_t *target,
5425	   trio_flags_t flags,
5426	   int width,
5427	   int base)
5428{
5429  trio_uintmax_t number = 0;
5430  int digit;
5431  int count;
5432  BOOLEAN_T isNegative = FALSE;
5433  BOOLEAN_T gotNumber = FALSE;
5434  int j;
5435
5436  assert(VALID(self));
5437  assert(VALID(self->InStream));
5438  assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
5439
5440  if (internalDigitsUnconverted)
5441    {
5442      /* Lazy evaluation of digits array */
5443      memset(internalDigitArray, -1, sizeof(internalDigitArray));
5444      for (j = 0; j < (int)sizeof(internalDigitsLower) - 1; j++)
5445	{
5446	  internalDigitArray[(int)internalDigitsLower[j]] = j;
5447	  internalDigitArray[(int)internalDigitsUpper[j]] = j;
5448	}
5449      internalDigitsUnconverted = FALSE;
5450    }
5451
5452  TrioSkipWhitespaces(self);
5453
5454  if (!(flags & FLAGS_UNSIGNED))
5455    {
5456      /* Leading sign */
5457      if (self->current == '+')
5458	{
5459	  self->InStream(self, NULL);
5460	}
5461      else if (self->current == '-')
5462	{
5463	  self->InStream(self, NULL);
5464	  isNegative = TRUE;
5465	}
5466    }
5467
5468  count = self->processed;
5469
5470  if (flags & FLAGS_ALTERNATIVE)
5471    {
5472      switch (base)
5473	{
5474	case NO_BASE:
5475	case BASE_OCTAL:
5476	case BASE_HEX:
5477	case BASE_BINARY:
5478	  if (self->current == '0')
5479	    {
5480	      self->InStream(self, NULL);
5481	      if (self->current)
5482		{
5483		  if ((base == BASE_HEX) &&
5484		      (trio_to_upper(self->current) == 'X'))
5485		    {
5486		      self->InStream(self, NULL);
5487		    }
5488		  else if ((base == BASE_BINARY) &&
5489			   (trio_to_upper(self->current) == 'B'))
5490		    {
5491		      self->InStream(self, NULL);
5492		    }
5493		}
5494	    }
5495	  else
5496	    return FALSE;
5497	  break;
5498	default:
5499	  break;
5500	}
5501    }
5502
5503  while (((width == NO_WIDTH) || (self->processed - count < width)) &&
5504	 (! ((self->current == EOF) || isspace(self->current))))
5505    {
5506      if (isascii(self->current))
5507	{
5508	  digit = internalDigitArray[self->current];
5509	  /* Abort if digit is not allowed in the specified base */
5510	  if ((digit == -1) || (digit >= base))
5511	    break;
5512	}
5513      else if (flags & FLAGS_QUOTE)
5514	{
5515	  /* Compare with thousands separator */
5516	  for (j = 0; internalThousandSeparator[j] && self->current; j++)
5517	    {
5518	      if (internalThousandSeparator[j] != self->current)
5519		break;
5520
5521	      self->InStream(self, NULL);
5522	    }
5523	  if (internalThousandSeparator[j])
5524	    break; /* Mismatch */
5525	  else
5526	    continue; /* Match */
5527	}
5528      else
5529	break;
5530
5531      number *= base;
5532      number += digit;
5533      gotNumber = TRUE; /* we need at least one digit */
5534
5535      self->InStream(self, NULL);
5536    }
5537
5538  /* Was anything read at all? */
5539  if (!gotNumber)
5540    return FALSE;
5541
5542  if (target)
5543    *target = (isNegative) ? -((trio_intmax_t)number) : number;
5544  return TRUE;
5545}
5546
5547/*************************************************************************
5548 * TrioReadChar
5549 */
5550TRIO_PRIVATE int
5551TrioReadChar
5552TRIO_ARGS4((self, target, flags, width),
5553	   trio_class_t *self,
5554	   char *target,
5555	   trio_flags_t flags,
5556	   int width)
5557{
5558  int i;
5559  char ch;
5560  trio_uintmax_t number;
5561
5562  assert(VALID(self));
5563  assert(VALID(self->InStream));
5564
5565  for (i = 0;
5566       (self->current != EOF) && (i < width);
5567       i++)
5568    {
5569      ch = (char)self->current;
5570      self->InStream(self, NULL);
5571      if ((flags & FLAGS_ALTERNATIVE) && (ch == CHAR_BACKSLASH))
5572	{
5573	  switch (self->current)
5574	    {
5575	    case '\\': ch = '\\'; break;
5576	    case 'a': ch = '\007'; break;
5577	    case 'b': ch = '\b'; break;
5578	    case 'f': ch = '\f'; break;
5579	    case 'n': ch = '\n'; break;
5580	    case 'r': ch = '\r'; break;
5581	    case 't': ch = '\t'; break;
5582	    case 'v': ch = '\v'; break;
5583	    default:
5584	      if (isdigit(self->current))
5585		{
5586		  /* Read octal number */
5587		  if (!TrioReadNumber(self, &number, 0, 3, BASE_OCTAL))
5588		    return 0;
5589		  ch = (char)number;
5590		}
5591	      else if (trio_to_upper(self->current) == 'X')
5592		{
5593		  /* Read hexadecimal number */
5594		  self->InStream(self, NULL);
5595		  if (!TrioReadNumber(self, &number, 0, 2, BASE_HEX))
5596		    return 0;
5597		  ch = (char)number;
5598		}
5599	      else
5600		{
5601		  ch = (char)self->current;
5602		}
5603	      break;
5604	    }
5605	}
5606
5607      if (target)
5608	target[i] = ch;
5609    }
5610  return i + 1;
5611}
5612
5613/*************************************************************************
5614 * TrioReadString
5615 */
5616TRIO_PRIVATE BOOLEAN_T
5617TrioReadString
5618TRIO_ARGS4((self, target, flags, width),
5619	   trio_class_t *self,
5620	   char *target,
5621	   trio_flags_t flags,
5622	   int width)
5623{
5624  int i;
5625
5626  assert(VALID(self));
5627  assert(VALID(self->InStream));
5628
5629  TrioSkipWhitespaces(self);
5630
5631  /*
5632   * Continue until end of string is reached, a whitespace is encountered,
5633   * or width is exceeded
5634   */
5635  for (i = 0;
5636       ((width == NO_WIDTH) || (i < width)) &&
5637       (! ((self->current == EOF) || isspace(self->current)));
5638       i++)
5639    {
5640      if (TrioReadChar(self, (target ? &target[i] : 0), flags, 1) == 0)
5641	break; /* for */
5642    }
5643  if (target)
5644    target[i] = NIL;
5645  return TRUE;
5646}
5647
5648/*************************************************************************
5649 * TrioReadWideChar
5650 */
5651#if TRIO_WIDECHAR
5652TRIO_PRIVATE int
5653TrioReadWideChar
5654TRIO_ARGS4((self, target, flags, width),
5655	   trio_class_t *self,
5656	   trio_wchar_t *target,
5657	   trio_flags_t flags,
5658	   int width)
5659{
5660  int i;
5661  int j;
5662  int size;
5663  int amount = 0;
5664  trio_wchar_t wch;
5665  char buffer[MB_LEN_MAX + 1];
5666
5667  assert(VALID(self));
5668  assert(VALID(self->InStream));
5669
5670  for (i = 0;
5671       (self->current != EOF) && (i < width);
5672       i++)
5673    {
5674      if (isascii(self->current))
5675	{
5676	  if (TrioReadChar(self, buffer, flags, 1) == 0)
5677	    return 0;
5678	  buffer[1] = NIL;
5679	}
5680      else
5681	{
5682	  /*
5683	   * Collect a multibyte character, by enlarging buffer until
5684	   * it contains a fully legal multibyte character, or the
5685	   * buffer is full.
5686	   */
5687	  j = 0;
5688	  do
5689	    {
5690	      buffer[j++] = (char)self->current;
5691	      buffer[j] = NIL;
5692	      self->InStream(self, NULL);
5693	    }
5694	  while ((j < (int)sizeof(buffer)) && (mblen(buffer, (size_t)j) != j));
5695	}
5696      if (target)
5697	{
5698	  size = mbtowc(&wch, buffer, sizeof(buffer));
5699	  if (size > 0)
5700	    target[i] = wch;
5701	}
5702      amount += size;
5703      self->InStream(self, NULL);
5704    }
5705  return amount;
5706}
5707#endif /* TRIO_WIDECHAR */
5708
5709/*************************************************************************
5710 * TrioReadWideString
5711 */
5712#if TRIO_WIDECHAR
5713TRIO_PRIVATE BOOLEAN_T
5714TrioReadWideString
5715TRIO_ARGS4((self, target, flags, width),
5716	   trio_class_t *self,
5717	   trio_wchar_t *target,
5718	   trio_flags_t flags,
5719	   int width)
5720{
5721  int i;
5722  int size;
5723
5724  assert(VALID(self));
5725  assert(VALID(self->InStream));
5726
5727  TrioSkipWhitespaces(self);
5728
5729#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
5730  (void)mblen(NULL, 0);
5731#endif
5732
5733  /*
5734   * Continue until end of string is reached, a whitespace is encountered,
5735   * or width is exceeded
5736   */
5737  for (i = 0;
5738       ((width == NO_WIDTH) || (i < width)) &&
5739       (! ((self->current == EOF) || isspace(self->current)));
5740       )
5741    {
5742      size = TrioReadWideChar(self, &target[i], flags, 1);
5743      if (size == 0)
5744	break; /* for */
5745
5746      i += size;
5747    }
5748  if (target)
5749    target[i] = WCONST('\0');
5750  return TRUE;
5751}
5752#endif /* TRIO_WIDECHAR */
5753
5754/*************************************************************************
5755 * TrioReadGroup
5756 *
5757 * FIXME: characterclass does not work with multibyte characters
5758 */
5759TRIO_PRIVATE BOOLEAN_T
5760TrioReadGroup
5761TRIO_ARGS5((self, target, characterclass, flags, width),
5762	   trio_class_t *self,
5763	   char *target,
5764	   int *characterclass,
5765	   trio_flags_t flags,
5766	   int width)
5767{
5768  int ch;
5769  int i;
5770
5771  assert(VALID(self));
5772  assert(VALID(self->InStream));
5773
5774  ch = self->current;
5775  for (i = 0;
5776       ((width == NO_WIDTH) || (i < width)) &&
5777       (! ((ch == EOF) ||
5778	   (((flags & FLAGS_EXCLUDE) != 0) ^ (characterclass[ch] == 0))));
5779       i++)
5780    {
5781      if (target)
5782	target[i] = (char)ch;
5783      self->InStream(self, &ch);
5784    }
5785
5786  if (target)
5787    target[i] = NIL;
5788  return TRUE;
5789}
5790
5791/*************************************************************************
5792 * TrioReadDouble
5793 *
5794 * FIXME:
5795 *  add long double
5796 *  handle base
5797 */
5798TRIO_PRIVATE BOOLEAN_T
5799TrioReadDouble
5800TRIO_ARGS4((self, target, flags, width),
5801	   trio_class_t *self,
5802	   trio_pointer_t target,
5803	   trio_flags_t flags,
5804	   int width)
5805{
5806  int ch;
5807  char doubleString[512];
5808  int index = 0;
5809  int start;
5810  int j;
5811  BOOLEAN_T isHex = FALSE;
5812
5813  doubleString[0] = 0;
5814
5815  if ((width == NO_WIDTH) || (width > (int)sizeof(doubleString) - 1))
5816    width = sizeof(doubleString) - 1;
5817
5818  TrioSkipWhitespaces(self);
5819
5820  /*
5821   * Read entire double number from stream. trio_to_double requires
5822   * a string as input, but InStream can be anything, so we have to
5823   * collect all characters.
5824   */
5825  ch = self->current;
5826  if ((ch == '+') || (ch == '-'))
5827    {
5828      doubleString[index++] = (char)ch;
5829      self->InStream(self, &ch);
5830      width--;
5831    }
5832
5833  start = index;
5834  switch (ch)
5835    {
5836    case 'n':
5837    case 'N':
5838      /* Not-a-number */
5839      if (index != 0)
5840	break;
5841      /* FALLTHROUGH */
5842    case 'i':
5843    case 'I':
5844      /* Infinity */
5845      while (isalpha(ch) && (index - start < width))
5846	{
5847	  doubleString[index++] = (char)ch;
5848	  self->InStream(self, &ch);
5849	}
5850      doubleString[index] = NIL;
5851
5852      /* Case insensitive string comparison */
5853      if (trio_equal(&doubleString[start], INFINITE_UPPER) ||
5854	  trio_equal(&doubleString[start], LONG_INFINITE_UPPER))
5855	{
5856	  if (flags & FLAGS_LONGDOUBLE)
5857	    {
5858	      if ((start == 1) && (doubleString[0] == '-'))
5859		{
5860		  *((trio_long_double_t *)target) = trio_ninf();
5861		}
5862	      else
5863		{
5864		  *((trio_long_double_t *)target) = trio_pinf();
5865		}
5866	    }
5867	  else
5868	    {
5869	      if ((start == 1) && (doubleString[0] == '-'))
5870		{
5871		  *((double *)target) = trio_ninf();
5872		}
5873	      else
5874		{
5875		  *((double *)target) = trio_pinf();
5876		}
5877	    }
5878	  return TRUE;
5879	}
5880      if (trio_equal(doubleString, NAN_UPPER))
5881	{
5882	  /* NaN must not have a preceeding + nor - */
5883	  if (flags & FLAGS_LONGDOUBLE)
5884	    {
5885	      *((trio_long_double_t *)target) = trio_nan();
5886	    }
5887	  else
5888	    {
5889	      *((double *)target) = trio_nan();
5890	    }
5891	  return TRUE;
5892	}
5893      return FALSE;
5894
5895    case '0':
5896      doubleString[index++] = (char)ch;
5897      self->InStream(self, &ch);
5898      if (trio_to_upper(ch) == 'X')
5899	{
5900	  isHex = TRUE;
5901	  doubleString[index++] = (char)ch;
5902	  self->InStream(self, &ch);
5903	}
5904      break;
5905
5906    default:
5907      break;
5908    }
5909
5910  while ((ch != EOF) && (index - start < width))
5911    {
5912      /* Integer part */
5913      if (isHex ? isxdigit(ch) : isdigit(ch))
5914	{
5915	  doubleString[index++] = (char)ch;
5916	  self->InStream(self, &ch);
5917	}
5918      else if (flags & FLAGS_QUOTE)
5919	{
5920	  /* Compare with thousands separator */
5921	  for (j = 0; internalThousandSeparator[j] && self->current; j++)
5922	    {
5923	      if (internalThousandSeparator[j] != self->current)
5924		break;
5925
5926	      self->InStream(self, &ch);
5927	    }
5928	  if (internalThousandSeparator[j])
5929	    break; /* Mismatch */
5930	  else
5931	    continue; /* Match */
5932	}
5933      else
5934	break; /* while */
5935    }
5936  if (ch == '.')
5937    {
5938      /* Decimal part */
5939      doubleString[index++] = (char)ch;
5940      self->InStream(self, &ch);
5941      while ((isHex ? isxdigit(ch) : isdigit(ch)) &&
5942	     (index - start < width))
5943	{
5944	  doubleString[index++] = (char)ch;
5945	  self->InStream(self, &ch);
5946	}
5947      if (isHex ? (trio_to_upper(ch) == 'P') : (trio_to_upper(ch) == 'E'))
5948	{
5949	  /* Exponent */
5950	  doubleString[index++] = (char)ch;
5951	  self->InStream(self, &ch);
5952	  if ((ch == '+') || (ch == '-'))
5953	    {
5954	      doubleString[index++] = (char)ch;
5955	      self->InStream(self, &ch);
5956	    }
5957	  while (isdigit(ch) && (index - start < width))
5958	    {
5959	      doubleString[index++] = (char)ch;
5960	      self->InStream(self, &ch);
5961	    }
5962	}
5963    }
5964
5965  if ((index == start) || (*doubleString == NIL))
5966    return FALSE;
5967
5968  doubleString[index] = 0;
5969
5970  if (flags & FLAGS_LONGDOUBLE)
5971    {
5972      *((trio_long_double_t *)target) = trio_to_long_double(doubleString, NULL);
5973    }
5974  else
5975    {
5976      *((double *)target) = trio_to_double(doubleString, NULL);
5977    }
5978  return TRUE;
5979}
5980
5981/*************************************************************************
5982 * TrioReadPointer
5983 */
5984TRIO_PRIVATE BOOLEAN_T
5985TrioReadPointer
5986TRIO_ARGS3((self, target, flags),
5987	   trio_class_t *self,
5988	   trio_pointer_t *target,
5989	   trio_flags_t flags)
5990{
5991  trio_uintmax_t number;
5992  char buffer[sizeof(internalNullString)];
5993
5994  flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | FLAGS_NILPADDING);
5995
5996  if (TrioReadNumber(self,
5997		     &number,
5998		     flags,
5999		     POINTER_WIDTH,
6000		     BASE_HEX))
6001    {
6002      /*
6003       * The strange assignment of number is a workaround for a compiler
6004       * warning
6005       */
6006      if (target)
6007	*target = (char *)0 + number;
6008      return TRUE;
6009    }
6010  else if (TrioReadString(self,
6011			  (flags & FLAGS_IGNORE)
6012			  ? NULL
6013			  : buffer,
6014			  0,
6015			  sizeof(internalNullString) - 1))
6016    {
6017      if (trio_equal_case(buffer, internalNullString))
6018	{
6019	  if (target)
6020	    *target = NULL;
6021	  return TRUE;
6022	}
6023    }
6024  return FALSE;
6025}
6026
6027/*************************************************************************
6028 * TrioScanProcess
6029 */
6030TRIO_PRIVATE int
6031TrioScanProcess
6032TRIO_ARGS3((data, format, parameters),
6033	   trio_class_t *data,
6034	   TRIO_CONST char *format,
6035	   trio_parameter_t *parameters)
6036{
6037#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
6038  int charlen;
6039  int cnt;
6040#endif
6041  int assignment;
6042  int ch;
6043  int index; /* Index of format string */
6044  int i; /* Index of current parameter */
6045  trio_flags_t flags;
6046  int width;
6047  int base;
6048  trio_pointer_t pointer;
6049
6050  assignment = 0;
6051  i = 0;
6052  index = 0;
6053  data->InStream(data, &ch);
6054
6055#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
6056  (void)mblen(NULL, 0);
6057#endif
6058
6059  while (format[index])
6060    {
6061#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
6062      if (! isascii(format[index]))
6063	{
6064	  charlen = mblen(&format[index], MB_LEN_MAX);
6065	  if (charlen != -1)
6066	    {
6067	      /* Compare multibyte characters in format string */
6068	      for (cnt = 0; cnt < charlen - 1; cnt++)
6069		{
6070		  if (ch != format[index + cnt])
6071		    {
6072		      return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
6073		    }
6074		  data->InStream(data, &ch);
6075		}
6076	      continue; /* while characters left in formatting string */
6077	    }
6078	}
6079#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
6080
6081      if ((EOF == ch) && (parameters[i].type != FORMAT_COUNT))
6082	{
6083	  return (assignment > 0) ? assignment : EOF;
6084	}
6085
6086      if (CHAR_IDENTIFIER == format[index])
6087	{
6088	  if (CHAR_IDENTIFIER == format[index + 1])
6089	    {
6090	      /* Two % in format matches one % in input stream */
6091	      if (CHAR_IDENTIFIER == ch)
6092		{
6093		  data->InStream(data, &ch);
6094		  index += 2;
6095		  continue; /* while format chars left */
6096		}
6097	      else
6098		return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
6099	    }
6100
6101	  /* Skip the parameter entries */
6102	  while (parameters[i].type == FORMAT_PARAMETER)
6103	    i++;
6104
6105	  flags = parameters[i].flags;
6106	  /* Find width */
6107	  width = parameters[i].width;
6108	  if (flags & FLAGS_WIDTH_PARAMETER)
6109	    {
6110	      /* Get width from parameter list */
6111	      width = (int)parameters[width].data.number.as_signed;
6112	    }
6113	  /* Find base */
6114	  base = parameters[i].base;
6115	  if (flags & FLAGS_BASE_PARAMETER)
6116	    {
6117	      /* Get base from parameter list */
6118	      base = (int)parameters[base].data.number.as_signed;
6119	    }
6120
6121	  switch (parameters[i].type)
6122	    {
6123	    case FORMAT_INT:
6124	      {
6125		trio_uintmax_t number;
6126
6127		if (0 == base)
6128		  base = BASE_DECIMAL;
6129
6130		if (!TrioReadNumber(data,
6131				    &number,
6132				    flags,
6133				    width,
6134				    base))
6135		  return assignment;
6136
6137		if (!(flags & FLAGS_IGNORE))
6138		  {
6139		    assignment++;
6140
6141		    pointer = parameters[i].data.pointer;
6142#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
6143		    if (flags & FLAGS_SIZE_T)
6144		      *(size_t *)pointer = (size_t)number;
6145		    else
6146#endif
6147#if defined(QUALIFIER_PTRDIFF_T)
6148		    if (flags & FLAGS_PTRDIFF_T)
6149		      *(ptrdiff_t *)pointer = (ptrdiff_t)number;
6150		    else
6151#endif
6152#if defined(QUALIFIER_INTMAX_T)
6153		    if (flags & FLAGS_INTMAX_T)
6154		      *(trio_intmax_t *)pointer = (trio_intmax_t)number;
6155		    else
6156#endif
6157		    if (flags & FLAGS_QUAD)
6158		      *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)number;
6159		    else if (flags & FLAGS_LONG)
6160		      *(long int *)pointer = (long int)number;
6161		    else if (flags & FLAGS_SHORT)
6162		      *(short int *)pointer = (short int)number;
6163		    else
6164		      *(int *)pointer = (int)number;
6165		  }
6166	      }
6167	      break; /* FORMAT_INT */
6168
6169	    case FORMAT_STRING:
6170#if TRIO_WIDECHAR
6171	      if (flags & FLAGS_WIDECHAR)
6172		{
6173		  if (!TrioReadWideString(data,
6174					  (flags & FLAGS_IGNORE)
6175					  ? NULL
6176					  : parameters[i].data.wstring,
6177					  flags,
6178					  width))
6179		    return assignment;
6180		}
6181	      else
6182#endif
6183		{
6184		  if (!TrioReadString(data,
6185				      (flags & FLAGS_IGNORE)
6186				      ? NULL
6187				      : parameters[i].data.string,
6188				      flags,
6189				      width))
6190		    return assignment;
6191		}
6192	      if (!(flags & FLAGS_IGNORE))
6193		assignment++;
6194	      break; /* FORMAT_STRING */
6195
6196	    case FORMAT_DOUBLE:
6197	      {
6198		trio_pointer_t pointer;
6199
6200		if (flags & FLAGS_IGNORE)
6201		  {
6202		    pointer = NULL;
6203		  }
6204		else
6205		  {
6206		    pointer = (flags & FLAGS_LONGDOUBLE)
6207		      ? (trio_pointer_t)parameters[i].data.longdoublePointer
6208		      : (trio_pointer_t)parameters[i].data.doublePointer;
6209		  }
6210		if (!TrioReadDouble(data, pointer, flags, width))
6211		  {
6212		    return assignment;
6213		  }
6214		if (!(flags & FLAGS_IGNORE))
6215		  {
6216		    assignment++;
6217		  }
6218		break; /* FORMAT_DOUBLE */
6219	      }
6220	    case FORMAT_GROUP:
6221	      {
6222		int characterclass[MAX_CHARACTER_CLASS + 1];
6223		int rc;
6224
6225		/* Skip over modifiers */
6226		while (format[index] != SPECIFIER_GROUP)
6227		  {
6228		    index++;
6229		  }
6230		/* Skip over group specifier */
6231		index++;
6232
6233		memset(characterclass, 0, sizeof(characterclass));
6234		rc = TrioGetCharacterClass(format,
6235					   &index,
6236					   &flags,
6237					   characterclass);
6238		if (rc < 0)
6239		  return rc;
6240
6241		if (!TrioReadGroup(data,
6242				   (flags & FLAGS_IGNORE)
6243				   ? NULL
6244				   : parameters[i].data.string,
6245				   characterclass,
6246				   flags,
6247				   parameters[i].width))
6248		  return assignment;
6249		if (!(flags & FLAGS_IGNORE))
6250		  assignment++;
6251	      }
6252	      break; /* FORMAT_GROUP */
6253
6254	    case FORMAT_COUNT:
6255	      pointer = parameters[i].data.pointer;
6256	      if (NULL != pointer)
6257		{
6258		  int count = data->committed;
6259		  if (ch != EOF)
6260		    count--; /* a character is read, but is not consumed yet */
6261#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
6262		  if (flags & FLAGS_SIZE_T)
6263		    *(size_t *)pointer = (size_t)count;
6264		  else
6265#endif
6266#if defined(QUALIFIER_PTRDIFF_T)
6267		  if (flags & FLAGS_PTRDIFF_T)
6268		    *(ptrdiff_t *)pointer = (ptrdiff_t)count;
6269		  else
6270#endif
6271#if defined(QUALIFIER_INTMAX_T)
6272		  if (flags & FLAGS_INTMAX_T)
6273		    *(trio_intmax_t *)pointer = (trio_intmax_t)count;
6274		  else
6275#endif
6276		  if (flags & FLAGS_QUAD)
6277		    {
6278		      *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)count;
6279		    }
6280		  else if (flags & FLAGS_LONG)
6281		    {
6282		      *(long int *)pointer = (long int)count;
6283		    }
6284		  else if (flags & FLAGS_SHORT)
6285		    {
6286		      *(short int *)pointer = (short int)count;
6287		    }
6288		  else
6289		    {
6290		      *(int *)pointer = (int)count;
6291		    }
6292		}
6293	      break; /* FORMAT_COUNT */
6294
6295	    case FORMAT_CHAR:
6296#if TRIO_WIDECHAR
6297	      if (flags & FLAGS_WIDECHAR)
6298		{
6299		  if (TrioReadWideChar(data,
6300				       (flags & FLAGS_IGNORE)
6301				       ? NULL
6302				       : parameters[i].data.wstring,
6303				       flags,
6304				       (width == NO_WIDTH) ? 1 : width) == 0)
6305		    return assignment;
6306		}
6307	      else
6308#endif
6309		{
6310		  if (TrioReadChar(data,
6311				   (flags & FLAGS_IGNORE)
6312				   ? NULL
6313				   : parameters[i].data.string,
6314				   flags,
6315				   (width == NO_WIDTH) ? 1 : width) == 0)
6316		    return assignment;
6317		}
6318	      if (!(flags & FLAGS_IGNORE))
6319		assignment++;
6320	      break; /* FORMAT_CHAR */
6321
6322	    case FORMAT_POINTER:
6323	      if (!TrioReadPointer(data,
6324				   (flags & FLAGS_IGNORE)
6325				   ? NULL
6326				   : (trio_pointer_t *)parameters[i].data.pointer,
6327				   flags))
6328		return assignment;
6329	      if (!(flags & FLAGS_IGNORE))
6330		assignment++;
6331	      break; /* FORMAT_POINTER */
6332
6333	    case FORMAT_PARAMETER:
6334	      break; /* FORMAT_PARAMETER */
6335
6336	    default:
6337	      return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
6338	    }
6339	  ch = data->current;
6340	  index = parameters[i].indexAfterSpecifier;
6341	  i++;
6342	}
6343      else /* Not an % identifier */
6344	{
6345	  if (isspace((int)format[index]))
6346	    {
6347	      /* Whitespaces may match any amount of whitespaces */
6348	      ch = TrioSkipWhitespaces(data);
6349	    }
6350	  else if (ch == format[index])
6351	    {
6352	      data->InStream(data, &ch);
6353	    }
6354	  else
6355	    return assignment;
6356
6357	  index++;
6358	}
6359    }
6360  return assignment;
6361}
6362
6363/*************************************************************************
6364 * TrioScan
6365 */
6366TRIO_PRIVATE int
6367TrioScan
6368TRIO_ARGS6((source, sourceSize, InStream, format, arglist, argarray),
6369	   trio_pointer_t source,
6370	   size_t sourceSize,
6371	   void (*InStream) TRIO_PROTO((trio_class_t *, int *)),
6372	   TRIO_CONST char *format,
6373	   va_list *arglist,
6374	   trio_pointer_t *argarray)
6375{
6376  int status;
6377  trio_parameter_t parameters[MAX_PARAMETERS];
6378  trio_class_t data;
6379
6380  assert(VALID(InStream));
6381  assert(VALID(format));
6382
6383  memset(&data, 0, sizeof(data));
6384  data.InStream = InStream;
6385  data.location = (trio_pointer_t)source;
6386  data.max = sourceSize;
6387  data.error = 0;
6388
6389#if defined(USE_LOCALE)
6390  if (NULL == internalLocaleValues)
6391    {
6392      TrioSetLocale();
6393    }
6394#endif
6395
6396  status = TrioParse(TYPE_SCAN, format, parameters, arglist, argarray);
6397  if (status < 0)
6398    return status;
6399
6400  status = TrioScanProcess(&data, format, parameters);
6401  if (data.error != 0)
6402    {
6403      status = data.error;
6404    }
6405  return status;
6406}
6407
6408/*************************************************************************
6409 * TrioInStreamFile
6410 */
6411TRIO_PRIVATE void
6412TrioInStreamFile
6413TRIO_ARGS2((self, intPointer),
6414	   trio_class_t *self,
6415	   int *intPointer)
6416{
6417  FILE *file = (FILE *)self->location;
6418
6419  assert(VALID(self));
6420  assert(VALID(file));
6421
6422  self->current = fgetc(file);
6423  if (self->current == EOF)
6424    {
6425      self->error = (ferror(file))
6426	? TRIO_ERROR_RETURN(TRIO_ERRNO, 0)
6427	: TRIO_ERROR_RETURN(TRIO_EOF, 0);
6428    }
6429  else
6430    {
6431      self->processed++;
6432      self->committed++;
6433    }
6434
6435  if (VALID(intPointer))
6436    {
6437      *intPointer = self->current;
6438    }
6439}
6440
6441/*************************************************************************
6442 * TrioInStreamFileDescriptor
6443 */
6444TRIO_PRIVATE void
6445TrioInStreamFileDescriptor
6446TRIO_ARGS2((self, intPointer),
6447	   trio_class_t *self,
6448	   int *intPointer)
6449{
6450  int fd = *((int *)self->location);
6451  int size;
6452  unsigned char input;
6453
6454  assert(VALID(self));
6455
6456  size = read(fd, &input, sizeof(char));
6457  if (size == -1)
6458    {
6459      self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0);
6460      self->current = EOF;
6461    }
6462  else
6463    {
6464      self->current = (size == 0) ? EOF : input;
6465    }
6466  if (self->current != EOF)
6467    {
6468      self->committed++;
6469      self->processed++;
6470    }
6471
6472  if (VALID(intPointer))
6473    {
6474      *intPointer = self->current;
6475    }
6476}
6477
6478/*************************************************************************
6479 * TrioInStreamCustom
6480 */
6481TRIO_PRIVATE void
6482TrioInStreamCustom
6483TRIO_ARGS2((self, intPointer),
6484	   trio_class_t *self,
6485	   int *intPointer)
6486{
6487  trio_custom_t *data;
6488
6489  assert(VALID(self));
6490  assert(VALID(self->location));
6491
6492  data = (trio_custom_t *)self->location;
6493
6494  self->current = (data->stream.in == NULL)
6495    ? NIL
6496    : (data->stream.in)(data->closure);
6497
6498  if (self->current == NIL)
6499    {
6500      self->current = EOF;
6501    }
6502  else
6503    {
6504      self->processed++;
6505      self->committed++;
6506    }
6507
6508  if (VALID(intPointer))
6509    {
6510      *intPointer = self->current;
6511    }
6512}
6513
6514/*************************************************************************
6515 * TrioInStreamString
6516 */
6517TRIO_PRIVATE void
6518TrioInStreamString
6519TRIO_ARGS2((self, intPointer),
6520	   trio_class_t *self,
6521	   int *intPointer)
6522{
6523  unsigned char **buffer;
6524
6525  assert(VALID(self));
6526  assert(VALID(self->location));
6527
6528  buffer = (unsigned char **)self->location;
6529  self->current = (*buffer)[0];
6530  if (self->current == NIL)
6531    {
6532      self->current = EOF;
6533    }
6534  else
6535    {
6536      (*buffer)++;
6537      self->processed++;
6538      self->committed++;
6539    }
6540
6541  if (VALID(intPointer))
6542    {
6543      *intPointer = self->current;
6544    }
6545}
6546
6547/*************************************************************************
6548 *
6549 * Formatted scanning functions
6550 *
6551 ************************************************************************/
6552
6553#if defined(TRIO_DOCUMENTATION)
6554# include "doc/doc_scanf.h"
6555#endif
6556/** @addtogroup Scanf
6557    @{
6558*/
6559
6560/*************************************************************************
6561 * scanf
6562 */
6563
6564/**
6565   Scan characters from standard input stream.
6566
6567   @param format Formatting string.
6568   @param ... Arguments.
6569   @return Number of scanned characters.
6570 */
6571TRIO_PUBLIC int
6572trio_scanf
6573TRIO_VARGS2((format, va_alist),
6574	    TRIO_CONST char *format,
6575	    TRIO_VA_DECL)
6576{
6577  int status;
6578  va_list args;
6579
6580  assert(VALID(format));
6581
6582  TRIO_VA_START(args, format);
6583  status = TrioScan((trio_pointer_t)stdin, 0,
6584		    TrioInStreamFile,
6585		    format, &args, NULL);
6586  TRIO_VA_END(args);
6587  return status;
6588}
6589
6590TRIO_PUBLIC int
6591trio_vscanf
6592TRIO_ARGS2((format, args),
6593	   TRIO_CONST char *format,
6594	   va_list args)
6595{
6596  assert(VALID(format));
6597
6598  return TrioScan((trio_pointer_t)stdin, 0,
6599		  TrioInStreamFile,
6600		  format, &args, NULL);
6601}
6602
6603TRIO_PUBLIC int
6604trio_scanfv
6605TRIO_ARGS2((format, args),
6606	   TRIO_CONST char *format,
6607	   trio_pointer_t *args)
6608{
6609  assert(VALID(format));
6610
6611  return TrioScan((trio_pointer_t)stdin, 0,
6612		  TrioInStreamFile,
6613		  format, NULL, args);
6614}
6615
6616/*************************************************************************
6617 * fscanf
6618 */
6619TRIO_PUBLIC int
6620trio_fscanf
6621TRIO_VARGS3((file, format, va_alist),
6622	    FILE *file,
6623	    TRIO_CONST char *format,
6624	    TRIO_VA_DECL)
6625{
6626  int status;
6627  va_list args;
6628
6629  assert(VALID(file));
6630  assert(VALID(format));
6631
6632  TRIO_VA_START(args, format);
6633  status = TrioScan((trio_pointer_t)file, 0,
6634		    TrioInStreamFile,
6635		    format, &args, NULL);
6636  TRIO_VA_END(args);
6637  return status;
6638}
6639
6640TRIO_PUBLIC int
6641trio_vfscanf
6642TRIO_ARGS3((file, format, args),
6643	   FILE *file,
6644	   TRIO_CONST char *format,
6645	   va_list args)
6646{
6647  assert(VALID(file));
6648  assert(VALID(format));
6649
6650  return TrioScan((trio_pointer_t)file, 0,
6651		  TrioInStreamFile,
6652		  format, &args, NULL);
6653}
6654
6655TRIO_PUBLIC int
6656trio_fscanfv
6657TRIO_ARGS3((file, format, args),
6658	   FILE *file,
6659	   TRIO_CONST char *format,
6660	   trio_pointer_t *args)
6661{
6662  assert(VALID(file));
6663  assert(VALID(format));
6664
6665  return TrioScan((trio_pointer_t)file, 0,
6666		  TrioInStreamFile,
6667		  format, NULL, args);
6668}
6669
6670/*************************************************************************
6671 * dscanf
6672 */
6673TRIO_PUBLIC int
6674trio_dscanf
6675TRIO_VARGS3((fd, format, va_alist),
6676	    int fd,
6677	    TRIO_CONST char *format,
6678	    TRIO_VA_DECL)
6679{
6680  int status;
6681  va_list args;
6682
6683  assert(VALID(format));
6684
6685  TRIO_VA_START(args, format);
6686  status = TrioScan((trio_pointer_t)&fd, 0,
6687		    TrioInStreamFileDescriptor,
6688		    format, &args, NULL);
6689  TRIO_VA_END(args);
6690  return status;
6691}
6692
6693TRIO_PUBLIC int
6694trio_vdscanf
6695TRIO_ARGS3((fd, format, args),
6696	   int fd,
6697	   TRIO_CONST char *format,
6698	   va_list args)
6699{
6700  assert(VALID(format));
6701
6702  return TrioScan((trio_pointer_t)&fd, 0,
6703		  TrioInStreamFileDescriptor,
6704		  format, &args, NULL);
6705}
6706
6707TRIO_PUBLIC int
6708trio_dscanfv
6709TRIO_ARGS3((fd, format, args),
6710	   int fd,
6711	   TRIO_CONST char *format,
6712	   trio_pointer_t *args)
6713{
6714  assert(VALID(format));
6715
6716  return TrioScan((trio_pointer_t)&fd, 0,
6717		  TrioInStreamFileDescriptor,
6718		  format, NULL, args);
6719}
6720
6721/*************************************************************************
6722 * cscanf
6723 */
6724TRIO_PUBLIC int
6725trio_cscanf
6726TRIO_VARGS4((stream, closure, format, va_alist),
6727	    trio_instream_t stream,
6728	    trio_pointer_t closure,
6729	    TRIO_CONST char *format,
6730	    TRIO_VA_DECL)
6731{
6732  int status;
6733  va_list args;
6734  trio_custom_t data;
6735
6736  assert(VALID(stream));
6737  assert(VALID(format));
6738
6739  TRIO_VA_START(args, format);
6740  data.stream.in = stream;
6741  data.closure = closure;
6742  status = TrioScan(&data, 0, TrioInStreamCustom, format, &args, NULL);
6743  TRIO_VA_END(args);
6744  return status;
6745}
6746
6747TRIO_PUBLIC int
6748trio_vcscanf
6749TRIO_ARGS4((stream, closure, format, args),
6750	   trio_instream_t stream,
6751	   trio_pointer_t closure,
6752	   TRIO_CONST char *format,
6753	   va_list args)
6754{
6755  trio_custom_t data;
6756
6757  assert(VALID(stream));
6758  assert(VALID(format));
6759
6760  data.stream.in = stream;
6761  data.closure = closure;
6762  return TrioScan(&data, 0, TrioInStreamCustom, format, &args, NULL);
6763}
6764
6765TRIO_PUBLIC int
6766trio_cscanfv
6767TRIO_ARGS4((stream, closure, format, args),
6768	   trio_instream_t stream,
6769	   trio_pointer_t closure,
6770	   TRIO_CONST char *format,
6771	   trio_pointer_t *args)
6772{
6773  trio_custom_t data;
6774
6775  assert(VALID(stream));
6776  assert(VALID(format));
6777
6778  data.stream.in = stream;
6779  data.closure = closure;
6780  return TrioScan(&data, 0, TrioInStreamCustom, format, NULL, args);
6781}
6782
6783/*************************************************************************
6784 * sscanf
6785 */
6786TRIO_PUBLIC int
6787trio_sscanf
6788TRIO_VARGS3((buffer, format, va_alist),
6789	    TRIO_CONST char *buffer,
6790	    TRIO_CONST char *format,
6791	    TRIO_VA_DECL)
6792{
6793  int status;
6794  va_list args;
6795
6796  assert(VALID(buffer));
6797  assert(VALID(format));
6798
6799  TRIO_VA_START(args, format);
6800  status = TrioScan((trio_pointer_t)&buffer, 0,
6801		    TrioInStreamString,
6802		    format, &args, NULL);
6803  TRIO_VA_END(args);
6804  return status;
6805}
6806
6807TRIO_PUBLIC int
6808trio_vsscanf
6809TRIO_ARGS3((buffer, format, args),
6810	   TRIO_CONST char *buffer,
6811	   TRIO_CONST char *format,
6812	   va_list args)
6813{
6814  assert(VALID(buffer));
6815  assert(VALID(format));
6816
6817  return TrioScan((trio_pointer_t)&buffer, 0,
6818		  TrioInStreamString,
6819		  format, &args, NULL);
6820}
6821
6822TRIO_PUBLIC int
6823trio_sscanfv
6824TRIO_ARGS3((buffer, format, args),
6825	   TRIO_CONST char *buffer,
6826	   TRIO_CONST char *format,
6827	   trio_pointer_t *args)
6828{
6829  assert(VALID(buffer));
6830  assert(VALID(format));
6831
6832  return TrioScan((trio_pointer_t)&buffer, 0,
6833		  TrioInStreamString,
6834		  format, NULL, args);
6835}
6836
6837/** @} End of Scanf documentation module */
6838
6839/*************************************************************************
6840 * trio_strerror
6841 */
6842TRIO_PUBLIC TRIO_CONST char *
6843trio_strerror
6844TRIO_ARGS1((errorcode),
6845	   int errorcode)
6846{
6847  /* Textual versions of the error codes */
6848  switch (TRIO_ERROR_CODE(errorcode))
6849    {
6850    case TRIO_EOF:
6851      return "End of file";
6852    case TRIO_EINVAL:
6853      return "Invalid argument";
6854    case TRIO_ETOOMANY:
6855      return "Too many arguments";
6856    case TRIO_EDBLREF:
6857      return "Double reference";
6858    case TRIO_EGAP:
6859      return "Reference gap";
6860    case TRIO_ENOMEM:
6861      return "Out of memory";
6862    case TRIO_ERANGE:
6863      return "Invalid range";
6864    case TRIO_ECUSTOM:
6865      return "Custom error";
6866    default:
6867      return "Unknown";
6868    }
6869}
6870