blob: adfd3243422ba0f999c02a9f301249094b3bd19a [file] [log] [blame]
Daniel Veillard92ad2102001-03-27 12:47:33 +00001/*************************************************************************
2 *
3 * $Id$
4 *
5 * Copyright (C) 1998 Bjorn Reese and Daniel Stenberg.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
12 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
13 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
14 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
15 *
16 *************************************************************************
17 *
Bjorn Reese70a9da52001-04-21 16:57:29 +000018 * A note to trio contributors:
19 *
Daniel Veillard92ad2102001-03-27 12:47:33 +000020 * Avoid heap allocation at all costs to ensure that the trio functions
21 * are async-safe. The exceptions are the printf/fprintf functions, which
22 * uses fputc, and the asprintf functions and the <alloc> modifier, which
23 * by design are required to allocate form the heap.
24 *
25 ************************************************************************/
26
Daniel Veillard92ad2102001-03-27 12:47:33 +000027/*
Bjorn Reese70a9da52001-04-21 16:57:29 +000028 * TODO:
Daniel Veillard92ad2102001-03-27 12:47:33 +000029 * - Scan is probably too permissive about its modifiers.
Daniel Veillard92ad2102001-03-27 12:47:33 +000030 * - C escapes in %#[] ?
31 * - Multibyte characters (done for format parsing, except scan groups)
Daniel Veillard92ad2102001-03-27 12:47:33 +000032 * - Complex numbers? (C99 _Complex)
33 * - Boolean values? (C99 _Bool)
Daniel Veillarda48ed3d2003-04-03 15:28:28 +000034 * - C99 NaN(n-char-sequence) missing. The n-char-sequence can be used
35 * to print the mantissa, e.g. NaN(0xc000000000000000)
Daniel Veillard92ad2102001-03-27 12:47:33 +000036 * - Should we support the GNU %a alloc modifier? GNU has an ugly hack
37 * for %a, because C99 used %a for other purposes. If specified as
38 * %as or %a[ it is interpreted as the alloc modifier, otherwise as
39 * the C99 hex-float. This means that you cannot scan %as as a hex-float
40 * immediately followed by an 's'.
Bjorn Reese906ec8a2001-06-05 12:46:33 +000041 * - Scanning of collating symbols.
Daniel Veillard92ad2102001-03-27 12:47:33 +000042 */
43
Daniel Veillard92ad2102001-03-27 12:47:33 +000044/*************************************************************************
Bjorn Reese906ec8a2001-06-05 12:46:33 +000045 * Trio include files
Daniel Veillard92ad2102001-03-27 12:47:33 +000046 */
Bjorn Reese45029602001-08-21 09:23:53 +000047#include "triodef.h"
Daniel Veillard92ad2102001-03-27 12:47:33 +000048#include "trio.h"
Bjorn Reese70a9da52001-04-21 16:57:29 +000049#include "triop.h"
Bjorn Reese45029602001-08-21 09:23:53 +000050#include "trionan.h"
Daniel Veillardb7c29c32002-09-25 22:44:43 +000051#if !defined(TRIO_MINIMAL)
52# include "triostr.h"
Daniel Veillard92ad2102001-03-27 12:47:33 +000053#endif
54
Daniel Veillardb7c29c32002-09-25 22:44:43 +000055/**************************************************************************
56 *
57 * Definitions
58 *
59 *************************************************************************/
60
Daniel Veillarda48ed3d2003-04-03 15:28:28 +000061#include <math.h>
62#include <limits.h>
63#include <float.h>
64
Daniel Veillard59d3ed82007-04-17 12:44:58 +000065#if (defined(__STDC_ISO_10646__) || defined(MB_LEN_MAX) \
66 || defined(USE_MULTIBYTE) || TRIO_WIDECHAR) \
67 && !defined(_WIN32_WCE)
Bjorn Reese906ec8a2001-06-05 12:46:33 +000068# define TRIO_COMPILER_SUPPORTS_MULTIBYTE
69# if !defined(MB_LEN_MAX)
70# define MB_LEN_MAX 6
71# endif
72#endif
73
Daniel Veillarda48ed3d2003-04-03 15:28:28 +000074#if (defined(TRIO_COMPILER_MSVC) && (_MSC_VER >= 1100)) || defined(TRIO_COMPILER_BCB)
75# define TRIO_COMPILER_SUPPORTS_MSVC_INT
76#endif
77
Daniel Veillard59d3ed82007-04-17 12:44:58 +000078#if defined(_WIN32_WCE)
79#include <wincecompat.h>
80#endif
81
Bjorn Reese906ec8a2001-06-05 12:46:33 +000082/*************************************************************************
83 * Generic definitions
84 */
85
86#if !(defined(DEBUG) || defined(NDEBUG))
87# define NDEBUG
88#endif
Daniel Veillarda48ed3d2003-04-03 15:28:28 +000089
Bjorn Reese906ec8a2001-06-05 12:46:33 +000090#include <assert.h>
91#include <ctype.h>
92#if !defined(TRIO_COMPILER_SUPPORTS_C99)
93# define isblank(x) (((x)==32) || ((x)==9))
94#endif
Daniel Veillardb7c29c32002-09-25 22:44:43 +000095#if defined(TRIO_COMPILER_ANCIENT)
96# include <varargs.h>
97#else
98# include <stdarg.h>
99#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000100#include <stddef.h>
Daniel Veillard59d3ed82007-04-17 12:44:58 +0000101
102#ifdef HAVE_ERRNO_H
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000103#include <errno.h>
Daniel Veillard59d3ed82007-04-17 12:44:58 +0000104#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000105
106#ifndef NULL
107# define NULL 0
108#endif
109#define NIL ((char)0)
110#ifndef FALSE
111# define FALSE (1 == 0)
112# define TRUE (! FALSE)
113#endif
114#define BOOLEAN_T int
115
116/* mincore() can be used for debugging purposes */
117#define VALID(x) (NULL != (x))
118
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000119#if TRIO_ERRORS
120 /*
121 * Encode the error code and the position. This is decoded
122 * with TRIO_ERROR_CODE and TRIO_ERROR_POSITION.
123 */
124# define TRIO_ERROR_RETURN(x,y) (- ((x) + ((y) << 8)))
125#else
126# define TRIO_ERROR_RETURN(x,y) (-1)
127#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000128
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +0800129#ifndef VA_LIST_IS_ARRAY
130#define TRIO_VA_LIST_PTR va_list *
131#define TRIO_VA_LIST_ADDR(l) (&(l))
132#define TRIO_VA_LIST_DEREF(l) (*(l))
133#else
134#define TRIO_VA_LIST_PTR va_list
135#define TRIO_VA_LIST_ADDR(l) (l)
136#define TRIO_VA_LIST_DEREF(l) (l)
137#endif
138
Daniel Veillarda48ed3d2003-04-03 15:28:28 +0000139typedef unsigned long trio_flags_t;
140
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000141
142/*************************************************************************
143 * Platform specific definitions
144 */
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +0800145#if defined(TRIO_PLATFORM_UNIX) || defined(TRIO_PLATFORM_OS400)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000146# include <unistd.h>
147# include <signal.h>
148# include <locale.h>
149# define USE_LOCALE
Bjorn Reese026d29f2002-01-19 15:40:18 +0000150#endif /* TRIO_PLATFORM_UNIX */
151#if defined(TRIO_PLATFORM_VMS)
152# include <unistd.h>
153#endif
154#if defined(TRIO_PLATFORM_WIN32)
Daniel Veillard59d3ed82007-04-17 12:44:58 +0000155# if defined(_WIN32_WCE)
156# include <wincecompat.h>
157# else
158# include <io.h>
159# define read _read
160# define write _write
161# endif
Bjorn Reese026d29f2002-01-19 15:40:18 +0000162#endif /* TRIO_PLATFORM_WIN32 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000163
164#if TRIO_WIDECHAR
165# if defined(TRIO_COMPILER_SUPPORTS_ISO94)
166# include <wchar.h>
167# include <wctype.h>
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000168typedef wchar_t trio_wchar_t;
169typedef wint_t trio_wint_t;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000170# else
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000171typedef char trio_wchar_t;
172typedef int trio_wint_t;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000173# define WCONST(x) L ## x
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000174# define WEOF EOF
175# define iswalnum(x) isalnum(x)
176# define iswalpha(x) isalpha(x)
177# define iswblank(x) isblank(x)
178# define iswcntrl(x) iscntrl(x)
179# define iswdigit(x) isdigit(x)
180# define iswgraph(x) isgraph(x)
181# define iswlower(x) islower(x)
182# define iswprint(x) isprint(x)
183# define iswpunct(x) ispunct(x)
184# define iswspace(x) isspace(x)
185# define iswupper(x) isupper(x)
186# define iswxdigit(x) isxdigit(x)
187# endif
188#endif
189
190
191/*************************************************************************
192 * Compiler dependent definitions
193 */
194
195/* Support for long long */
196#ifndef __cplusplus
197# if !defined(USE_LONGLONG)
Bjorn Reese026d29f2002-01-19 15:40:18 +0000198# if defined(TRIO_COMPILER_GCC) && !defined(__STRICT_ANSI__)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000199# define USE_LONGLONG
Bjorn Reese026d29f2002-01-19 15:40:18 +0000200# elif defined(TRIO_COMPILER_SUNPRO)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000201# define USE_LONGLONG
202# elif defined(_LONG_LONG) || defined(_LONGLONG)
203# define USE_LONGLONG
204# endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000205# endif
206#endif
207
208/* The extra long numbers */
209#if defined(USE_LONGLONG)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000210typedef signed long long int trio_longlong_t;
211typedef unsigned long long int trio_ulonglong_t;
Daniel Veillarda48ed3d2003-04-03 15:28:28 +0000212#elif defined(TRIO_COMPILER_SUPPORTS_MSVC_INT)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000213typedef signed __int64 trio_longlong_t;
214typedef unsigned __int64 trio_ulonglong_t;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000215#else
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000216typedef TRIO_SIGNED long int trio_longlong_t;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000217typedef unsigned long int trio_ulonglong_t;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000218#endif
219
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000220/* Maximal and fixed integer types */
221#if defined(TRIO_COMPILER_SUPPORTS_C99)
222# include <stdint.h>
223typedef intmax_t trio_intmax_t;
224typedef uintmax_t trio_uintmax_t;
225typedef int8_t trio_int8_t;
226typedef int16_t trio_int16_t;
227typedef int32_t trio_int32_t;
228typedef int64_t trio_int64_t;
229#elif defined(TRIO_COMPILER_SUPPORTS_UNIX98)
230# include <inttypes.h>
231typedef intmax_t trio_intmax_t;
232typedef uintmax_t trio_uintmax_t;
233typedef int8_t trio_int8_t;
234typedef int16_t trio_int16_t;
235typedef int32_t trio_int32_t;
236typedef int64_t trio_int64_t;
Daniel Veillarda48ed3d2003-04-03 15:28:28 +0000237#elif defined(TRIO_COMPILER_SUPPORTS_MSVC_INT)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000238typedef trio_longlong_t trio_intmax_t;
239typedef trio_ulonglong_t trio_uintmax_t;
240typedef __int8 trio_int8_t;
241typedef __int16 trio_int16_t;
242typedef __int32 trio_int32_t;
243typedef __int64 trio_int64_t;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000244#else
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000245typedef trio_longlong_t trio_intmax_t;
246typedef trio_ulonglong_t trio_uintmax_t;
247# if defined(TRIO_INT8_T)
248typedef TRIO_INT8_T trio_int8_t;
249# else
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000250typedef TRIO_SIGNED char trio_int8_t;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000251# endif
252# if defined(TRIO_INT16_T)
253typedef TRIO_INT16_T trio_int16_t;
254# else
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000255typedef TRIO_SIGNED short trio_int16_t;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000256# endif
257# if defined(TRIO_INT32_T)
258typedef TRIO_INT32_T trio_int32_t;
259# else
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000260typedef TRIO_SIGNED int trio_int32_t;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000261# endif
262# if defined(TRIO_INT64_T)
263typedef TRIO_INT64_T trio_int64_t;
264# else
265typedef trio_longlong_t trio_int64_t;
266# endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000267#endif
268
Daniel Veillard59d3ed82007-04-17 12:44:58 +0000269#if (!(defined(TRIO_COMPILER_SUPPORTS_C99) \
270 || defined(TRIO_COMPILER_SUPPORTS_UNIX01))) \
271 && !defined(_WIN32_WCE)
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000272# define floorl(x) floor((double)(x))
273# define fmodl(x,y) fmod((double)(x),(double)(y))
274# define powl(x,y) pow((double)(x),(double)(y))
275#endif
276
277#define TRIO_FABS(x) (((x) < 0.0) ? -(x) : (x))
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000278
279/*************************************************************************
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000280 * Internal Definitions
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000281 */
282
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000283#ifndef DECIMAL_DIG
284# define DECIMAL_DIG DBL_DIG
285#endif
286
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000287/* Long double sizes */
288#ifdef LDBL_DIG
289# define MAX_MANTISSA_DIGITS LDBL_DIG
290# define MAX_EXPONENT_DIGITS 4
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000291# define MAX_DOUBLE_DIGITS LDBL_MAX_10_EXP
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000292#else
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000293# define MAX_MANTISSA_DIGITS DECIMAL_DIG
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000294# define MAX_EXPONENT_DIGITS 3
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000295# define MAX_DOUBLE_DIGITS DBL_MAX_10_EXP
296#endif
297
298#if defined(TRIO_COMPILER_ANCIENT) || !defined(LDBL_DIG)
299# undef LDBL_DIG
300# undef LDBL_MANT_DIG
301# undef LDBL_EPSILON
302# define LDBL_DIG DBL_DIG
303# define LDBL_MANT_DIG DBL_MANT_DIG
304# define LDBL_EPSILON DBL_EPSILON
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000305#endif
306
307/* The maximal number of digits is for base 2 */
308#define MAX_CHARS_IN(x) (sizeof(x) * CHAR_BIT)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000309/* The width of a pointer. The number of bits in a hex digit is 4 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000310#define POINTER_WIDTH ((sizeof("0x") - 1) + sizeof(trio_pointer_t) * CHAR_BIT / 4)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000311
312/* Infinite and Not-A-Number for floating-point */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000313#define INFINITE_LOWER "inf"
314#define INFINITE_UPPER "INF"
315#define LONG_INFINITE_LOWER "infinite"
316#define LONG_INFINITE_UPPER "INFINITE"
317#define NAN_LOWER "nan"
318#define NAN_UPPER "NAN"
Daniel Veillard92ad2102001-03-27 12:47:33 +0000319
Daniel Richard G5706b6d2012-08-06 11:32:54 +0800320#if !defined(HAVE_ISASCII) && !defined(isascii)
321# define isascii(x) ((unsigned int)(x) < 128)
322#endif
323
Daniel Veillard92ad2102001-03-27 12:47:33 +0000324/* Various constants */
325enum {
326 TYPE_PRINT = 1,
327 TYPE_SCAN = 2,
328
Daniel Veillarda48ed3d2003-04-03 15:28:28 +0000329 /* Flags. FLAGS_LAST must be less than ULONG_MAX */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000330 FLAGS_NEW = 0,
331 FLAGS_STICKY = 1,
332 FLAGS_SPACE = 2 * FLAGS_STICKY,
333 FLAGS_SHOWSIGN = 2 * FLAGS_SPACE,
334 FLAGS_LEFTADJUST = 2 * FLAGS_SHOWSIGN,
335 FLAGS_ALTERNATIVE = 2 * FLAGS_LEFTADJUST,
336 FLAGS_SHORT = 2 * FLAGS_ALTERNATIVE,
337 FLAGS_SHORTSHORT = 2 * FLAGS_SHORT,
338 FLAGS_LONG = 2 * FLAGS_SHORTSHORT,
339 FLAGS_QUAD = 2 * FLAGS_LONG,
340 FLAGS_LONGDOUBLE = 2 * FLAGS_QUAD,
341 FLAGS_SIZE_T = 2 * FLAGS_LONGDOUBLE,
342 FLAGS_PTRDIFF_T = 2 * FLAGS_SIZE_T,
343 FLAGS_INTMAX_T = 2 * FLAGS_PTRDIFF_T,
344 FLAGS_NILPADDING = 2 * FLAGS_INTMAX_T,
345 FLAGS_UNSIGNED = 2 * FLAGS_NILPADDING,
346 FLAGS_UPPER = 2 * FLAGS_UNSIGNED,
347 FLAGS_WIDTH = 2 * FLAGS_UPPER,
348 FLAGS_WIDTH_PARAMETER = 2 * FLAGS_WIDTH,
349 FLAGS_PRECISION = 2 * FLAGS_WIDTH_PARAMETER,
350 FLAGS_PRECISION_PARAMETER = 2 * FLAGS_PRECISION,
351 FLAGS_BASE = 2 * FLAGS_PRECISION_PARAMETER,
352 FLAGS_BASE_PARAMETER = 2 * FLAGS_BASE,
353 FLAGS_FLOAT_E = 2 * FLAGS_BASE_PARAMETER,
354 FLAGS_FLOAT_G = 2 * FLAGS_FLOAT_E,
355 FLAGS_QUOTE = 2 * FLAGS_FLOAT_G,
356 FLAGS_WIDECHAR = 2 * FLAGS_QUOTE,
357 FLAGS_ALLOC = 2 * FLAGS_WIDECHAR,
358 FLAGS_IGNORE = 2 * FLAGS_ALLOC,
359 FLAGS_IGNORE_PARAMETER = 2 * FLAGS_IGNORE,
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000360 FLAGS_VARSIZE_PARAMETER = 2 * FLAGS_IGNORE_PARAMETER,
361 FLAGS_FIXED_SIZE = 2 * FLAGS_VARSIZE_PARAMETER,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +0000362 FLAGS_LAST = FLAGS_FIXED_SIZE,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000363 /* Reused flags */
364 FLAGS_EXCLUDE = FLAGS_SHORT,
Bjorn Reese70a9da52001-04-21 16:57:29 +0000365 FLAGS_USER_DEFINED = FLAGS_IGNORE,
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000366 FLAGS_ROUNDING = FLAGS_INTMAX_T,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000367 /* Compounded flags */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000368 FLAGS_ALL_VARSIZES = FLAGS_LONG | FLAGS_QUAD | FLAGS_INTMAX_T | FLAGS_PTRDIFF_T | FLAGS_SIZE_T,
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000369 FLAGS_ALL_SIZES = FLAGS_ALL_VARSIZES | FLAGS_SHORTSHORT | FLAGS_SHORT,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000370
371 NO_POSITION = -1,
372 NO_WIDTH = 0,
373 NO_PRECISION = -1,
374 NO_SIZE = -1,
375
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000376 /* Do not change these */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000377 NO_BASE = -1,
378 MIN_BASE = 2,
379 MAX_BASE = 36,
380 BASE_BINARY = 2,
381 BASE_OCTAL = 8,
382 BASE_DECIMAL = 10,
383 BASE_HEX = 16,
384
385 /* Maximal number of allowed parameters */
386 MAX_PARAMETERS = 64,
387 /* Maximal number of characters in class */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000388 MAX_CHARACTER_CLASS = UCHAR_MAX + 1,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000389
Bjorn Reese70a9da52001-04-21 16:57:29 +0000390 /* Maximal string lengths for user-defined specifiers */
391 MAX_USER_NAME = 64,
392 MAX_USER_DATA = 256,
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800393
Daniel Veillard92ad2102001-03-27 12:47:33 +0000394 /* Maximal length of locale separator strings */
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000395 MAX_LOCALE_SEPARATOR_LENGTH = MB_LEN_MAX,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000396 /* Maximal number of integers in grouping */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000397 MAX_LOCALE_GROUPS = 64,
398
399 /* Initial size of asprintf buffer */
400 DYNAMIC_START_SIZE = 32
Daniel Veillard92ad2102001-03-27 12:47:33 +0000401};
402
403#define NO_GROUPING ((int)CHAR_MAX)
404
405/* Fundamental formatting parameter types */
406#define FORMAT_UNKNOWN 0
407#define FORMAT_INT 1
408#define FORMAT_DOUBLE 2
409#define FORMAT_CHAR 3
410#define FORMAT_STRING 4
411#define FORMAT_POINTER 5
412#define FORMAT_COUNT 6
413#define FORMAT_PARAMETER 7
414#define FORMAT_GROUP 8
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000415#if TRIO_GNU
Bjorn Reese70a9da52001-04-21 16:57:29 +0000416# define FORMAT_ERRNO 9
417#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000418#if TRIO_EXTENSION
Bjorn Reese70a9da52001-04-21 16:57:29 +0000419# define FORMAT_USER_DEFINED 10
Daniel Veillard92ad2102001-03-27 12:47:33 +0000420#endif
421
422/* Character constants */
423#define CHAR_IDENTIFIER '%'
424#define CHAR_BACKSLASH '\\'
425#define CHAR_QUOTE '\"'
426#define CHAR_ADJUST ' '
427
428/* Character class expressions */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000429#define CLASS_ALNUM "[:alnum:]"
430#define CLASS_ALPHA "[:alpha:]"
431#define CLASS_BLANK "[:blank:]"
432#define CLASS_CNTRL "[:cntrl:]"
433#define CLASS_DIGIT "[:digit:]"
434#define CLASS_GRAPH "[:graph:]"
435#define CLASS_LOWER "[:lower:]"
436#define CLASS_PRINT "[:print:]"
437#define CLASS_PUNCT "[:punct:]"
438#define CLASS_SPACE "[:space:]"
439#define CLASS_UPPER "[:upper:]"
440#define CLASS_XDIGIT "[:xdigit:]"
Daniel Veillard92ad2102001-03-27 12:47:33 +0000441
442/*
443 * SPECIFIERS:
444 *
445 *
446 * a Hex-float
447 * A Hex-float
448 * c Character
449 * C Widechar character (wint_t)
450 * d Decimal
451 * e Float
452 * E Float
453 * F Float
454 * F Float
455 * g Float
456 * G Float
457 * i Integer
458 * m Error message
459 * n Count
460 * o Octal
461 * p Pointer
462 * s String
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000463 * S Widechar string (wchar_t *)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000464 * u Unsigned
465 * x Hex
466 * X Hex
Bjorn Reese70a9da52001-04-21 16:57:29 +0000467 * [] Group
468 * <> User-defined
Daniel Veillard92ad2102001-03-27 12:47:33 +0000469 *
470 * Reserved:
471 *
472 * D Binary Coded Decimal %D(length,precision) (OS/390)
473 */
474#define SPECIFIER_CHAR 'c'
475#define SPECIFIER_STRING 's'
476#define SPECIFIER_DECIMAL 'd'
477#define SPECIFIER_INTEGER 'i'
478#define SPECIFIER_UNSIGNED 'u'
479#define SPECIFIER_OCTAL 'o'
480#define SPECIFIER_HEX 'x'
481#define SPECIFIER_HEX_UPPER 'X'
482#define SPECIFIER_FLOAT_E 'e'
483#define SPECIFIER_FLOAT_E_UPPER 'E'
484#define SPECIFIER_FLOAT_F 'f'
485#define SPECIFIER_FLOAT_F_UPPER 'F'
486#define SPECIFIER_FLOAT_G 'g'
487#define SPECIFIER_FLOAT_G_UPPER 'G'
488#define SPECIFIER_POINTER 'p'
489#define SPECIFIER_GROUP '['
490#define SPECIFIER_UNGROUP ']'
491#define SPECIFIER_COUNT 'n'
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000492#if TRIO_UNIX98
Daniel Veillard92ad2102001-03-27 12:47:33 +0000493# define SPECIFIER_CHAR_UPPER 'C'
494# define SPECIFIER_STRING_UPPER 'S'
495#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000496#if TRIO_C99
Daniel Veillard92ad2102001-03-27 12:47:33 +0000497# define SPECIFIER_HEXFLOAT 'a'
498# define SPECIFIER_HEXFLOAT_UPPER 'A'
499#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000500#if TRIO_GNU
Daniel Veillard92ad2102001-03-27 12:47:33 +0000501# define SPECIFIER_ERRNO 'm'
502#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000503#if TRIO_EXTENSION
Daniel Veillard92ad2102001-03-27 12:47:33 +0000504# define SPECIFIER_BINARY 'b'
505# define SPECIFIER_BINARY_UPPER 'B'
Bjorn Reese70a9da52001-04-21 16:57:29 +0000506# define SPECIFIER_USER_DEFINED_BEGIN '<'
507# define SPECIFIER_USER_DEFINED_END '>'
508# define SPECIFIER_USER_DEFINED_SEPARATOR ':'
Daniel Veillard92ad2102001-03-27 12:47:33 +0000509#endif
510
511/*
512 * QUALIFIERS:
513 *
514 *
515 * Numbers = d,i,o,u,x,X
516 * Float = a,A,e,E,f,F,g,G
517 * String = s
518 * Char = c
519 *
520 *
521 * 9$ Position
522 * Use the 9th parameter. 9 can be any number between 1 and
523 * the maximal argument
524 *
525 * 9 Width
526 * Set width to 9. 9 can be any number, but must not be postfixed
527 * by '$'
528 *
529 * h Short
530 * Numbers:
531 * (unsigned) short int
532 *
533 * hh Short short
534 * Numbers:
535 * (unsigned) char
536 *
537 * l Long
538 * Numbers:
539 * (unsigned) long int
540 * String:
541 * as the S specifier
542 * Char:
543 * as the C specifier
544 *
545 * ll Long Long
546 * Numbers:
547 * (unsigned) long long int
548 *
549 * L Long Double
550 * Float
551 * long double
552 *
553 * # Alternative
554 * Float:
555 * Decimal-point is always present
556 * String:
557 * non-printable characters are handled as \number
558 *
559 * Spacing
560 *
561 * + Sign
562 *
563 * - Alignment
564 *
565 * . Precision
566 *
567 * * Parameter
568 * print: use parameter
569 * scan: no parameter (ignore)
570 *
571 * q Quad
572 *
573 * Z size_t
574 *
575 * w Widechar
576 *
577 * ' Thousands/quote
578 * Numbers:
579 * Integer part grouped in thousands
580 * Binary numbers:
581 * Number grouped in nibbles (4 bits)
582 * String:
583 * Quoted string
584 *
585 * j intmax_t
586 * t prtdiff_t
587 * z size_t
588 *
589 * ! Sticky
590 * @ Parameter (for both print and scan)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000591 *
592 * I n-bit Integer
593 * Numbers:
594 * The following options exists
595 * I8 = 8-bit integer
596 * I16 = 16-bit integer
597 * I32 = 32-bit integer
598 * I64 = 64-bit integer
Daniel Veillard92ad2102001-03-27 12:47:33 +0000599 */
600#define QUALIFIER_POSITION '$'
601#define QUALIFIER_SHORT 'h'
602#define QUALIFIER_LONG 'l'
603#define QUALIFIER_LONG_UPPER 'L'
604#define QUALIFIER_ALTERNATIVE '#'
605#define QUALIFIER_SPACE ' '
606#define QUALIFIER_PLUS '+'
607#define QUALIFIER_MINUS '-'
608#define QUALIFIER_DOT '.'
609#define QUALIFIER_STAR '*'
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000610#define QUALIFIER_CIRCUMFLEX '^' /* For scanlists */
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000611#if TRIO_C99
Daniel Veillard92ad2102001-03-27 12:47:33 +0000612# define QUALIFIER_SIZE_T 'z'
613# define QUALIFIER_PTRDIFF_T 't'
614# define QUALIFIER_INTMAX_T 'j'
615#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000616#if TRIO_BSD || TRIO_GNU
Daniel Veillard92ad2102001-03-27 12:47:33 +0000617# define QUALIFIER_QUAD 'q'
618#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000619#if TRIO_GNU
Daniel Veillard92ad2102001-03-27 12:47:33 +0000620# define QUALIFIER_SIZE_T_UPPER 'Z'
621#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000622#if TRIO_MISC
Daniel Veillard92ad2102001-03-27 12:47:33 +0000623# define QUALIFIER_WIDECHAR 'w'
624#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000625#if TRIO_MICROSOFT
626# define QUALIFIER_FIXED_SIZE 'I'
627#endif
628#if TRIO_EXTENSION
Daniel Veillard92ad2102001-03-27 12:47:33 +0000629# define QUALIFIER_QUOTE '\''
630# define QUALIFIER_STICKY '!'
631# define QUALIFIER_VARSIZE '&' /* This should remain undocumented */
632# define QUALIFIER_PARAM '@' /* Experimental */
633# define QUALIFIER_COLON ':' /* For scanlists */
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000634# define QUALIFIER_EQUAL '=' /* For scanlists */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000635# define QUALIFIER_ROUNDING_UPPER 'R'
Daniel Veillard92ad2102001-03-27 12:47:33 +0000636#endif
637
Bjorn Reese70a9da52001-04-21 16:57:29 +0000638
639/*************************************************************************
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000640 *
641 * Internal Structures
642 *
643 *************************************************************************/
Bjorn Reese70a9da52001-04-21 16:57:29 +0000644
645/* Parameters */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000646typedef struct {
Bjorn Reese026d29f2002-01-19 15:40:18 +0000647 /* An indication of which entry in the data union is used */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000648 int type;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000649 /* The flags */
Daniel Veillarda48ed3d2003-04-03 15:28:28 +0000650 trio_flags_t flags;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000651 /* The width qualifier */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000652 int width;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000653 /* The precision qualifier */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000654 int precision;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000655 /* The base qualifier */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000656 int base;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000657 /* The size for the variable size qualifier */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000658 int varsize;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000659 /* The marker of the end of the specifier */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000660 int indexAfterSpecifier;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000661 /* The data from the argument list */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000662 union {
663 char *string;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000664#if TRIO_WIDECHAR
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000665 trio_wchar_t *wstring;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000666#endif
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000667 trio_pointer_t pointer;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000668 union {
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000669 trio_intmax_t as_signed;
670 trio_uintmax_t as_unsigned;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000671 } number;
672 double doubleNumber;
673 double *doublePointer;
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000674 trio_long_double_t longdoubleNumber;
675 trio_long_double_t *longdoublePointer;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000676 int errorNumber;
677 } data;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000678 /* For the user-defined specifier */
679 char user_name[MAX_USER_NAME];
680 char user_data[MAX_USER_DATA];
Bjorn Reese026d29f2002-01-19 15:40:18 +0000681} trio_parameter_t;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000682
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000683/* Container for customized functions */
684typedef struct {
685 union {
686 trio_outstream_t out;
687 trio_instream_t in;
688 } stream;
689 trio_pointer_t closure;
690} trio_custom_t;
691
Bjorn Reese70a9da52001-04-21 16:57:29 +0000692/* General trio "class" */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000693typedef struct _trio_class_t {
Bjorn Reese70a9da52001-04-21 16:57:29 +0000694 /*
Bjorn Reese026d29f2002-01-19 15:40:18 +0000695 * The function to write characters to a stream.
696 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000697 void (*OutStream) TRIO_PROTO((struct _trio_class_t *, int));
Bjorn Reese026d29f2002-01-19 15:40:18 +0000698 /*
699 * The function to read characters from a stream.
700 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000701 void (*InStream) TRIO_PROTO((struct _trio_class_t *, int *));
Bjorn Reese026d29f2002-01-19 15:40:18 +0000702 /*
703 * The current location in the stream.
704 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000705 trio_pointer_t location;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000706 /*
707 * The character currently being processed.
708 */
709 int current;
710 /*
711 * The number of characters that would have been written/read
712 * if there had been sufficient space.
Daniel Veillard92ad2102001-03-27 12:47:33 +0000713 */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000714 int processed;
715 /*
716 * The number of characters that are actually written/read.
Bjorn Reese026d29f2002-01-19 15:40:18 +0000717 * Processed and committed will only differ for the *nprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +0000718 * and *nscanf functions.
719 */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000720 int committed;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000721 /*
722 * The upper limit of characters that may be written/read.
723 */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000724 int max;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000725 /*
726 * The last output error that was detected.
727 */
728 int error;
729} trio_class_t;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000730
Bjorn Reese70a9da52001-04-21 16:57:29 +0000731/* References (for user-defined callbacks) */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000732typedef struct _trio_reference_t {
733 trio_class_t *data;
734 trio_parameter_t *parameter;
735} trio_reference_t;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000736
737/* Registered entries (for user-defined callbacks) */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000738typedef struct _trio_userdef_t {
739 struct _trio_userdef_t *next;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000740 trio_callback_t callback;
741 char *name;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000742} trio_userdef_t;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000743
Daniel Veillard92ad2102001-03-27 12:47:33 +0000744/*************************************************************************
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000745 *
746 * Internal Variables
747 *
748 *************************************************************************/
Daniel Veillard92ad2102001-03-27 12:47:33 +0000749
Bjorn Reese026d29f2002-01-19 15:40:18 +0000750static TRIO_CONST char rcsid[] = "@(#)$Id$";
751
752/*
753 * Need this to workaround a parser bug in HP C/iX compiler that fails
754 * to resolves macro definitions that includes type 'long double',
755 * e.g: va_arg(arg_ptr, long double)
756 */
757#if defined(TRIO_PLATFORM_MPEIX)
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000758static TRIO_CONST trio_long_double_t ___dummy_long_double = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000759#endif
Bjorn Reese026d29f2002-01-19 15:40:18 +0000760
761static TRIO_CONST char internalNullString[] = "(nil)";
Daniel Veillard92ad2102001-03-27 12:47:33 +0000762
Bjorn Reese70a9da52001-04-21 16:57:29 +0000763#if defined(USE_LOCALE)
764static struct lconv *internalLocaleValues = NULL;
765#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000766
Bjorn Reese70a9da52001-04-21 16:57:29 +0000767/*
768 * UNIX98 says "in a locale where the radix character is not defined,
769 * the radix character defaults to a period (.)"
770 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000771static int internalDecimalPointLength = 1;
772static int internalThousandSeparatorLength = 1;
773static char internalDecimalPoint = '.';
774static char internalDecimalPointString[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ".";
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000775static char internalThousandSeparator[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ",";
Bjorn Reese70a9da52001-04-21 16:57:29 +0000776static char internalGrouping[MAX_LOCALE_GROUPS] = { (char)NO_GROUPING };
777
Bjorn Reese026d29f2002-01-19 15:40:18 +0000778static TRIO_CONST char internalDigitsLower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
779static TRIO_CONST char internalDigitsUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
Bjorn Reese70a9da52001-04-21 16:57:29 +0000780static BOOLEAN_T internalDigitsUnconverted = TRUE;
781static int internalDigitArray[128];
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000782#if TRIO_EXTENSION
783static BOOLEAN_T internalCollationUnconverted = TRUE;
784static char internalCollationArray[MAX_CHARACTER_CLASS][MAX_CHARACTER_CLASS];
785#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +0000786
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000787#if TRIO_EXTENSION
Bjorn Reese026d29f2002-01-19 15:40:18 +0000788static TRIO_VOLATILE trio_callback_t internalEnterCriticalRegion = NULL;
789static TRIO_VOLATILE trio_callback_t internalLeaveCriticalRegion = NULL;
790static trio_userdef_t *internalUserDef = NULL;
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000791#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +0000792
793
794/*************************************************************************
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000795 *
796 * Internal Functions
797 *
798 ************************************************************************/
799
800#if defined(TRIO_MINIMAL)
801# define TRIO_STRING_PUBLIC static
802# include "triostr.c"
803#endif /* defined(TRIO_MINIMAL) */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000804
805/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +0000806 * TrioIsQualifier
Daniel Veillard92ad2102001-03-27 12:47:33 +0000807 *
808 * Description:
809 * Remember to add all new qualifiers to this function.
810 * QUALIFIER_POSITION must not be added.
811 */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000812TRIO_PRIVATE BOOLEAN_T
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000813TrioIsQualifier
814TRIO_ARGS1((character),
815 TRIO_CONST char character)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000816{
817 /* QUALIFIER_POSITION is not included */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000818 switch (character)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000819 {
820 case '0': case '1': case '2': case '3': case '4':
821 case '5': case '6': case '7': case '8': case '9':
822 case QUALIFIER_PLUS:
823 case QUALIFIER_MINUS:
824 case QUALIFIER_SPACE:
825 case QUALIFIER_DOT:
826 case QUALIFIER_STAR:
827 case QUALIFIER_ALTERNATIVE:
828 case QUALIFIER_SHORT:
829 case QUALIFIER_LONG:
830 case QUALIFIER_LONG_UPPER:
831 case QUALIFIER_CIRCUMFLEX:
832#if defined(QUALIFIER_SIZE_T)
833 case QUALIFIER_SIZE_T:
834#endif
835#if defined(QUALIFIER_PTRDIFF_T)
836 case QUALIFIER_PTRDIFF_T:
837#endif
838#if defined(QUALIFIER_INTMAX_T)
839 case QUALIFIER_INTMAX_T:
840#endif
841#if defined(QUALIFIER_QUAD)
842 case QUALIFIER_QUAD:
843#endif
844#if defined(QUALIFIER_SIZE_T_UPPER)
845 case QUALIFIER_SIZE_T_UPPER:
846#endif
847#if defined(QUALIFIER_WIDECHAR)
848 case QUALIFIER_WIDECHAR:
849#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000850#if defined(QUALIFIER_QUOTE)
851 case QUALIFIER_QUOTE:
852#endif
853#if defined(QUALIFIER_STICKY)
854 case QUALIFIER_STICKY:
855#endif
856#if defined(QUALIFIER_VARSIZE)
857 case QUALIFIER_VARSIZE:
858#endif
859#if defined(QUALIFIER_PARAM)
860 case QUALIFIER_PARAM:
861#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000862#if defined(QUALIFIER_FIXED_SIZE)
863 case QUALIFIER_FIXED_SIZE:
864#endif
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000865#if defined(QUALIFIER_ROUNDING_UPPER)
866 case QUALIFIER_ROUNDING_UPPER:
867#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000868 return TRUE;
869 default:
870 return FALSE;
871 }
872}
873
874/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +0000875 * TrioSetLocale
Bjorn Reese70a9da52001-04-21 16:57:29 +0000876 */
877#if defined(USE_LOCALE)
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000878TRIO_PRIVATE void
879TrioSetLocale(TRIO_NOARGS)
Bjorn Reese70a9da52001-04-21 16:57:29 +0000880{
881 internalLocaleValues = (struct lconv *)localeconv();
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000882 if (internalLocaleValues)
Bjorn Reese70a9da52001-04-21 16:57:29 +0000883 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000884 if ((internalLocaleValues->decimal_point) &&
885 (internalLocaleValues->decimal_point[0] != NIL))
886 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000887 internalDecimalPointLength = trio_length(internalLocaleValues->decimal_point);
888 if (internalDecimalPointLength == 1)
889 {
890 internalDecimalPoint = internalLocaleValues->decimal_point[0];
891 }
892 else
893 {
894 internalDecimalPoint = NIL;
895 trio_copy_max(internalDecimalPointString,
896 sizeof(internalDecimalPointString),
897 internalLocaleValues->decimal_point);
898 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000899 }
900 if ((internalLocaleValues->thousands_sep) &&
901 (internalLocaleValues->thousands_sep[0] != NIL))
902 {
Bjorn Reese026d29f2002-01-19 15:40:18 +0000903 trio_copy_max(internalThousandSeparator,
904 sizeof(internalThousandSeparator),
905 internalLocaleValues->thousands_sep);
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000906 internalThousandSeparatorLength = trio_length(internalThousandSeparator);
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000907 }
908 if ((internalLocaleValues->grouping) &&
909 (internalLocaleValues->grouping[0] != NIL))
910 {
Bjorn Reese026d29f2002-01-19 15:40:18 +0000911 trio_copy_max(internalGrouping,
912 sizeof(internalGrouping),
913 internalLocaleValues->grouping);
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000914 }
Bjorn Reese70a9da52001-04-21 16:57:29 +0000915 }
916}
917#endif /* defined(USE_LOCALE) */
918
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000919TRIO_PRIVATE int
920TrioCalcThousandSeparatorLength
921TRIO_ARGS1((digits),
922 int digits)
923{
924#if TRIO_EXTENSION
925 int count = 0;
926 int step = NO_GROUPING;
927 char *groupingPointer = internalGrouping;
928
929 while (digits > 0)
930 {
931 if (*groupingPointer == CHAR_MAX)
932 {
933 /* Disable grouping */
934 break; /* while */
935 }
936 else if (*groupingPointer == 0)
937 {
938 /* Repeat last group */
939 if (step == NO_GROUPING)
940 {
941 /* Error in locale */
942 break; /* while */
943 }
944 }
945 else
946 {
947 step = *groupingPointer++;
948 }
949 if (digits > step)
950 count += internalThousandSeparatorLength;
951 digits -= step;
952 }
953 return count;
954#else
955 return 0;
956#endif
957}
958
959TRIO_PRIVATE BOOLEAN_T
960TrioFollowedBySeparator
961TRIO_ARGS1((position),
962 int position)
963{
964#if TRIO_EXTENSION
965 int step = 0;
966 char *groupingPointer = internalGrouping;
967
968 position--;
969 if (position == 0)
970 return FALSE;
971 while (position > 0)
972 {
973 if (*groupingPointer == CHAR_MAX)
974 {
975 /* Disable grouping */
976 break; /* while */
977 }
978 else if (*groupingPointer != 0)
979 {
980 step = *groupingPointer++;
981 }
982 if (step == 0)
983 break;
984 position -= step;
985 }
986 return (position == 0);
987#else
988 return FALSE;
989#endif
990}
991
Bjorn Reese70a9da52001-04-21 16:57:29 +0000992/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +0000993 * TrioGetPosition
Daniel Veillard92ad2102001-03-27 12:47:33 +0000994 *
995 * Get the %n$ position.
996 */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000997TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000998TrioGetPosition
999TRIO_ARGS2((format, indexPointer),
1000 TRIO_CONST char *format,
1001 int *indexPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001002{
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001003#if TRIO_UNIX98
Daniel Veillard92ad2102001-03-27 12:47:33 +00001004 char *tmpformat;
1005 int number = 0;
1006 int index = *indexPointer;
1007
Bjorn Reese026d29f2002-01-19 15:40:18 +00001008 number = (int)trio_to_long(&format[index], &tmpformat, BASE_DECIMAL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001009 index = (int)(tmpformat - format);
1010 if ((number != 0) && (QUALIFIER_POSITION == format[index++]))
1011 {
1012 *indexPointer = index;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001013 /*
1014 * number is decreased by 1, because n$ starts from 1, whereas
Daniel Veillard92ad2102001-03-27 12:47:33 +00001015 * the array it is indexing starts from 0.
1016 */
1017 return number - 1;
1018 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001019#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +00001020 return NO_POSITION;
1021}
1022
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001023#if TRIO_EXTENSION
Daniel Veillard92ad2102001-03-27 12:47:33 +00001024/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00001025 * TrioFindNamespace
Bjorn Reese70a9da52001-04-21 16:57:29 +00001026 *
1027 * Find registered user-defined specifier.
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001028 * The prev argument is used for optimization only.
Bjorn Reese70a9da52001-04-21 16:57:29 +00001029 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00001030TRIO_PRIVATE trio_userdef_t *
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001031TrioFindNamespace
1032TRIO_ARGS2((name, prev),
1033 TRIO_CONST char *name,
1034 trio_userdef_t **prev)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001035{
Bjorn Reese026d29f2002-01-19 15:40:18 +00001036 trio_userdef_t *def;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001037
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001038 if (internalEnterCriticalRegion)
1039 (void)internalEnterCriticalRegion(NULL);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001040
Bjorn Reese70a9da52001-04-21 16:57:29 +00001041 for (def = internalUserDef; def; def = def->next)
1042 {
1043 /* Case-sensitive string comparison */
Bjorn Reese026d29f2002-01-19 15:40:18 +00001044 if (trio_equal_case(def->name, name))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001045 break;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001046
Bjorn Reese70a9da52001-04-21 16:57:29 +00001047 if (prev)
1048 *prev = def;
1049 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001050
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001051 if (internalLeaveCriticalRegion)
1052 (void)internalLeaveCriticalRegion(NULL);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001053
Bjorn Reese70a9da52001-04-21 16:57:29 +00001054 return def;
1055}
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001056#endif
1057
1058/*************************************************************************
1059 * TrioPower
1060 *
1061 * Description:
1062 * Calculate pow(base, exponent), where number and exponent are integers.
1063 */
1064TRIO_PRIVATE trio_long_double_t
1065TrioPower
1066TRIO_ARGS2((number, exponent),
1067 int number,
1068 int exponent)
1069{
1070 trio_long_double_t result;
1071
1072 if (number == 10)
1073 {
1074 switch (exponent)
1075 {
1076 /* Speed up calculation of common cases */
1077 case 0:
1078 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E-1);
1079 break;
1080 case 1:
1081 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+0);
1082 break;
1083 case 2:
1084 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+1);
1085 break;
1086 case 3:
1087 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+2);
1088 break;
1089 case 4:
1090 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+3);
1091 break;
1092 case 5:
1093 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+4);
1094 break;
1095 case 6:
1096 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+5);
1097 break;
1098 case 7:
1099 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+6);
1100 break;
1101 case 8:
1102 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+7);
1103 break;
1104 case 9:
1105 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+8);
1106 break;
1107 default:
1108 result = powl((trio_long_double_t)number,
1109 (trio_long_double_t)exponent);
1110 break;
1111 }
1112 }
1113 else
1114 {
1115 return powl((trio_long_double_t)number, (trio_long_double_t)exponent);
1116 }
1117 return result;
1118}
1119
1120/*************************************************************************
1121 * TrioLogarithm
1122 */
1123TRIO_PRIVATE double
1124TrioLogarithm
1125TRIO_ARGS2((number, base),
1126 double number,
1127 int base)
1128{
1129 double result;
1130
1131 if (number <= 0.0)
1132 {
1133 /* xlC crashes on log(0) */
1134 result = (number == 0.0) ? trio_ninf() : trio_nan();
1135 }
1136 else
1137 {
1138 if (base == 10)
1139 {
1140 result = log10(number);
1141 }
1142 else
1143 {
1144 result = log10(number) / log10((double)base);
1145 }
1146 }
1147 return result;
1148}
1149
1150/*************************************************************************
1151 * TrioLogarithmBase
1152 */
1153TRIO_PRIVATE double
1154TrioLogarithmBase
1155TRIO_ARGS1((base),
1156 int base)
1157{
1158 switch (base)
1159 {
1160 case BASE_BINARY : return 1.0;
1161 case BASE_OCTAL : return 3.0;
1162 case BASE_DECIMAL: return 3.321928094887362345;
1163 case BASE_HEX : return 4.0;
1164 default : return TrioLogarithm((double)base, 2);
1165 }
1166}
Bjorn Reese70a9da52001-04-21 16:57:29 +00001167
1168/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00001169 * TrioParse
Daniel Veillard92ad2102001-03-27 12:47:33 +00001170 *
1171 * Description:
1172 * Parse the format string
1173 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00001174TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001175TrioParse
1176TRIO_ARGS5((type, format, parameters, arglist, argarray),
1177 int type,
1178 TRIO_CONST char *format,
1179 trio_parameter_t *parameters,
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08001180 TRIO_VA_LIST_PTR arglist,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001181 trio_pointer_t *argarray)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001182{
Daniel Veillard92ad2102001-03-27 12:47:33 +00001183 /* Count the number of times a parameter is referenced */
1184 unsigned short usedEntries[MAX_PARAMETERS];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001185 /* Parameter counters */
1186 int parameterPosition;
1187 int currentParam;
1188 int maxParam = -1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001189 /* Utility variables */
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00001190 trio_flags_t flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001191 int width;
1192 int precision;
1193 int varsize;
1194 int base;
1195 int index; /* Index into formatting string */
1196 int dots; /* Count number of dots in modifier part */
1197 BOOLEAN_T positional; /* Does the specifier have a positional? */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001198 BOOLEAN_T gotSticky = FALSE; /* Are there any sticky modifiers at all? */
Bjorn Reese70a9da52001-04-21 16:57:29 +00001199 /*
1200 * indices specifies the order in which the parameters must be
Daniel Veillard92ad2102001-03-27 12:47:33 +00001201 * read from the va_args (this is necessary to handle positionals)
1202 */
1203 int indices[MAX_PARAMETERS];
1204 int pos = 0;
1205 /* Various variables */
1206 char ch;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001207#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001208 int charlen;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001209#endif
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001210 int save_errno;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001211 int i = -1;
1212 int num;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001213 char *tmpformat;
1214
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001215 /* One and only one of arglist and argarray must be used */
1216 assert((arglist != NULL) ^ (argarray != NULL));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001217
Bjorn Reese70a9da52001-04-21 16:57:29 +00001218 /*
1219 * The 'parameters' array is not initialized, but we need to
Daniel Veillard92ad2102001-03-27 12:47:33 +00001220 * know which entries we have used.
1221 */
1222 memset(usedEntries, 0, sizeof(usedEntries));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001223
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001224 save_errno = errno;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001225 index = 0;
1226 parameterPosition = 0;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001227#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001228 (void)mblen(NULL, 0);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001229#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001230
Daniel Veillard92ad2102001-03-27 12:47:33 +00001231 while (format[index])
1232 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001233#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001234 if (! isascii(format[index]))
1235 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001236 /*
1237 * Multibyte characters cannot be legal specifiers or
Daniel Veillard92ad2102001-03-27 12:47:33 +00001238 * modifiers, so we skip over them.
1239 */
1240 charlen = mblen(&format[index], MB_LEN_MAX);
1241 index += (charlen > 0) ? charlen : 1;
1242 continue; /* while */
1243 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001244#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
Daniel Veillard92ad2102001-03-27 12:47:33 +00001245 if (CHAR_IDENTIFIER == format[index++])
1246 {
1247 if (CHAR_IDENTIFIER == format[index])
1248 {
1249 index++;
1250 continue; /* while */
1251 }
1252
1253 flags = FLAGS_NEW;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001254 dots = 0;
1255 currentParam = TrioGetPosition(format, &index);
1256 positional = (NO_POSITION != currentParam);
1257 if (!positional)
1258 {
1259 /* We have no positional, get the next counter */
1260 currentParam = parameterPosition;
1261 }
1262 if(currentParam >= MAX_PARAMETERS)
1263 {
1264 /* Bail out completely to make the error more obvious */
1265 return TRIO_ERROR_RETURN(TRIO_ETOOMANY, index);
1266 }
1267
1268 if (currentParam > maxParam)
1269 maxParam = currentParam;
1270
1271 /* Default values */
1272 width = NO_WIDTH;
1273 precision = NO_PRECISION;
1274 base = NO_BASE;
1275 varsize = NO_SIZE;
1276
Bjorn Reese70a9da52001-04-21 16:57:29 +00001277 while (TrioIsQualifier(format[index]))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001278 {
1279 ch = format[index++];
1280
Daniel Veillard92ad2102001-03-27 12:47:33 +00001281 switch (ch)
1282 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00001283 case QUALIFIER_SPACE:
1284 flags |= FLAGS_SPACE;
1285 break;
1286
1287 case QUALIFIER_PLUS:
1288 flags |= FLAGS_SHOWSIGN;
1289 break;
1290
1291 case QUALIFIER_MINUS:
1292 flags |= FLAGS_LEFTADJUST;
1293 flags &= ~FLAGS_NILPADDING;
1294 break;
1295
1296 case QUALIFIER_ALTERNATIVE:
1297 flags |= FLAGS_ALTERNATIVE;
1298 break;
1299
1300 case QUALIFIER_DOT:
1301 if (dots == 0) /* Precision */
1302 {
1303 dots++;
1304
1305 /* Skip if no precision */
1306 if (QUALIFIER_DOT == format[index])
1307 break;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001308
Daniel Veillard92ad2102001-03-27 12:47:33 +00001309 /* After the first dot we have the precision */
1310 flags |= FLAGS_PRECISION;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001311 if ((QUALIFIER_STAR == format[index])
1312#if defined(QUALIFIER_PARAM)
1313 || (QUALIFIER_PARAM == format[index])
1314#endif
1315 )
Daniel Veillard92ad2102001-03-27 12:47:33 +00001316 {
1317 index++;
1318 flags |= FLAGS_PRECISION_PARAMETER;
1319
1320 precision = TrioGetPosition(format, &index);
1321 if (precision == NO_POSITION)
1322 {
1323 parameterPosition++;
1324 if (positional)
1325 precision = parameterPosition;
1326 else
1327 {
1328 precision = currentParam;
1329 currentParam = precision + 1;
1330 }
1331 }
1332 else
1333 {
1334 if (! positional)
1335 currentParam = precision + 1;
1336 if (width > maxParam)
1337 maxParam = precision;
1338 }
1339 if (currentParam > maxParam)
1340 maxParam = currentParam;
1341 }
1342 else
1343 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00001344 precision = trio_to_long(&format[index],
1345 &tmpformat,
1346 BASE_DECIMAL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001347 index = (int)(tmpformat - format);
1348 }
1349 }
1350 else if (dots == 1) /* Base */
1351 {
1352 dots++;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001353
Daniel Veillard92ad2102001-03-27 12:47:33 +00001354 /* After the second dot we have the base */
1355 flags |= FLAGS_BASE;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001356 if ((QUALIFIER_STAR == format[index])
1357#if defined(QUALIFIER_PARAM)
1358 || (QUALIFIER_PARAM == format[index])
1359#endif
1360 )
Daniel Veillard92ad2102001-03-27 12:47:33 +00001361 {
1362 index++;
1363 flags |= FLAGS_BASE_PARAMETER;
1364 base = TrioGetPosition(format, &index);
1365 if (base == NO_POSITION)
1366 {
1367 parameterPosition++;
1368 if (positional)
1369 base = parameterPosition;
1370 else
1371 {
1372 base = currentParam;
1373 currentParam = base + 1;
1374 }
1375 }
1376 else
1377 {
1378 if (! positional)
1379 currentParam = base + 1;
1380 if (base > maxParam)
1381 maxParam = base;
1382 }
1383 if (currentParam > maxParam)
1384 maxParam = currentParam;
1385 }
1386 else
1387 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00001388 base = trio_to_long(&format[index],
1389 &tmpformat,
1390 BASE_DECIMAL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001391 if (base > MAX_BASE)
1392 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1393 index = (int)(tmpformat - format);
1394 }
1395 }
1396 else
1397 {
1398 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1399 }
1400 break; /* QUALIFIER_DOT */
1401
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001402#if defined(QUALIFIER_PARAM)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001403 case QUALIFIER_PARAM:
1404 type = TYPE_PRINT;
1405 /* FALLTHROUGH */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001406#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +00001407 case QUALIFIER_STAR:
1408 /* This has different meanings for print and scan */
1409 if (TYPE_PRINT == type)
1410 {
1411 /* Read with from parameter */
1412 flags |= (FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER);
1413 width = TrioGetPosition(format, &index);
1414 if (width == NO_POSITION)
1415 {
1416 parameterPosition++;
1417 if (positional)
1418 width = parameterPosition;
1419 else
1420 {
1421 width = currentParam;
1422 currentParam = width + 1;
1423 }
1424 }
1425 else
1426 {
1427 if (! positional)
1428 currentParam = width + 1;
1429 if (width > maxParam)
1430 maxParam = width;
1431 }
1432 if (currentParam > maxParam)
1433 maxParam = currentParam;
1434 }
1435 else
1436 {
1437 /* Scan, but do not store result */
1438 flags |= FLAGS_IGNORE;
1439 }
1440
1441 break; /* QUALIFIER_STAR */
1442
1443 case '0':
1444 if (! (flags & FLAGS_LEFTADJUST))
1445 flags |= FLAGS_NILPADDING;
1446 /* FALLTHROUGH */
1447 case '1': case '2': case '3': case '4':
1448 case '5': case '6': case '7': case '8': case '9':
1449 flags |= FLAGS_WIDTH;
1450 /* &format[index - 1] is used to "rewind" the read
1451 * character from format
1452 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00001453 width = trio_to_long(&format[index - 1],
1454 &tmpformat,
1455 BASE_DECIMAL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001456 index = (int)(tmpformat - format);
1457 break;
1458
1459 case QUALIFIER_SHORT:
1460 if (flags & FLAGS_SHORTSHORT)
1461 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1462 else if (flags & FLAGS_SHORT)
1463 flags |= FLAGS_SHORTSHORT;
1464 else
1465 flags |= FLAGS_SHORT;
1466 break;
1467
1468 case QUALIFIER_LONG:
1469 if (flags & FLAGS_QUAD)
1470 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1471 else if (flags & FLAGS_LONG)
1472 flags |= FLAGS_QUAD;
1473 else
1474 flags |= FLAGS_LONG;
1475 break;
1476
1477 case QUALIFIER_LONG_UPPER:
1478 flags |= FLAGS_LONGDOUBLE;
1479 break;
1480
1481#if defined(QUALIFIER_SIZE_T)
1482 case QUALIFIER_SIZE_T:
1483 flags |= FLAGS_SIZE_T;
1484 /* Modify flags for later truncation of number */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001485 if (sizeof(size_t) == sizeof(trio_ulonglong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001486 flags |= FLAGS_QUAD;
1487 else if (sizeof(size_t) == sizeof(long))
1488 flags |= FLAGS_LONG;
1489 break;
1490#endif
1491
1492#if defined(QUALIFIER_PTRDIFF_T)
1493 case QUALIFIER_PTRDIFF_T:
1494 flags |= FLAGS_PTRDIFF_T;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001495 if (sizeof(ptrdiff_t) == sizeof(trio_ulonglong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001496 flags |= FLAGS_QUAD;
1497 else if (sizeof(ptrdiff_t) == sizeof(long))
1498 flags |= FLAGS_LONG;
1499 break;
1500#endif
1501
1502#if defined(QUALIFIER_INTMAX_T)
1503 case QUALIFIER_INTMAX_T:
1504 flags |= FLAGS_INTMAX_T;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001505 if (sizeof(trio_intmax_t) == sizeof(trio_ulonglong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001506 flags |= FLAGS_QUAD;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001507 else if (sizeof(trio_intmax_t) == sizeof(long))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001508 flags |= FLAGS_LONG;
1509 break;
1510#endif
1511
1512#if defined(QUALIFIER_QUAD)
1513 case QUALIFIER_QUAD:
1514 flags |= FLAGS_QUAD;
1515 break;
1516#endif
1517
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001518#if defined(QUALIFIER_FIXED_SIZE)
1519 case QUALIFIER_FIXED_SIZE:
1520 if (flags & FLAGS_FIXED_SIZE)
1521 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1522
1523 if (flags & (FLAGS_ALL_SIZES | FLAGS_LONGDOUBLE |
1524 FLAGS_WIDECHAR | FLAGS_VARSIZE_PARAMETER))
1525 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1526
1527 if ((format[index] == '6') &&
1528 (format[index + 1] == '4'))
1529 {
1530 varsize = sizeof(trio_int64_t);
1531 index += 2;
1532 }
1533 else if ((format[index] == '3') &&
1534 (format[index + 1] == '2'))
1535 {
1536 varsize = sizeof(trio_int32_t);
1537 index += 2;
1538 }
1539 else if ((format[index] == '1') &&
1540 (format[index + 1] == '6'))
1541 {
1542 varsize = sizeof(trio_int16_t);
1543 index += 2;
1544 }
1545 else if (format[index] == '8')
1546 {
1547 varsize = sizeof(trio_int8_t);
1548 index++;
1549 }
1550 else
1551 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001552
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001553 flags |= FLAGS_FIXED_SIZE;
1554 break;
1555#endif
1556
Daniel Veillard92ad2102001-03-27 12:47:33 +00001557#if defined(QUALIFIER_WIDECHAR)
1558 case QUALIFIER_WIDECHAR:
1559 flags |= FLAGS_WIDECHAR;
1560 break;
1561#endif
1562
1563#if defined(QUALIFIER_SIZE_T_UPPER)
1564 case QUALIFIER_SIZE_T_UPPER:
1565 break;
1566#endif
1567
1568#if defined(QUALIFIER_QUOTE)
1569 case QUALIFIER_QUOTE:
1570 flags |= FLAGS_QUOTE;
1571 break;
1572#endif
1573
1574#if defined(QUALIFIER_STICKY)
1575 case QUALIFIER_STICKY:
1576 flags |= FLAGS_STICKY;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001577 gotSticky = TRUE;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001578 break;
1579#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001580
Daniel Veillard92ad2102001-03-27 12:47:33 +00001581#if defined(QUALIFIER_VARSIZE)
1582 case QUALIFIER_VARSIZE:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001583 flags |= FLAGS_VARSIZE_PARAMETER;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001584 parameterPosition++;
1585 if (positional)
1586 varsize = parameterPosition;
1587 else
1588 {
1589 varsize = currentParam;
1590 currentParam = varsize + 1;
1591 }
1592 if (currentParam > maxParam)
1593 maxParam = currentParam;
1594 break;
1595#endif
1596
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001597#if defined(QUALIFIER_ROUNDING_UPPER)
1598 case QUALIFIER_ROUNDING_UPPER:
1599 flags |= FLAGS_ROUNDING;
1600 break;
1601#endif
1602
Daniel Veillard92ad2102001-03-27 12:47:33 +00001603 default:
1604 /* Bail out completely to make the error more obvious */
1605 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1606 }
1607 } /* while qualifier */
1608
Bjorn Reese70a9da52001-04-21 16:57:29 +00001609 /*
1610 * Parameters only need the type and value. The value is
Daniel Veillard92ad2102001-03-27 12:47:33 +00001611 * read later.
1612 */
1613 if (flags & FLAGS_WIDTH_PARAMETER)
1614 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00001615 usedEntries[width] += 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001616 parameters[pos].type = FORMAT_PARAMETER;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001617 parameters[pos].flags = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001618 indices[width] = pos;
1619 width = pos++;
1620 }
1621 if (flags & FLAGS_PRECISION_PARAMETER)
1622 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00001623 usedEntries[precision] += 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001624 parameters[pos].type = FORMAT_PARAMETER;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001625 parameters[pos].flags = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001626 indices[precision] = pos;
1627 precision = pos++;
1628 }
1629 if (flags & FLAGS_BASE_PARAMETER)
1630 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00001631 usedEntries[base] += 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001632 parameters[pos].type = FORMAT_PARAMETER;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001633 parameters[pos].flags = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001634 indices[base] = pos;
1635 base = pos++;
1636 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001637 if (flags & FLAGS_VARSIZE_PARAMETER)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001638 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00001639 usedEntries[varsize] += 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001640 parameters[pos].type = FORMAT_PARAMETER;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001641 parameters[pos].flags = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001642 indices[varsize] = pos;
1643 varsize = pos++;
1644 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001645
Daniel Veillard92ad2102001-03-27 12:47:33 +00001646 indices[currentParam] = pos;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001647
Daniel Veillard92ad2102001-03-27 12:47:33 +00001648 switch (format[index++])
1649 {
1650#if defined(SPECIFIER_CHAR_UPPER)
1651 case SPECIFIER_CHAR_UPPER:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001652 flags |= FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001653 /* FALLTHROUGH */
1654#endif
1655 case SPECIFIER_CHAR:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001656 if (flags & FLAGS_LONG)
1657 flags |= FLAGS_WIDECHAR;
1658 else if (flags & FLAGS_SHORT)
1659 flags &= ~FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001660 parameters[pos].type = FORMAT_CHAR;
1661 break;
1662
1663#if defined(SPECIFIER_STRING_UPPER)
1664 case SPECIFIER_STRING_UPPER:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001665 flags |= FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001666 /* FALLTHROUGH */
1667#endif
1668 case SPECIFIER_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001669 if (flags & FLAGS_LONG)
1670 flags |= FLAGS_WIDECHAR;
1671 else if (flags & FLAGS_SHORT)
1672 flags &= ~FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001673 parameters[pos].type = FORMAT_STRING;
1674 break;
1675
1676 case SPECIFIER_GROUP:
1677 if (TYPE_SCAN == type)
1678 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001679 int depth = 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001680 parameters[pos].type = FORMAT_GROUP;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001681 if (format[index] == QUALIFIER_CIRCUMFLEX)
1682 index++;
1683 if (format[index] == SPECIFIER_UNGROUP)
1684 index++;
1685 if (format[index] == QUALIFIER_MINUS)
1686 index++;
1687 /* Skip nested brackets */
1688 while (format[index] != NIL)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001689 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001690 if (format[index] == SPECIFIER_GROUP)
1691 {
1692 depth++;
1693 }
1694 else if (format[index] == SPECIFIER_UNGROUP)
1695 {
1696 if (--depth <= 0)
1697 {
1698 index++;
1699 break;
1700 }
1701 }
1702 index++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001703 }
1704 }
1705 break;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001706
Daniel Veillard92ad2102001-03-27 12:47:33 +00001707 case SPECIFIER_INTEGER:
1708 parameters[pos].type = FORMAT_INT;
1709 break;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001710
Daniel Veillard92ad2102001-03-27 12:47:33 +00001711 case SPECIFIER_UNSIGNED:
1712 flags |= FLAGS_UNSIGNED;
1713 parameters[pos].type = FORMAT_INT;
1714 break;
1715
1716 case SPECIFIER_DECIMAL:
1717 /* Disable base modifier */
1718 flags &= ~FLAGS_BASE_PARAMETER;
1719 base = BASE_DECIMAL;
1720 parameters[pos].type = FORMAT_INT;
1721 break;
1722
1723 case SPECIFIER_OCTAL:
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00001724 flags |= FLAGS_UNSIGNED;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001725 flags &= ~FLAGS_BASE_PARAMETER;
1726 base = BASE_OCTAL;
1727 parameters[pos].type = FORMAT_INT;
1728 break;
1729
1730#if defined(SPECIFIER_BINARY)
1731 case SPECIFIER_BINARY_UPPER:
1732 flags |= FLAGS_UPPER;
1733 /* FALLTHROUGH */
1734 case SPECIFIER_BINARY:
1735 flags |= FLAGS_NILPADDING;
1736 flags &= ~FLAGS_BASE_PARAMETER;
1737 base = BASE_BINARY;
1738 parameters[pos].type = FORMAT_INT;
1739 break;
1740#endif
1741
1742 case SPECIFIER_HEX_UPPER:
1743 flags |= FLAGS_UPPER;
1744 /* FALLTHROUGH */
1745 case SPECIFIER_HEX:
1746 flags |= FLAGS_UNSIGNED;
1747 flags &= ~FLAGS_BASE_PARAMETER;
1748 base = BASE_HEX;
1749 parameters[pos].type = FORMAT_INT;
1750 break;
1751
1752 case SPECIFIER_FLOAT_E_UPPER:
1753 flags |= FLAGS_UPPER;
1754 /* FALLTHROUGH */
1755 case SPECIFIER_FLOAT_E:
1756 flags |= FLAGS_FLOAT_E;
1757 parameters[pos].type = FORMAT_DOUBLE;
1758 break;
1759
1760 case SPECIFIER_FLOAT_G_UPPER:
1761 flags |= FLAGS_UPPER;
1762 /* FALLTHROUGH */
1763 case SPECIFIER_FLOAT_G:
1764 flags |= FLAGS_FLOAT_G;
1765 parameters[pos].type = FORMAT_DOUBLE;
1766 break;
1767
1768 case SPECIFIER_FLOAT_F_UPPER:
1769 flags |= FLAGS_UPPER;
1770 /* FALLTHROUGH */
1771 case SPECIFIER_FLOAT_F:
1772 parameters[pos].type = FORMAT_DOUBLE;
1773 break;
1774
1775 case SPECIFIER_POINTER:
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001776 if (sizeof(trio_pointer_t) == sizeof(trio_ulonglong_t))
1777 flags |= FLAGS_QUAD;
1778 else if (sizeof(trio_pointer_t) == sizeof(long))
1779 flags |= FLAGS_LONG;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001780 parameters[pos].type = FORMAT_POINTER;
1781 break;
1782
1783 case SPECIFIER_COUNT:
1784 parameters[pos].type = FORMAT_COUNT;
1785 break;
1786
1787#if defined(SPECIFIER_HEXFLOAT)
1788# if defined(SPECIFIER_HEXFLOAT_UPPER)
1789 case SPECIFIER_HEXFLOAT_UPPER:
1790 flags |= FLAGS_UPPER;
1791 /* FALLTHROUGH */
1792# endif
1793 case SPECIFIER_HEXFLOAT:
1794 base = BASE_HEX;
1795 parameters[pos].type = FORMAT_DOUBLE;
1796 break;
1797#endif
1798
1799#if defined(FORMAT_ERRNO)
1800 case SPECIFIER_ERRNO:
1801 parameters[pos].type = FORMAT_ERRNO;
1802 break;
1803#endif
1804
Bjorn Reese70a9da52001-04-21 16:57:29 +00001805#if defined(SPECIFIER_USER_DEFINED_BEGIN)
1806 case SPECIFIER_USER_DEFINED_BEGIN:
1807 {
1808 unsigned int max;
1809 int without_namespace = TRUE;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001810
Bjorn Reese70a9da52001-04-21 16:57:29 +00001811 parameters[pos].type = FORMAT_USER_DEFINED;
1812 parameters[pos].user_name[0] = NIL;
1813 tmpformat = (char *)&format[index];
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001814
Bjorn Reese70a9da52001-04-21 16:57:29 +00001815 while ((ch = format[index]))
1816 {
1817 index++;
1818 if (ch == SPECIFIER_USER_DEFINED_END)
1819 {
1820 if (without_namespace)
1821 {
1822 /* We must get the handle first */
1823 parameters[pos].type = FORMAT_PARAMETER;
1824 parameters[pos].indexAfterSpecifier = index;
1825 parameters[pos].flags = FLAGS_USER_DEFINED;
1826 /* Adjust parameters for insertion of new one */
1827 pos++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001828 usedEntries[currentParam] += 1;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001829 parameters[pos].type = FORMAT_USER_DEFINED;
1830 currentParam++;
1831 indices[currentParam] = pos;
1832 if (currentParam > maxParam)
1833 maxParam = currentParam;
1834 }
1835 /* Copy the user data */
1836 max = (unsigned int)(&format[index] - tmpformat);
1837 if (max > MAX_USER_DATA)
1838 max = MAX_USER_DATA;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001839 trio_copy_max(parameters[pos].user_data,
1840 max,
1841 tmpformat);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001842 break; /* while */
1843 }
1844 if (ch == SPECIFIER_USER_DEFINED_SEPARATOR)
1845 {
1846 without_namespace = FALSE;
1847 /* Copy the namespace for later looking-up */
1848 max = (int)(&format[index] - tmpformat);
1849 if (max > MAX_USER_NAME)
1850 max = MAX_USER_NAME;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001851 trio_copy_max(parameters[pos].user_name,
1852 max,
1853 tmpformat);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001854 tmpformat = (char *)&format[index];
1855 }
1856 }
1857 if (ch != SPECIFIER_USER_DEFINED_END)
1858 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1859 }
1860 break;
1861#endif /* defined(SPECIFIER_USER_DEFINED_BEGIN) */
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001862
Daniel Veillard92ad2102001-03-27 12:47:33 +00001863 default:
1864 /* Bail out completely to make the error more obvious */
1865 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1866 }
1867
Daniel Veillard92ad2102001-03-27 12:47:33 +00001868 /* Count the number of times this entry has been used */
1869 usedEntries[currentParam] += 1;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001870
Daniel Veillard92ad2102001-03-27 12:47:33 +00001871 /* Find last sticky parameters */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001872 if (gotSticky && !(flags & FLAGS_STICKY))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001873 {
1874 for (i = pos - 1; i >= 0; i--)
1875 {
1876 if (parameters[i].type == FORMAT_PARAMETER)
1877 continue;
1878 if ((parameters[i].flags & FLAGS_STICKY) &&
1879 (parameters[i].type == parameters[pos].type))
1880 {
1881 /* Do not overwrite current qualifiers */
Bjorn Reese70a9da52001-04-21 16:57:29 +00001882 flags |= (parameters[i].flags & (unsigned long)~FLAGS_STICKY);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001883 if (width == NO_WIDTH)
1884 width = parameters[i].width;
1885 if (precision == NO_PRECISION)
1886 precision = parameters[i].precision;
1887 if (base == NO_BASE)
1888 base = parameters[i].base;
1889 break;
1890 }
1891 }
1892 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001893
Daniel Veillard92ad2102001-03-27 12:47:33 +00001894 parameters[pos].indexAfterSpecifier = index;
1895 parameters[pos].flags = flags;
1896 parameters[pos].width = width;
1897 parameters[pos].precision = precision;
1898 parameters[pos].base = (base == NO_BASE) ? BASE_DECIMAL : base;
1899 parameters[pos].varsize = varsize;
1900 pos++;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001901
Bjorn Reese70a9da52001-04-21 16:57:29 +00001902 if (! positional)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001903 parameterPosition++;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001904
Daniel Veillard92ad2102001-03-27 12:47:33 +00001905 } /* if identifier */
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001906
Daniel Veillard92ad2102001-03-27 12:47:33 +00001907 } /* while format characters left */
1908
1909 for (num = 0; num <= maxParam; num++)
1910 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00001911 if (usedEntries[num] != 1)
1912 {
1913 if (usedEntries[num] == 0) /* gap detected */
1914 return TRIO_ERROR_RETURN(TRIO_EGAP, num);
1915 else /* double references detected */
1916 return TRIO_ERROR_RETURN(TRIO_EDBLREF, num);
1917 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001918
Daniel Veillard92ad2102001-03-27 12:47:33 +00001919 i = indices[num];
1920
Bjorn Reese70a9da52001-04-21 16:57:29 +00001921 /*
1922 * FORMAT_PARAMETERS are only present if they must be read,
Daniel Veillard92ad2102001-03-27 12:47:33 +00001923 * so it makes no sense to check the ignore flag (besides,
1924 * the flags variable is not set for that particular type)
1925 */
1926 if ((parameters[i].type != FORMAT_PARAMETER) &&
1927 (parameters[i].flags & FLAGS_IGNORE))
1928 continue; /* for all arguments */
1929
Bjorn Reese70a9da52001-04-21 16:57:29 +00001930 /*
1931 * The stack arguments are read according to ANSI C89
Daniel Veillard92ad2102001-03-27 12:47:33 +00001932 * default argument promotions:
1933 *
1934 * char = int
1935 * short = int
1936 * unsigned char = unsigned int
1937 * unsigned short = unsigned int
1938 * float = double
1939 *
1940 * In addition to the ANSI C89 these types are read (the
1941 * default argument promotions of C99 has not been
1942 * considered yet)
1943 *
1944 * long long
1945 * long double
1946 * size_t
1947 * ptrdiff_t
1948 * intmax_t
1949 */
1950 switch (parameters[i].type)
1951 {
1952 case FORMAT_GROUP:
1953 case FORMAT_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001954#if TRIO_WIDECHAR
1955 if (flags & FLAGS_WIDECHAR)
1956 {
1957 parameters[i].data.wstring = (argarray == NULL)
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08001958 ? va_arg(TRIO_VA_LIST_DEREF(arglist), trio_wchar_t *)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001959 : (trio_wchar_t *)(argarray[num]);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001960 }
1961 else
1962#endif
1963 {
1964 parameters[i].data.string = (argarray == NULL)
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08001965 ? va_arg(TRIO_VA_LIST_DEREF(arglist), char *)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001966 : (char *)(argarray[num]);
1967 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001968 break;
1969
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001970#if defined(FORMAT_USER_DEFINED)
1971 case FORMAT_USER_DEFINED:
1972#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +00001973 case FORMAT_POINTER:
1974 case FORMAT_COUNT:
1975 case FORMAT_UNKNOWN:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001976 parameters[i].data.pointer = (argarray == NULL)
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08001977 ? va_arg(TRIO_VA_LIST_DEREF(arglist), trio_pointer_t )
Bjorn Reese70a9da52001-04-21 16:57:29 +00001978 : argarray[num];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001979 break;
1980
1981 case FORMAT_CHAR:
1982 case FORMAT_INT:
1983 if (TYPE_SCAN == type)
1984 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001985 if (argarray == NULL)
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001986 parameters[i].data.pointer =
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08001987 (trio_pointer_t)va_arg(TRIO_VA_LIST_DEREF(arglist), trio_pointer_t);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001988 else
1989 {
1990 if (parameters[i].type == FORMAT_CHAR)
1991 parameters[i].data.pointer =
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001992 (trio_pointer_t)((char *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001993 else if (parameters[i].flags & FLAGS_SHORT)
1994 parameters[i].data.pointer =
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001995 (trio_pointer_t)((short *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001996 else
1997 parameters[i].data.pointer =
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001998 (trio_pointer_t)((int *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001999 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002000 }
2001 else
2002 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002003#if defined(QUALIFIER_VARSIZE) || defined(QUALIFIER_FIXED_SIZE)
Bjorn Reese026d29f2002-01-19 15:40:18 +00002004 if (parameters[i].flags
2005 & (FLAGS_VARSIZE_PARAMETER | FLAGS_FIXED_SIZE))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002006 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002007 if (parameters[i].flags & FLAGS_VARSIZE_PARAMETER)
2008 {
2009 /*
2010 * Variable sizes are mapped onto the fixed sizes, in
2011 * accordance with integer promotion.
2012 *
2013 * Please note that this may not be portable, as we
2014 * only guess the size, not the layout of the numbers.
2015 * For example, if int is little-endian, and long is
2016 * big-endian, then this will fail.
2017 */
2018 varsize = (int)parameters[parameters[i].varsize].data.number.as_unsigned;
2019 }
2020 else
2021 {
2022 /* Used for the I<bits> modifiers */
2023 varsize = parameters[i].varsize;
2024 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002025 parameters[i].flags &= ~FLAGS_ALL_VARSIZES;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002026
Daniel Veillard92ad2102001-03-27 12:47:33 +00002027 if (varsize <= (int)sizeof(int))
2028 ;
2029 else if (varsize <= (int)sizeof(long))
2030 parameters[i].flags |= FLAGS_LONG;
2031#if defined(QUALIFIER_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002032 else if (varsize <= (int)sizeof(trio_longlong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002033 parameters[i].flags |= FLAGS_QUAD;
2034 else
2035 parameters[i].flags |= FLAGS_INTMAX_T;
2036#else
2037 else
2038 parameters[i].flags |= FLAGS_QUAD;
2039#endif
2040 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002041#endif /* defined(QUALIFIER_VARSIZE) */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002042#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
2043 if (parameters[i].flags & FLAGS_SIZE_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002044 parameters[i].data.number.as_unsigned = (argarray == NULL)
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08002045 ? (trio_uintmax_t)va_arg(TRIO_VA_LIST_DEREF(arglist), size_t)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002046 : (trio_uintmax_t)(*((size_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002047 else
2048#endif
2049#if defined(QUALIFIER_PTRDIFF_T)
2050 if (parameters[i].flags & FLAGS_PTRDIFF_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002051 parameters[i].data.number.as_unsigned = (argarray == NULL)
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08002052 ? (trio_uintmax_t)va_arg(TRIO_VA_LIST_DEREF(arglist), ptrdiff_t)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002053 : (trio_uintmax_t)(*((ptrdiff_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002054 else
2055#endif
2056#if defined(QUALIFIER_INTMAX_T)
2057 if (parameters[i].flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002058 parameters[i].data.number.as_unsigned = (argarray == NULL)
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08002059 ? (trio_uintmax_t)va_arg(TRIO_VA_LIST_DEREF(arglist), trio_intmax_t)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002060 : (trio_uintmax_t)(*((trio_intmax_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002061 else
2062#endif
2063 if (parameters[i].flags & FLAGS_QUAD)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002064 parameters[i].data.number.as_unsigned = (argarray == NULL)
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08002065 ? (trio_uintmax_t)va_arg(TRIO_VA_LIST_DEREF(arglist), trio_ulonglong_t)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002066 : (trio_uintmax_t)(*((trio_ulonglong_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002067 else if (parameters[i].flags & FLAGS_LONG)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002068 parameters[i].data.number.as_unsigned = (argarray == NULL)
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08002069 ? (trio_uintmax_t)va_arg(TRIO_VA_LIST_DEREF(arglist), long)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002070 : (trio_uintmax_t)(*((long *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002071 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00002072 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002073 if (argarray == NULL)
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08002074 parameters[i].data.number.as_unsigned = (trio_uintmax_t)va_arg(TRIO_VA_LIST_DEREF(arglist), int);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002075 else
2076 {
2077 if (parameters[i].type == FORMAT_CHAR)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002078 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((char *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00002079 else if (parameters[i].flags & FLAGS_SHORT)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002080 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((short *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00002081 else
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002082 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((int *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00002083 }
2084 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002085 }
2086 break;
2087
2088 case FORMAT_PARAMETER:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002089 /*
2090 * The parameter for the user-defined specifier is a pointer,
2091 * whereas the rest (width, precision, base) uses an integer.
2092 */
2093 if (parameters[i].flags & FLAGS_USER_DEFINED)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002094 parameters[i].data.pointer = (argarray == NULL)
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08002095 ? va_arg(TRIO_VA_LIST_DEREF(arglist), trio_pointer_t )
Bjorn Reese70a9da52001-04-21 16:57:29 +00002096 : argarray[num];
2097 else
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002098 parameters[i].data.number.as_unsigned = (argarray == NULL)
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08002099 ? (trio_uintmax_t)va_arg(TRIO_VA_LIST_DEREF(arglist), int)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002100 : (trio_uintmax_t)(*((int *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002101 break;
2102
2103 case FORMAT_DOUBLE:
2104 if (TYPE_SCAN == type)
2105 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002106 if (parameters[i].flags & FLAGS_LONGDOUBLE)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002107 parameters[i].data.longdoublePointer = (argarray == NULL)
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08002108 ? va_arg(TRIO_VA_LIST_DEREF(arglist), trio_long_double_t *)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002109 : (trio_long_double_t *)argarray[num];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002110 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00002111 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002112 if (parameters[i].flags & FLAGS_LONG)
2113 parameters[i].data.doublePointer = (argarray == NULL)
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08002114 ? va_arg(TRIO_VA_LIST_DEREF(arglist), double *)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002115 : (double *)argarray[num];
2116 else
2117 parameters[i].data.doublePointer = (argarray == NULL)
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08002118 ? (double *)va_arg(TRIO_VA_LIST_DEREF(arglist), float *)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002119 : (double *)((float *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002120 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002121 }
2122 else
2123 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002124 if (parameters[i].flags & FLAGS_LONGDOUBLE)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002125 parameters[i].data.longdoubleNumber = (argarray == NULL)
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08002126 ? va_arg(TRIO_VA_LIST_DEREF(arglist), trio_long_double_t)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002127 : (trio_long_double_t)(*((trio_long_double_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002128 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00002129 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002130 if (argarray == NULL)
Bjorn Reese026d29f2002-01-19 15:40:18 +00002131 parameters[i].data.longdoubleNumber =
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08002132 (trio_long_double_t)va_arg(TRIO_VA_LIST_DEREF(arglist), double);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002133 else
2134 {
2135 if (parameters[i].flags & FLAGS_SHORT)
Bjorn Reese026d29f2002-01-19 15:40:18 +00002136 parameters[i].data.longdoubleNumber =
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002137 (trio_long_double_t)(*((float *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00002138 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00002139 parameters[i].data.longdoubleNumber =
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002140 (trio_long_double_t)(*((double *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00002141 }
2142 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002143 }
2144 break;
2145
2146#if defined(FORMAT_ERRNO)
2147 case FORMAT_ERRNO:
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002148 parameters[i].data.errorNumber = save_errno;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002149 break;
2150#endif
2151
2152 default:
2153 break;
2154 }
2155 } /* for all specifiers */
2156 return num;
2157}
2158
2159
2160/*************************************************************************
2161 *
Bjorn Reese026d29f2002-01-19 15:40:18 +00002162 * FORMATTING
Daniel Veillard92ad2102001-03-27 12:47:33 +00002163 *
2164 ************************************************************************/
2165
2166
2167/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002168 * TrioWriteNumber
Daniel Veillard92ad2102001-03-27 12:47:33 +00002169 *
2170 * Description:
2171 * Output a number.
2172 * The complexity of this function is a result of the complexity
2173 * of the dependencies of the flags.
2174 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00002175TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002176TrioWriteNumber
2177TRIO_ARGS6((self, number, flags, width, precision, base),
2178 trio_class_t *self,
2179 trio_uintmax_t number,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002180 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002181 int width,
2182 int precision,
2183 int base)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002184{
2185 BOOLEAN_T isNegative;
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002186 BOOLEAN_T isNumberZero;
2187 BOOLEAN_T isPrecisionZero;
2188 BOOLEAN_T ignoreNumber;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002189 char buffer[MAX_CHARS_IN(trio_uintmax_t) * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002190 char *bufferend;
2191 char *pointer;
Bjorn Reese026d29f2002-01-19 15:40:18 +00002192 TRIO_CONST char *digits;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002193 int i;
2194 int length;
2195 char *p;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002196 int count;
2197
2198 assert(VALID(self));
2199 assert(VALID(self->OutStream));
Bjorn Reese026d29f2002-01-19 15:40:18 +00002200 assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002201
Bjorn Reese70a9da52001-04-21 16:57:29 +00002202 digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002203 if (base == NO_BASE)
2204 base = BASE_DECIMAL;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002205
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002206 isNumberZero = (number == 0);
2207 isPrecisionZero = (precision == 0);
2208 ignoreNumber = (isNumberZero
2209 && isPrecisionZero
2210 && !((flags & FLAGS_ALTERNATIVE) && (base == BASE_OCTAL)));
2211
2212 if (flags & FLAGS_UNSIGNED)
2213 {
2214 isNegative = FALSE;
2215 flags &= ~FLAGS_SHOWSIGN;
2216 }
2217 else
2218 {
2219 isNegative = ((trio_intmax_t)number < 0);
2220 if (isNegative)
2221 number = -((trio_intmax_t)number);
2222 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002223
2224 if (flags & FLAGS_QUAD)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002225 number &= (trio_ulonglong_t)-1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002226 else if (flags & FLAGS_LONG)
2227 number &= (unsigned long)-1;
2228 else
2229 number &= (unsigned int)-1;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002230
Daniel Veillard92ad2102001-03-27 12:47:33 +00002231 /* Build number */
2232 pointer = bufferend = &buffer[sizeof(buffer) - 1];
2233 *pointer-- = NIL;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002234 for (i = 1; i < (int)sizeof(buffer); i++)
2235 {
2236 *pointer-- = digits[number % base];
2237 number /= base;
2238 if (number == 0)
2239 break;
2240
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002241 if ((flags & FLAGS_QUOTE) && TrioFollowedBySeparator(i + 1))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002242 {
2243 /*
2244 * We are building the number from the least significant
2245 * to the most significant digit, so we have to copy the
2246 * thousand separator backwards
2247 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002248 length = internalThousandSeparatorLength;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002249 if (((int)(pointer - buffer) - length) > 0)
2250 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002251 p = &internalThousandSeparator[length - 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002252 while (length-- > 0)
2253 *pointer-- = *p--;
2254 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002255 }
2256 }
2257
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002258 if (! ignoreNumber)
2259 {
2260 /* Adjust width */
2261 width -= (bufferend - pointer) - 1;
2262 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002263
2264 /* Adjust precision */
2265 if (NO_PRECISION != precision)
2266 {
2267 precision -= (bufferend - pointer) - 1;
2268 if (precision < 0)
2269 precision = 0;
2270 flags |= FLAGS_NILPADDING;
2271 }
2272
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002273 /* Calculate padding */
2274 count = (! ((flags & FLAGS_LEFTADJUST) || (precision == NO_PRECISION)))
2275 ? precision
2276 : 0;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002277
Daniel Veillard92ad2102001-03-27 12:47:33 +00002278 /* Adjust width further */
2279 if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
2280 width--;
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002281 if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002282 {
2283 switch (base)
2284 {
2285 case BASE_BINARY:
2286 case BASE_HEX:
2287 width -= 2;
2288 break;
2289 case BASE_OCTAL:
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002290 if (!(flags & FLAGS_NILPADDING) || (count == 0))
2291 width--;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002292 break;
2293 default:
2294 break;
2295 }
2296 }
2297
2298 /* Output prefixes spaces if needed */
2299 if (! ((flags & FLAGS_LEFTADJUST) ||
2300 ((flags & FLAGS_NILPADDING) && (precision == NO_PRECISION))))
2301 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00002302 while (width-- > count)
2303 self->OutStream(self, CHAR_ADJUST);
2304 }
2305
2306 /* width has been adjusted for signs and alternatives */
2307 if (isNegative)
2308 self->OutStream(self, '-');
2309 else if (flags & FLAGS_SHOWSIGN)
2310 self->OutStream(self, '+');
2311 else if (flags & FLAGS_SPACE)
2312 self->OutStream(self, ' ');
2313
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002314 /* Prefix is not written when the value is zero */
2315 if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002316 {
2317 switch (base)
2318 {
2319 case BASE_BINARY:
2320 self->OutStream(self, '0');
2321 self->OutStream(self, (flags & FLAGS_UPPER) ? 'B' : 'b');
2322 break;
2323
2324 case BASE_OCTAL:
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002325 if (!(flags & FLAGS_NILPADDING) || (count == 0))
2326 self->OutStream(self, '0');
Daniel Veillard92ad2102001-03-27 12:47:33 +00002327 break;
2328
2329 case BASE_HEX:
2330 self->OutStream(self, '0');
2331 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2332 break;
2333
2334 default:
2335 break;
2336 } /* switch base */
2337 }
2338
2339 /* Output prefixed zero padding if needed */
2340 if (flags & FLAGS_NILPADDING)
2341 {
2342 if (precision == NO_PRECISION)
2343 precision = width;
2344 while (precision-- > 0)
2345 {
2346 self->OutStream(self, '0');
2347 width--;
2348 }
2349 }
2350
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002351 if (! ignoreNumber)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002352 {
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002353 /* Output the number itself */
2354 while (*(++pointer))
2355 {
2356 self->OutStream(self, *pointer);
2357 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002358 }
2359
2360 /* Output trailing spaces if needed */
2361 if (flags & FLAGS_LEFTADJUST)
2362 {
2363 while (width-- > 0)
2364 self->OutStream(self, CHAR_ADJUST);
2365 }
2366}
2367
2368/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002369 * TrioWriteStringCharacter
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002370 *
2371 * Description:
2372 * Output a single character of a string
2373 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00002374TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002375TrioWriteStringCharacter
2376TRIO_ARGS3((self, ch, flags),
2377 trio_class_t *self,
2378 int ch,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002379 trio_flags_t flags)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002380{
2381 if (flags & FLAGS_ALTERNATIVE)
2382 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002383 if (! isprint(ch))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002384 {
2385 /*
2386 * Non-printable characters are converted to C escapes or
2387 * \number, if no C escape exists.
2388 */
2389 self->OutStream(self, CHAR_BACKSLASH);
2390 switch (ch)
2391 {
2392 case '\007': self->OutStream(self, 'a'); break;
2393 case '\b': self->OutStream(self, 'b'); break;
2394 case '\f': self->OutStream(self, 'f'); break;
2395 case '\n': self->OutStream(self, 'n'); break;
2396 case '\r': self->OutStream(self, 'r'); break;
2397 case '\t': self->OutStream(self, 't'); break;
2398 case '\v': self->OutStream(self, 'v'); break;
2399 case '\\': self->OutStream(self, '\\'); break;
2400 default:
2401 self->OutStream(self, 'x');
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002402 TrioWriteNumber(self, (trio_uintmax_t)ch,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002403 FLAGS_UNSIGNED | FLAGS_NILPADDING,
2404 2, 2, BASE_HEX);
2405 break;
2406 }
2407 }
2408 else if (ch == CHAR_BACKSLASH)
2409 {
2410 self->OutStream(self, CHAR_BACKSLASH);
2411 self->OutStream(self, CHAR_BACKSLASH);
2412 }
2413 else
2414 {
2415 self->OutStream(self, ch);
2416 }
2417 }
2418 else
2419 {
2420 self->OutStream(self, ch);
2421 }
2422}
2423
2424/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002425 * TrioWriteString
Daniel Veillard92ad2102001-03-27 12:47:33 +00002426 *
2427 * Description:
2428 * Output a string
2429 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00002430TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002431TrioWriteString
2432TRIO_ARGS5((self, string, flags, width, precision),
2433 trio_class_t *self,
2434 TRIO_CONST char *string,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002435 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002436 int width,
2437 int precision)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002438{
2439 int length;
2440 int ch;
2441
2442 assert(VALID(self));
2443 assert(VALID(self->OutStream));
2444
2445 if (string == NULL)
2446 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00002447 string = internalNullString;
2448 length = sizeof(internalNullString) - 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002449 /* Disable quoting for the null pointer */
2450 flags &= (~FLAGS_QUOTE);
2451 width = 0;
2452 }
2453 else
2454 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00002455 length = trio_length(string);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002456 }
2457 if ((NO_PRECISION != precision) &&
2458 (precision < length))
2459 {
2460 length = precision;
2461 }
2462 width -= length;
2463
2464 if (flags & FLAGS_QUOTE)
2465 self->OutStream(self, CHAR_QUOTE);
2466
2467 if (! (flags & FLAGS_LEFTADJUST))
2468 {
2469 while (width-- > 0)
2470 self->OutStream(self, CHAR_ADJUST);
2471 }
2472
2473 while (length-- > 0)
2474 {
2475 /* The ctype parameters must be an unsigned char (or EOF) */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002476 ch = (int)((unsigned char)(*string++));
2477 TrioWriteStringCharacter(self, ch, flags);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002478 }
2479
2480 if (flags & FLAGS_LEFTADJUST)
2481 {
2482 while (width-- > 0)
2483 self->OutStream(self, CHAR_ADJUST);
2484 }
2485 if (flags & FLAGS_QUOTE)
2486 self->OutStream(self, CHAR_QUOTE);
2487}
2488
2489/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002490 * TrioWriteWideStringCharacter
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002491 *
2492 * Description:
2493 * Output a wide string as a multi-byte sequence
2494 */
2495#if TRIO_WIDECHAR
Bjorn Reese026d29f2002-01-19 15:40:18 +00002496TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002497TrioWriteWideStringCharacter
2498TRIO_ARGS4((self, wch, flags, width),
2499 trio_class_t *self,
2500 trio_wchar_t wch,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002501 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002502 int width)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002503{
2504 int size;
2505 int i;
2506 int ch;
2507 char *string;
2508 char buffer[MB_LEN_MAX + 1];
2509
2510 if (width == NO_WIDTH)
2511 width = sizeof(buffer);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002512
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002513 size = wctomb(buffer, wch);
2514 if ((size <= 0) || (size > width) || (buffer[0] == NIL))
2515 return 0;
2516
2517 string = buffer;
2518 i = size;
2519 while ((width >= i) && (width-- > 0) && (i-- > 0))
2520 {
2521 /* The ctype parameters must be an unsigned char (or EOF) */
2522 ch = (int)((unsigned char)(*string++));
2523 TrioWriteStringCharacter(self, ch, flags);
2524 }
2525 return size;
2526}
2527#endif /* TRIO_WIDECHAR */
2528
2529/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002530 * TrioWriteWideString
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002531 *
2532 * Description:
2533 * Output a wide character string as a multi-byte string
2534 */
2535#if TRIO_WIDECHAR
Bjorn Reese026d29f2002-01-19 15:40:18 +00002536TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002537TrioWriteWideString
2538TRIO_ARGS5((self, wstring, flags, width, precision),
2539 trio_class_t *self,
2540 TRIO_CONST trio_wchar_t *wstring,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002541 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002542 int width,
2543 int precision)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002544{
2545 int length;
2546 int size;
2547
2548 assert(VALID(self));
2549 assert(VALID(self->OutStream));
2550
2551#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002552 (void)mblen(NULL, 0);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002553#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002554
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002555 if (wstring == NULL)
2556 {
2557 TrioWriteString(self, NULL, flags, width, precision);
2558 return;
2559 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002560
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002561 if (NO_PRECISION == precision)
2562 {
2563 length = INT_MAX;
2564 }
2565 else
2566 {
2567 length = precision;
2568 width -= length;
2569 }
2570
2571 if (flags & FLAGS_QUOTE)
2572 self->OutStream(self, CHAR_QUOTE);
2573
2574 if (! (flags & FLAGS_LEFTADJUST))
2575 {
2576 while (width-- > 0)
2577 self->OutStream(self, CHAR_ADJUST);
2578 }
2579
2580 while (length > 0)
2581 {
2582 size = TrioWriteWideStringCharacter(self, *wstring++, flags, length);
2583 if (size == 0)
2584 break; /* while */
2585 length -= size;
2586 }
2587
2588 if (flags & FLAGS_LEFTADJUST)
2589 {
2590 while (width-- > 0)
2591 self->OutStream(self, CHAR_ADJUST);
2592 }
2593 if (flags & FLAGS_QUOTE)
2594 self->OutStream(self, CHAR_QUOTE);
2595}
2596#endif /* TRIO_WIDECHAR */
2597
2598/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002599 * TrioWriteDouble
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002600 *
2601 * http://wwwold.dkuug.dk/JTC1/SC22/WG14/www/docs/dr_211.htm
2602 *
2603 * "5.2.4.2.2 paragraph #4
2604 *
2605 * The accuracy [...] is implementation defined, as is the accuracy
2606 * of the conversion between floating-point internal representations
2607 * and string representations performed by the libray routine in
2608 * <stdio.h>"
2609 */
2610/* FIXME: handle all instances of constant long-double number (L)
2611 * and *l() math functions.
Daniel Veillard92ad2102001-03-27 12:47:33 +00002612 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00002613TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002614TrioWriteDouble
2615TRIO_ARGS6((self, number, flags, width, precision, base),
2616 trio_class_t *self,
2617 trio_long_double_t number,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002618 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002619 int width,
2620 int precision,
2621 int base)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002622{
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002623 trio_long_double_t integerNumber;
2624 trio_long_double_t fractionNumber;
2625 trio_long_double_t workNumber;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002626 int integerDigits;
2627 int fractionDigits;
2628 int exponentDigits;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002629 int baseDigits;
2630 int integerThreshold;
2631 int fractionThreshold;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002632 int expectedWidth;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002633 int exponent = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002634 unsigned int uExponent = 0;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002635 int exponentBase;
2636 trio_long_double_t dblBase;
2637 trio_long_double_t dblIntegerBase;
2638 trio_long_double_t dblFractionBase;
2639 trio_long_double_t integerAdjust;
2640 trio_long_double_t fractionAdjust;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002641 BOOLEAN_T isNegative;
2642 BOOLEAN_T isExponentNegative = FALSE;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002643 BOOLEAN_T requireTwoDigitExponent;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002644 BOOLEAN_T isHex;
Bjorn Reese026d29f2002-01-19 15:40:18 +00002645 TRIO_CONST char *digits;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002646 char *groupingPointer;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002647 int i;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002648 int index;
2649 BOOLEAN_T hasOnlyZeroes;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002650 int zeroes = 0;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002651 register int trailingZeroes;
2652 BOOLEAN_T keepTrailingZeroes;
2653 BOOLEAN_T keepDecimalPoint;
2654 trio_long_double_t epsilon;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002655
Daniel Veillard92ad2102001-03-27 12:47:33 +00002656 assert(VALID(self));
2657 assert(VALID(self->OutStream));
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002658 assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002659
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002660 /* Determine sign and look for special quantities */
2661 switch (trio_fpclassify_and_signbit(number, &isNegative))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002662 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002663 case TRIO_FP_NAN:
Daniel Veillard92ad2102001-03-27 12:47:33 +00002664 TrioWriteString(self,
2665 (flags & FLAGS_UPPER)
2666 ? NAN_UPPER
2667 : NAN_LOWER,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002668 flags, width, precision);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002669 return;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002670
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002671 case TRIO_FP_INFINITE:
2672 if (isNegative)
2673 {
2674 /* Negative infinity */
2675 TrioWriteString(self,
2676 (flags & FLAGS_UPPER)
2677 ? "-" INFINITE_UPPER
2678 : "-" INFINITE_LOWER,
2679 flags, width, precision);
2680 return;
2681 }
2682 else
2683 {
2684 /* Positive infinity */
2685 TrioWriteString(self,
2686 (flags & FLAGS_UPPER)
2687 ? INFINITE_UPPER
2688 : INFINITE_LOWER,
2689 flags, width, precision);
2690 return;
2691 }
2692
2693 default:
2694 /* Finitude */
2695 break;
2696 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002697
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002698 /* Normal numbers */
2699 if (flags & FLAGS_LONGDOUBLE)
2700 {
2701 baseDigits = (base == 10)
2702 ? LDBL_DIG
2703 : (int)floor(LDBL_MANT_DIG / TrioLogarithmBase(base));
2704 epsilon = LDBL_EPSILON;
2705 }
2706 else if (flags & FLAGS_SHORT)
2707 {
2708 baseDigits = (base == BASE_DECIMAL)
2709 ? FLT_DIG
2710 : (int)floor(FLT_MANT_DIG / TrioLogarithmBase(base));
2711 epsilon = FLT_EPSILON;
2712 }
2713 else
2714 {
2715 baseDigits = (base == BASE_DECIMAL)
2716 ? DBL_DIG
2717 : (int)floor(DBL_MANT_DIG / TrioLogarithmBase(base));
2718 epsilon = DBL_EPSILON;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002719 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002720
Bjorn Reese70a9da52001-04-21 16:57:29 +00002721 digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002722 isHex = (base == BASE_HEX);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002723 if (base == NO_BASE)
2724 base = BASE_DECIMAL;
2725 dblBase = (trio_long_double_t)base;
2726 keepTrailingZeroes = !( (flags & FLAGS_ROUNDING) ||
2727 ( (flags & FLAGS_FLOAT_G) &&
2728 !(flags & FLAGS_ALTERNATIVE) ) );
2729
2730 if (flags & FLAGS_ROUNDING)
2731 precision = baseDigits;
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002732
Daniel Veillard92ad2102001-03-27 12:47:33 +00002733 if (precision == NO_PRECISION)
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002734 {
2735 if (isHex)
2736 {
2737 keepTrailingZeroes = FALSE;
2738 precision = FLT_MANT_DIG;
2739 }
2740 else
2741 {
2742 precision = FLT_DIG;
2743 }
2744 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002745
Daniel Veillard92ad2102001-03-27 12:47:33 +00002746 if (isNegative)
2747 number = -number;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002748
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002749 if (isHex)
2750 flags |= FLAGS_FLOAT_E;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002751
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002752 if (flags & FLAGS_FLOAT_G)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002753 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00002754 if (precision == 0)
2755 precision = 1;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002756
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002757 if ((number < 1.0E-4) || (number > powl(base,
2758 (trio_long_double_t)precision)))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002759 {
2760 /* Use scientific notation */
2761 flags |= FLAGS_FLOAT_E;
2762 }
2763 else if (number < 1.0)
2764 {
2765 /*
2766 * Use normal notation. If the integer part of the number is
2767 * zero, then adjust the precision to include leading fractional
2768 * zeros.
2769 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002770 workNumber = TrioLogarithm(number, base);
2771 workNumber = TRIO_FABS(workNumber);
2772 if (workNumber - floorl(workNumber) < 0.001)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002773 workNumber--;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002774 zeroes = (int)floorl(workNumber);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002775 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002776 }
2777
2778 if (flags & FLAGS_FLOAT_E)
2779 {
2780 /* Scale the number */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002781 workNumber = TrioLogarithm(number, base);
Bjorn Reese45029602001-08-21 09:23:53 +00002782 if (trio_isinf(workNumber) == -1)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002783 {
2784 exponent = 0;
2785 /* Undo setting */
2786 if (flags & FLAGS_FLOAT_G)
2787 flags &= ~FLAGS_FLOAT_E;
2788 }
2789 else
2790 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002791 exponent = (int)floorl(workNumber);
2792 number /= powl(dblBase, (trio_long_double_t)exponent);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002793 isExponentNegative = (exponent < 0);
2794 uExponent = (isExponentNegative) ? -exponent : exponent;
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002795 if (isHex)
2796 uExponent *= 4; /* log16(2) */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002797 /* No thousand separators */
2798 flags &= ~FLAGS_QUOTE;
2799 }
2800 }
2801
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002802 integerNumber = floorl(number);
2803 fractionNumber = number - integerNumber;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002804
Daniel Veillard92ad2102001-03-27 12:47:33 +00002805 /*
2806 * Truncated number.
2807 *
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002808 * Precision is number of significant digits for FLOAT_G
2809 * and number of fractional digits for others.
Daniel Veillard92ad2102001-03-27 12:47:33 +00002810 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002811 integerDigits = (integerNumber > epsilon)
2812 ? 1 + (int)TrioLogarithm(integerNumber, base)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002813 : 1;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002814 fractionDigits = ((flags & FLAGS_FLOAT_G) && (zeroes == 0))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002815 ? precision - integerDigits
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002816 : zeroes + precision;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002817
2818 dblFractionBase = TrioPower(base, fractionDigits);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002819
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002820 workNumber = number + 0.5 / dblFractionBase;
2821 if (floorl(number) != floorl(workNumber))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002822 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002823 if (flags & FLAGS_FLOAT_E)
2824 {
2825 /* Adjust if number was rounded up one digit (ie. 0.99 to 1.00) */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002826 exponent++;
2827 isExponentNegative = (exponent < 0);
2828 uExponent = (isExponentNegative) ? -exponent : exponent;
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002829 if (isHex)
2830 uExponent *= 4; /* log16(2) */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002831 workNumber = (number + 0.5 / dblFractionBase) / dblBase;
2832 integerNumber = floorl(workNumber);
2833 fractionNumber = workNumber - integerNumber;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002834 }
2835 else
2836 {
2837 /* Adjust if number was rounded up one digit (ie. 99 to 100) */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002838 integerNumber = floorl(number + 0.5);
2839 fractionNumber = 0.0;
2840 integerDigits = (integerNumber > epsilon)
2841 ? 1 + (int)TrioLogarithm(integerNumber, base)
2842 : 1;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002843 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002844 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002845
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002846 /* Estimate accuracy */
2847 integerAdjust = fractionAdjust = 0.5;
2848 if (flags & FLAGS_ROUNDING)
2849 {
2850 if (integerDigits > baseDigits)
2851 {
2852 integerThreshold = baseDigits;
2853 fractionDigits = 0;
2854 dblFractionBase = 1.0;
2855 fractionThreshold = 0;
2856 precision = 0; /* Disable decimal-point */
2857 integerAdjust = TrioPower(base, integerDigits - integerThreshold - 1);
2858 fractionAdjust = 0.0;
2859 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002860 else
Daniel Veillard92ad2102001-03-27 12:47:33 +00002861 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002862 integerThreshold = integerDigits;
2863 fractionThreshold = fractionDigits - integerThreshold;
2864 fractionAdjust = 1.0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002865 }
2866 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002867 else
Daniel Veillard92ad2102001-03-27 12:47:33 +00002868 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002869 integerThreshold = INT_MAX;
2870 fractionThreshold = INT_MAX;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002871 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002872
Bjorn Reese70a9da52001-04-21 16:57:29 +00002873 /*
2874 * Calculate expected width.
Daniel Veillard92ad2102001-03-27 12:47:33 +00002875 * sign + integer part + thousands separators + decimal point
2876 * + fraction + exponent
2877 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002878 fractionAdjust /= dblFractionBase;
2879 hasOnlyZeroes = (floorl((fractionNumber + fractionAdjust) * dblFractionBase) < epsilon);
2880 keepDecimalPoint = ( (flags & FLAGS_ALTERNATIVE) ||
2881 !((precision == 0) ||
2882 (!keepTrailingZeroes && hasOnlyZeroes)) );
2883 if (flags & FLAGS_FLOAT_E)
2884 {
2885 exponentDigits = (uExponent == 0)
2886 ? 1
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002887 : (int)ceil(TrioLogarithm((double)(uExponent + 1),
2888 (isHex) ? 10.0 : base));
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002889 }
2890 else
2891 exponentDigits = 0;
2892 requireTwoDigitExponent = ((base == BASE_DECIMAL) && (exponentDigits == 1));
2893
2894 expectedWidth = integerDigits + fractionDigits
2895 + (keepDecimalPoint
2896 ? internalDecimalPointLength
2897 : 0)
2898 + ((flags & FLAGS_QUOTE)
2899 ? TrioCalcThousandSeparatorLength(integerDigits)
2900 : 0);
2901 if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002902 expectedWidth += sizeof("-") - 1;
2903 if (exponentDigits > 0)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002904 expectedWidth += exponentDigits +
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002905 ((requireTwoDigitExponent ? sizeof("E+0") : sizeof("E+")) - 1);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002906 if (isHex)
2907 expectedWidth += sizeof("0X") - 1;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002908
Daniel Veillard92ad2102001-03-27 12:47:33 +00002909 /* Output prefixing */
2910 if (flags & FLAGS_NILPADDING)
2911 {
2912 /* Leading zeros must be after sign */
2913 if (isNegative)
2914 self->OutStream(self, '-');
2915 else if (flags & FLAGS_SHOWSIGN)
2916 self->OutStream(self, '+');
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002917 else if (flags & FLAGS_SPACE)
2918 self->OutStream(self, ' ');
Daniel Veillard92ad2102001-03-27 12:47:33 +00002919 if (isHex)
2920 {
2921 self->OutStream(self, '0');
2922 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2923 }
2924 if (!(flags & FLAGS_LEFTADJUST))
2925 {
2926 for (i = expectedWidth; i < width; i++)
2927 {
2928 self->OutStream(self, '0');
2929 }
2930 }
2931 }
2932 else
2933 {
2934 /* Leading spaces must be before sign */
2935 if (!(flags & FLAGS_LEFTADJUST))
2936 {
2937 for (i = expectedWidth; i < width; i++)
2938 {
2939 self->OutStream(self, CHAR_ADJUST);
2940 }
2941 }
2942 if (isNegative)
2943 self->OutStream(self, '-');
2944 else if (flags & FLAGS_SHOWSIGN)
2945 self->OutStream(self, '+');
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002946 else if (flags & FLAGS_SPACE)
2947 self->OutStream(self, ' ');
Daniel Veillard92ad2102001-03-27 12:47:33 +00002948 if (isHex)
2949 {
2950 self->OutStream(self, '0');
2951 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2952 }
2953 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002954
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002955 /* Output the integer part and thousand separators */
2956 dblIntegerBase = 1.0 / TrioPower(base, integerDigits - 1);
2957 for (i = 0; i < integerDigits; i++)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002958 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002959 workNumber = floorl(((integerNumber + integerAdjust) * dblIntegerBase));
2960 if (i > integerThreshold)
2961 {
2962 /* Beyond accuracy */
2963 self->OutStream(self, digits[0]);
2964 }
2965 else
2966 {
2967 self->OutStream(self, digits[(int)fmodl(workNumber, dblBase)]);
2968 }
2969 dblIntegerBase *= dblBase;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002970
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002971 if (((flags & (FLAGS_FLOAT_E | FLAGS_QUOTE)) == FLAGS_QUOTE)
2972 && TrioFollowedBySeparator(integerDigits - i))
2973 {
2974 for (groupingPointer = internalThousandSeparator;
2975 *groupingPointer != NIL;
2976 groupingPointer++)
2977 {
2978 self->OutStream(self, *groupingPointer);
2979 }
2980 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002981 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002982
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002983 /* Insert decimal point and build the fraction part */
2984 trailingZeroes = 0;
2985
2986 if (keepDecimalPoint)
2987 {
2988 if (internalDecimalPoint)
2989 {
2990 self->OutStream(self, internalDecimalPoint);
2991 }
2992 else
2993 {
2994 for (i = 0; i < internalDecimalPointLength; i++)
2995 {
2996 self->OutStream(self, internalDecimalPointString[i]);
2997 }
2998 }
2999 }
3000
3001 for (i = 0; i < fractionDigits; i++)
3002 {
3003 if ((integerDigits > integerThreshold) || (i > fractionThreshold))
3004 {
3005 /* Beyond accuracy */
3006 trailingZeroes++;
3007 }
3008 else
3009 {
3010 fractionNumber *= dblBase;
3011 fractionAdjust *= dblBase;
3012 workNumber = floorl(fractionNumber + fractionAdjust);
3013 fractionNumber -= workNumber;
3014 index = (int)fmodl(workNumber, dblBase);
3015 if (index == 0)
3016 {
3017 trailingZeroes++;
3018 }
3019 else
3020 {
3021 while (trailingZeroes > 0)
3022 {
3023 /* Not trailing zeroes after all */
3024 self->OutStream(self, digits[0]);
3025 trailingZeroes--;
3026 }
3027 self->OutStream(self, digits[index]);
3028 }
3029 }
3030 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003031
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003032 if (keepTrailingZeroes)
3033 {
3034 while (trailingZeroes > 0)
3035 {
3036 self->OutStream(self, digits[0]);
3037 trailingZeroes--;
3038 }
3039 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003040
Daniel Veillard92ad2102001-03-27 12:47:33 +00003041 /* Output exponent */
3042 if (exponentDigits > 0)
3043 {
3044 self->OutStream(self,
3045 isHex
3046 ? ((flags & FLAGS_UPPER) ? 'P' : 'p')
3047 : ((flags & FLAGS_UPPER) ? 'E' : 'e'));
3048 self->OutStream(self, (isExponentNegative) ? '-' : '+');
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003049
3050 /* The exponent must contain at least two digits */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003051 if (requireTwoDigitExponent)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003052 self->OutStream(self, '0');
3053
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00003054 if (isHex)
3055 base = 10.0;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003056 exponentBase = (int)TrioPower(base, exponentDigits - 1);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003057 for (i = 0; i < exponentDigits; i++)
3058 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003059 self->OutStream(self, digits[(uExponent / exponentBase) % base]);
3060 exponentBase /= base;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003061 }
3062 }
3063 /* Output trailing spaces */
3064 if (flags & FLAGS_LEFTADJUST)
3065 {
3066 for (i = expectedWidth; i < width; i++)
3067 {
3068 self->OutStream(self, CHAR_ADJUST);
3069 }
3070 }
3071}
3072
3073/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003074 * TrioFormatProcess
3075 *
3076 * Description:
3077 * This is the main engine for formatting output
Daniel Veillard92ad2102001-03-27 12:47:33 +00003078 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003079TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003080TrioFormatProcess
3081TRIO_ARGS3((data, format, parameters),
3082 trio_class_t *data,
3083 TRIO_CONST char *format,
3084 trio_parameter_t *parameters)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003085{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003086#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003087 int charlen;
3088#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +00003089 int i;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003090 TRIO_CONST char *string;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003091 trio_pointer_t pointer;
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00003092 trio_flags_t flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003093 int width;
3094 int precision;
3095 int base;
3096 int index;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003097
Daniel Veillard92ad2102001-03-27 12:47:33 +00003098 index = 0;
3099 i = 0;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003100#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003101 (void)mblen(NULL, 0);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003102#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003103
Daniel Veillard92ad2102001-03-27 12:47:33 +00003104 while (format[index])
3105 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003106#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003107 if (! isascii(format[index]))
3108 {
3109 charlen = mblen(&format[index], MB_LEN_MAX);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003110 /*
3111 * Only valid multibyte characters are handled here. Invalid
3112 * multibyte characters (charlen == -1) are handled as normal
3113 * characters.
3114 */
3115 if (charlen != -1)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003116 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003117 while (charlen-- > 0)
3118 {
3119 data->OutStream(data, format[index++]);
3120 }
3121 continue; /* while characters left in formatting string */
Daniel Veillard92ad2102001-03-27 12:47:33 +00003122 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003123 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003124#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
Daniel Veillard92ad2102001-03-27 12:47:33 +00003125 if (CHAR_IDENTIFIER == format[index])
3126 {
3127 if (CHAR_IDENTIFIER == format[index + 1])
3128 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00003129 data->OutStream(data, CHAR_IDENTIFIER);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003130 index += 2;
3131 }
3132 else
3133 {
3134 /* Skip the parameter entries */
3135 while (parameters[i].type == FORMAT_PARAMETER)
3136 i++;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003137
Daniel Veillard92ad2102001-03-27 12:47:33 +00003138 flags = parameters[i].flags;
3139
3140 /* Find width */
3141 width = parameters[i].width;
3142 if (flags & FLAGS_WIDTH_PARAMETER)
3143 {
3144 /* Get width from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00003145 width = (int)parameters[width].data.number.as_signed;
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00003146 if (width < 0)
3147 {
3148 /*
3149 * A negative width is the same as the - flag and
3150 * a positive width.
3151 */
3152 flags |= FLAGS_LEFTADJUST;
3153 flags &= ~FLAGS_NILPADDING;
3154 width = -width;
3155 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003156 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003157
Daniel Veillard92ad2102001-03-27 12:47:33 +00003158 /* Find precision */
3159 if (flags & FLAGS_PRECISION)
3160 {
3161 precision = parameters[i].precision;
3162 if (flags & FLAGS_PRECISION_PARAMETER)
3163 {
3164 /* Get precision from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00003165 precision = (int)parameters[precision].data.number.as_signed;
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00003166 if (precision < 0)
3167 {
3168 /*
3169 * A negative precision is the same as no
3170 * precision
3171 */
3172 precision = NO_PRECISION;
3173 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003174 }
3175 }
3176 else
3177 {
3178 precision = NO_PRECISION;
3179 }
3180
3181 /* Find base */
3182 base = parameters[i].base;
3183 if (flags & FLAGS_BASE_PARAMETER)
3184 {
3185 /* Get base from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00003186 base = (int)parameters[base].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003187 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003188
Daniel Veillard92ad2102001-03-27 12:47:33 +00003189 switch (parameters[i].type)
3190 {
3191 case FORMAT_CHAR:
3192 if (flags & FLAGS_QUOTE)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003193 data->OutStream(data, CHAR_QUOTE);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003194 if (! (flags & FLAGS_LEFTADJUST))
3195 {
3196 while (--width > 0)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003197 data->OutStream(data, CHAR_ADJUST);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003198 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003199#if TRIO_WIDECHAR
3200 if (flags & FLAGS_WIDECHAR)
3201 {
3202 TrioWriteWideStringCharacter(data,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003203 (trio_wchar_t)parameters[i].data.number.as_signed,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003204 flags,
3205 NO_WIDTH);
3206 }
3207 else
3208#endif
Bjorn Reese026d29f2002-01-19 15:40:18 +00003209 {
3210 TrioWriteStringCharacter(data,
3211 (int)parameters[i].data.number.as_signed,
3212 flags);
3213 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003214
3215 if (flags & FLAGS_LEFTADJUST)
3216 {
3217 while(--width > 0)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003218 data->OutStream(data, CHAR_ADJUST);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003219 }
3220 if (flags & FLAGS_QUOTE)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003221 data->OutStream(data, CHAR_QUOTE);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003222
3223 break; /* FORMAT_CHAR */
3224
3225 case FORMAT_INT:
Daniel Veillard92ad2102001-03-27 12:47:33 +00003226 TrioWriteNumber(data,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003227 parameters[i].data.number.as_unsigned,
Daniel Veillard92ad2102001-03-27 12:47:33 +00003228 flags,
3229 width,
3230 precision,
3231 base);
3232
3233 break; /* FORMAT_INT */
3234
3235 case FORMAT_DOUBLE:
3236 TrioWriteDouble(data,
3237 parameters[i].data.longdoubleNumber,
3238 flags,
3239 width,
3240 precision,
3241 base);
3242 break; /* FORMAT_DOUBLE */
3243
3244 case FORMAT_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003245#if TRIO_WIDECHAR
3246 if (flags & FLAGS_WIDECHAR)
3247 {
3248 TrioWriteWideString(data,
3249 parameters[i].data.wstring,
3250 flags,
3251 width,
3252 precision);
3253 }
3254 else
3255#endif
3256 {
3257 TrioWriteString(data,
3258 parameters[i].data.string,
3259 flags,
3260 width,
3261 precision);
3262 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003263 break; /* FORMAT_STRING */
3264
3265 case FORMAT_POINTER:
Bjorn Reese70a9da52001-04-21 16:57:29 +00003266 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00003267 trio_reference_t reference;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003268
Bjorn Reese70a9da52001-04-21 16:57:29 +00003269 reference.data = data;
3270 reference.parameter = &parameters[i];
3271 trio_print_pointer(&reference, parameters[i].data.pointer);
3272 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003273 break; /* FORMAT_POINTER */
3274
3275 case FORMAT_COUNT:
3276 pointer = parameters[i].data.pointer;
3277 if (NULL != pointer)
3278 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00003279 /*
3280 * C99 paragraph 7.19.6.1.8 says "the number of
Daniel Veillard92ad2102001-03-27 12:47:33 +00003281 * characters written to the output stream so far by
3282 * this call", which is data->committed
3283 */
3284#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
3285 if (flags & FLAGS_SIZE_T)
3286 *(size_t *)pointer = (size_t)data->committed;
3287 else
3288#endif
3289#if defined(QUALIFIER_PTRDIFF_T)
3290 if (flags & FLAGS_PTRDIFF_T)
3291 *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
3292 else
3293#endif
3294#if defined(QUALIFIER_INTMAX_T)
3295 if (flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003296 *(trio_intmax_t *)pointer = (trio_intmax_t)data->committed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003297 else
3298#endif
3299 if (flags & FLAGS_QUAD)
3300 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003301 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->committed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003302 }
3303 else if (flags & FLAGS_LONG)
3304 {
3305 *(long int *)pointer = (long int)data->committed;
3306 }
3307 else if (flags & FLAGS_SHORT)
3308 {
3309 *(short int *)pointer = (short int)data->committed;
3310 }
3311 else
3312 {
3313 *(int *)pointer = (int)data->committed;
3314 }
3315 }
3316 break; /* FORMAT_COUNT */
3317
3318 case FORMAT_PARAMETER:
3319 break; /* FORMAT_PARAMETER */
3320
3321#if defined(FORMAT_ERRNO)
3322 case FORMAT_ERRNO:
Bjorn Reese026d29f2002-01-19 15:40:18 +00003323 string = trio_error(parameters[i].data.errorNumber);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003324 if (string)
3325 {
3326 TrioWriteString(data,
3327 string,
3328 flags,
3329 width,
3330 precision);
3331 }
3332 else
3333 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00003334 data->OutStream(data, '#');
Daniel Veillard92ad2102001-03-27 12:47:33 +00003335 TrioWriteNumber(data,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003336 (trio_uintmax_t)parameters[i].data.errorNumber,
Daniel Veillard92ad2102001-03-27 12:47:33 +00003337 flags,
3338 width,
3339 precision,
3340 BASE_DECIMAL);
3341 }
3342 break; /* FORMAT_ERRNO */
Bjorn Reese70a9da52001-04-21 16:57:29 +00003343#endif /* defined(FORMAT_ERRNO) */
Daniel Veillard92ad2102001-03-27 12:47:33 +00003344
Bjorn Reese70a9da52001-04-21 16:57:29 +00003345#if defined(FORMAT_USER_DEFINED)
3346 case FORMAT_USER_DEFINED:
3347 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00003348 trio_reference_t reference;
3349 trio_userdef_t *def = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003350
3351 if (parameters[i].user_name[0] == NIL)
3352 {
3353 /* Use handle */
3354 if ((i > 0) ||
3355 (parameters[i - 1].type == FORMAT_PARAMETER))
Bjorn Reese026d29f2002-01-19 15:40:18 +00003356 def = (trio_userdef_t *)parameters[i - 1].data.pointer;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003357 }
3358 else
3359 {
3360 /* Look up namespace */
3361 def = TrioFindNamespace(parameters[i].user_name, NULL);
3362 }
3363 if (def) {
3364 reference.data = data;
3365 reference.parameter = &parameters[i];
3366 def->callback(&reference);
3367 }
3368 }
3369 break;
3370#endif /* defined(FORMAT_USER_DEFINED) */
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003371
Daniel Veillard92ad2102001-03-27 12:47:33 +00003372 default:
3373 break;
3374 } /* switch parameter type */
3375
3376 /* Prepare for next */
3377 index = parameters[i].indexAfterSpecifier;
3378 i++;
3379 }
3380 }
3381 else /* not identifier */
3382 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00003383 data->OutStream(data, format[index++]);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003384 }
3385 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003386 return data->processed;
3387}
3388
3389/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003390 * TrioFormatRef
Bjorn Reese70a9da52001-04-21 16:57:29 +00003391 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003392TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003393TrioFormatRef
3394TRIO_ARGS4((reference, format, arglist, argarray),
3395 trio_reference_t *reference,
3396 TRIO_CONST char *format,
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08003397 TRIO_VA_LIST_PTR arglist,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003398 trio_pointer_t *argarray)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003399{
3400 int status;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003401 trio_parameter_t parameters[MAX_PARAMETERS];
Bjorn Reese70a9da52001-04-21 16:57:29 +00003402
Bjorn Reese026d29f2002-01-19 15:40:18 +00003403 status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003404 if (status < 0)
3405 return status;
3406
Bjorn Reese026d29f2002-01-19 15:40:18 +00003407 status = TrioFormatProcess(reference->data, format, parameters);
3408 if (reference->data->error != 0)
3409 {
3410 status = reference->data->error;
3411 }
3412 return status;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003413}
3414
3415/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003416 * TrioFormat
Bjorn Reese70a9da52001-04-21 16:57:29 +00003417 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003418TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003419TrioFormat
3420TRIO_ARGS6((destination, destinationSize, OutStream, format, arglist, argarray),
3421 trio_pointer_t destination,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003422 size_t destinationSize,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003423 void (*OutStream) TRIO_PROTO((trio_class_t *, int)),
Bjorn Reese026d29f2002-01-19 15:40:18 +00003424 TRIO_CONST char *format,
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08003425 TRIO_VA_LIST_PTR arglist,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003426 trio_pointer_t *argarray)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003427{
3428 int status;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003429 trio_class_t data;
3430 trio_parameter_t parameters[MAX_PARAMETERS];
Bjorn Reese70a9da52001-04-21 16:57:29 +00003431
3432 assert(VALID(OutStream));
3433 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003434
3435 memset(&data, 0, sizeof(data));
3436 data.OutStream = OutStream;
3437 data.location = destination;
3438 data.max = destinationSize;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003439 data.error = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003440
3441#if defined(USE_LOCALE)
3442 if (NULL == internalLocaleValues)
3443 {
3444 TrioSetLocale();
3445 }
3446#endif
3447
Bjorn Reese026d29f2002-01-19 15:40:18 +00003448 status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003449 if (status < 0)
3450 return status;
3451
Bjorn Reese026d29f2002-01-19 15:40:18 +00003452 status = TrioFormatProcess(&data, format, parameters);
3453 if (data.error != 0)
3454 {
3455 status = data.error;
3456 }
3457 return status;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003458}
3459
3460/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003461 * TrioOutStreamFile
Daniel Veillard92ad2102001-03-27 12:47:33 +00003462 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003463TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003464TrioOutStreamFile
3465TRIO_ARGS2((self, output),
3466 trio_class_t *self,
3467 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003468{
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003469 FILE *file;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003470
3471 assert(VALID(self));
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003472 assert(VALID(self->location));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003473
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003474 file = (FILE *)self->location;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003475 self->processed++;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003476 if (fputc(output, file) == EOF)
3477 {
3478 self->error = TRIO_ERROR_RETURN(TRIO_EOF, 0);
3479 }
3480 else
3481 {
3482 self->committed++;
3483 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003484}
3485
3486/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003487 * TrioOutStreamFileDescriptor
Daniel Veillard92ad2102001-03-27 12:47:33 +00003488 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003489TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003490TrioOutStreamFileDescriptor
3491TRIO_ARGS2((self, output),
3492 trio_class_t *self,
3493 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003494{
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003495 int fd;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003496 char ch;
3497
3498 assert(VALID(self));
3499
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003500 fd = *((int *)self->location);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003501 ch = (char)output;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003502 self->processed++;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003503 if (write(fd, &ch, sizeof(char)) == -1)
3504 {
3505 self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0);
3506 }
3507 else
3508 {
3509 self->committed++;
3510 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003511}
3512
3513/*************************************************************************
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003514 * TrioOutStreamCustom
3515 */
3516TRIO_PRIVATE void
3517TrioOutStreamCustom
3518TRIO_ARGS2((self, output),
3519 trio_class_t *self,
3520 int output)
3521{
3522 int status;
3523 trio_custom_t *data;
3524
3525 assert(VALID(self));
3526 assert(VALID(self->location));
3527
3528 data = (trio_custom_t *)self->location;
3529 if (data->stream.out)
3530 {
3531 status = (data->stream.out)(data->closure, output);
3532 if (status >= 0)
3533 {
3534 self->committed++;
3535 }
3536 else
3537 {
3538 if (self->error == 0)
3539 {
3540 self->error = TRIO_ERROR_RETURN(TRIO_ECUSTOM, -status);
3541 }
3542 }
3543 }
3544 self->processed++;
3545}
3546
3547/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003548 * TrioOutStreamString
Daniel Veillard92ad2102001-03-27 12:47:33 +00003549 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003550TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003551TrioOutStreamString
3552TRIO_ARGS2((self, output),
3553 trio_class_t *self,
3554 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003555{
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003556 char **buffer;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003557
3558 assert(VALID(self));
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003559 assert(VALID(self->location));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003560
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003561 buffer = (char **)self->location;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003562 **buffer = (char)output;
3563 (*buffer)++;
3564 self->processed++;
3565 self->committed++;
3566}
3567
3568/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003569 * TrioOutStreamStringMax
Daniel Veillard92ad2102001-03-27 12:47:33 +00003570 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003571TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003572TrioOutStreamStringMax
3573TRIO_ARGS2((self, output),
3574 trio_class_t *self,
3575 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003576{
3577 char **buffer;
3578
3579 assert(VALID(self));
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003580 assert(VALID(self->location));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003581
Daniel Veillard92ad2102001-03-27 12:47:33 +00003582 buffer = (char **)self->location;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003583
3584 if (self->processed < self->max)
3585 {
3586 **buffer = (char)output;
3587 (*buffer)++;
3588 self->committed++;
3589 }
3590 self->processed++;
3591}
3592
3593/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003594 * TrioOutStreamStringDynamic
Daniel Veillard92ad2102001-03-27 12:47:33 +00003595 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003596TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003597TrioOutStreamStringDynamic
3598TRIO_ARGS2((self, output),
3599 trio_class_t *self,
3600 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003601{
Daniel Veillard92ad2102001-03-27 12:47:33 +00003602 assert(VALID(self));
3603 assert(VALID(self->location));
3604
Bjorn Reese026d29f2002-01-19 15:40:18 +00003605 if (self->error == 0)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003606 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00003607 trio_xstring_append_char((trio_string_t *)self->location,
3608 (char)output);
3609 self->committed++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003610 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00003611 /* The processed variable must always be increased */
Daniel Veillard92ad2102001-03-27 12:47:33 +00003612 self->processed++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003613}
3614
Daniel Veillard92ad2102001-03-27 12:47:33 +00003615/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003616 *
3617 * Formatted printing functions
3618 *
3619 ************************************************************************/
3620
3621#if defined(TRIO_DOCUMENTATION)
3622# include "doc/doc_printf.h"
3623#endif
3624/** @addtogroup Printf
3625 @{
3626*/
3627
3628/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003629 * printf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003630 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003631
3632/**
3633 Print to standard output stream.
3634
3635 @param format Formatting string.
3636 @param ... Arguments.
3637 @return Number of printed characters.
3638 */
3639TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003640trio_printf
3641TRIO_VARGS2((format, va_alist),
3642 TRIO_CONST char *format,
3643 TRIO_VA_DECL)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003644{
3645 int status;
3646 va_list args;
3647
3648 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003649
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003650 TRIO_VA_START(args, format);
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08003651 status = TrioFormat(stdout, 0, TrioOutStreamFile, format, TRIO_VA_LIST_ADDR(args), NULL);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003652 TRIO_VA_END(args);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003653 return status;
3654}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003655
Bjorn Reese026d29f2002-01-19 15:40:18 +00003656/**
3657 Print to standard output stream.
3658
3659 @param format Formatting string.
3660 @param args Arguments.
3661 @return Number of printed characters.
3662 */
3663TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003664trio_vprintf
3665TRIO_ARGS2((format, args),
3666 TRIO_CONST char *format,
3667 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003668{
3669 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003670
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08003671 return TrioFormat(stdout, 0, TrioOutStreamFile, format, TRIO_VA_LIST_ADDR(args), NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003672}
3673
Bjorn Reese026d29f2002-01-19 15:40:18 +00003674/**
3675 Print to standard output stream.
3676
3677 @param format Formatting string.
3678 @param args Arguments.
3679 @return Number of printed characters.
3680 */
3681TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003682trio_printfv
3683TRIO_ARGS2((format, args),
3684 TRIO_CONST char *format,
3685 trio_pointer_t * args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003686{
3687 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003688
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003689 return TrioFormat(stdout, 0, TrioOutStreamFile, format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003690}
3691
Daniel Veillard92ad2102001-03-27 12:47:33 +00003692/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003693 * fprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003694 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003695
3696/**
3697 Print to file.
3698
3699 @param file File pointer.
3700 @param format Formatting string.
3701 @param ... Arguments.
3702 @return Number of printed characters.
3703 */
3704TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003705trio_fprintf
3706TRIO_VARGS3((file, format, va_alist),
3707 FILE *file,
3708 TRIO_CONST char *format,
3709 TRIO_VA_DECL)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003710{
3711 int status;
3712 va_list args;
3713
3714 assert(VALID(file));
3715 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003716
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003717 TRIO_VA_START(args, format);
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08003718 status = TrioFormat(file, 0, TrioOutStreamFile, format, TRIO_VA_LIST_ADDR(args), NULL);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003719 TRIO_VA_END(args);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003720 return status;
3721}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003722
Bjorn Reese026d29f2002-01-19 15:40:18 +00003723/**
3724 Print to file.
3725
3726 @param file File pointer.
3727 @param format Formatting string.
3728 @param args Arguments.
3729 @return Number of printed characters.
3730 */
3731TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003732trio_vfprintf
3733TRIO_ARGS3((file, format, args),
3734 FILE *file,
3735 TRIO_CONST char *format,
3736 va_list args)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003737{
3738 assert(VALID(file));
3739 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003740
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08003741 return TrioFormat(file, 0, TrioOutStreamFile, format, TRIO_VA_LIST_ADDR(args), NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003742}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003743
Bjorn Reese026d29f2002-01-19 15:40:18 +00003744/**
3745 Print to file.
3746
3747 @param file File pointer.
3748 @param format Formatting string.
3749 @param args Arguments.
3750 @return Number of printed characters.
3751 */
3752TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003753trio_fprintfv
3754TRIO_ARGS3((file, format, args),
3755 FILE *file,
3756 TRIO_CONST char *format,
3757 trio_pointer_t * args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003758{
3759 assert(VALID(file));
3760 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003761
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003762 return TrioFormat(file, 0, TrioOutStreamFile, format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003763}
3764
Daniel Veillard92ad2102001-03-27 12:47:33 +00003765/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003766 * dprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003767 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003768
3769/**
3770 Print to file descriptor.
3771
3772 @param fd File descriptor.
3773 @param format Formatting string.
3774 @param ... Arguments.
3775 @return Number of printed characters.
3776 */
3777TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003778trio_dprintf
3779TRIO_VARGS3((fd, format, va_alist),
3780 int fd,
3781 TRIO_CONST char *format,
3782 TRIO_VA_DECL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003783{
3784 int status;
3785 va_list args;
3786
3787 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003788
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003789 TRIO_VA_START(args, format);
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08003790 status = TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, TRIO_VA_LIST_ADDR(args), NULL);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003791 TRIO_VA_END(args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003792 return status;
3793}
3794
Bjorn Reese026d29f2002-01-19 15:40:18 +00003795/**
3796 Print to file descriptor.
3797
3798 @param fd File descriptor.
3799 @param format Formatting string.
3800 @param args Arguments.
3801 @return Number of printed characters.
3802 */
3803TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003804trio_vdprintf
3805TRIO_ARGS3((fd, format, args),
3806 int fd,
3807 TRIO_CONST char *format,
3808 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003809{
3810 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003811
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08003812 return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, TRIO_VA_LIST_ADDR(args), NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003813}
3814
Bjorn Reese026d29f2002-01-19 15:40:18 +00003815/**
3816 Print to file descriptor.
3817
3818 @param fd File descriptor.
3819 @param format Formatting string.
3820 @param args Arguments.
3821 @return Number of printed characters.
3822 */
3823TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003824trio_dprintfv
3825TRIO_ARGS3((fd, format, args),
3826 int fd,
3827 TRIO_CONST char *format,
3828 trio_pointer_t *args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003829{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003830 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003831
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003832 return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, NULL, args);
3833}
3834
3835/*************************************************************************
3836 * cprintf
3837 */
3838TRIO_PUBLIC int
3839trio_cprintf
3840TRIO_VARGS4((stream, closure, format, va_alist),
3841 trio_outstream_t stream,
3842 trio_pointer_t closure,
3843 TRIO_CONST char *format,
3844 TRIO_VA_DECL)
3845{
3846 int status;
3847 va_list args;
3848 trio_custom_t data;
3849
3850 assert(VALID(stream));
3851 assert(VALID(format));
3852
3853 TRIO_VA_START(args, format);
3854 data.stream.out = stream;
3855 data.closure = closure;
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08003856 status = TrioFormat(&data, 0, TrioOutStreamCustom, format, TRIO_VA_LIST_ADDR(args), NULL);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003857 TRIO_VA_END(args);
3858 return status;
3859}
3860
3861TRIO_PUBLIC int
3862trio_vcprintf
3863TRIO_ARGS4((stream, closure, format, args),
3864 trio_outstream_t stream,
3865 trio_pointer_t closure,
3866 TRIO_CONST char *format,
3867 va_list args)
3868{
3869 trio_custom_t data;
3870
3871 assert(VALID(stream));
3872 assert(VALID(format));
3873
3874 data.stream.out = stream;
3875 data.closure = closure;
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08003876 return TrioFormat(&data, 0, TrioOutStreamCustom, format, TRIO_VA_LIST_ADDR(args), NULL);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003877}
3878
3879TRIO_PUBLIC int
3880trio_cprintfv
3881TRIO_ARGS4((stream, closure, format, args),
3882 trio_outstream_t stream,
3883 trio_pointer_t closure,
3884 TRIO_CONST char *format,
3885 void **args)
3886{
3887 trio_custom_t data;
3888
3889 assert(VALID(stream));
3890 assert(VALID(format));
3891
3892 data.stream.out = stream;
3893 data.closure = closure;
3894 return TrioFormat(&data, 0, TrioOutStreamCustom, format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003895}
3896
3897/*************************************************************************
3898 * sprintf
3899 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003900
3901/**
3902 Print to string.
3903
3904 @param buffer Output string.
3905 @param format Formatting string.
3906 @param ... Arguments.
3907 @return Number of printed characters.
3908 */
3909TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003910trio_sprintf
3911TRIO_VARGS3((buffer, format, va_alist),
3912 char *buffer,
3913 TRIO_CONST char *format,
3914 TRIO_VA_DECL)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003915{
3916 int status;
3917 va_list args;
3918
3919 assert(VALID(buffer));
3920 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003921
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003922 TRIO_VA_START(args, format);
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08003923 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, TRIO_VA_LIST_ADDR(args), NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003924 *buffer = NIL; /* Terminate with NIL character */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003925 TRIO_VA_END(args);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003926 return status;
3927}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003928
Bjorn Reese026d29f2002-01-19 15:40:18 +00003929/**
3930 Print to string.
3931
3932 @param buffer Output string.
3933 @param format Formatting string.
3934 @param args Arguments.
3935 @return Number of printed characters.
3936 */
3937TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003938trio_vsprintf
3939TRIO_ARGS3((buffer, format, args),
3940 char *buffer,
3941 TRIO_CONST char *format,
3942 va_list args)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003943{
3944 int status;
3945
3946 assert(VALID(buffer));
3947 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003948
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08003949 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, TRIO_VA_LIST_ADDR(args), NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003950 *buffer = NIL;
3951 return status;
3952}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003953
Bjorn Reese026d29f2002-01-19 15:40:18 +00003954/**
3955 Print to string.
3956
3957 @param buffer Output string.
3958 @param format Formatting string.
3959 @param args Arguments.
3960 @return Number of printed characters.
3961 */
3962TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003963trio_sprintfv
3964TRIO_ARGS3((buffer, format, args),
3965 char *buffer,
3966 TRIO_CONST char *format,
3967 trio_pointer_t *args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003968{
3969 int status;
3970
3971 assert(VALID(buffer));
3972 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003973
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003974 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003975 *buffer = NIL;
3976 return status;
3977}
3978
Daniel Veillard92ad2102001-03-27 12:47:33 +00003979/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003980 * snprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003981 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003982
3983/**
3984 Print at most @p max characters to string.
3985
3986 @param buffer Output string.
3987 @param max Maximum number of characters to print.
3988 @param format Formatting string.
3989 @param ... Arguments.
3990 @return Number of printed characters.
3991 */
3992TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003993trio_snprintf
3994TRIO_VARGS4((buffer, max, format, va_alist),
3995 char *buffer,
3996 size_t max,
3997 TRIO_CONST char *format,
3998 TRIO_VA_DECL)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003999{
4000 int status;
4001 va_list args;
4002
4003 assert(VALID(buffer));
4004 assert(VALID(format));
4005
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004006 TRIO_VA_START(args, format);
Bjorn Reese026d29f2002-01-19 15:40:18 +00004007 status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08004008 TrioOutStreamStringMax, format, TRIO_VA_LIST_ADDR(args), NULL);
Bjorn Reese026d29f2002-01-19 15:40:18 +00004009 if (max > 0)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004010 *buffer = NIL;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004011 TRIO_VA_END(args);
Daniel Veillard92ad2102001-03-27 12:47:33 +00004012 return status;
4013}
Daniel Veillard92ad2102001-03-27 12:47:33 +00004014
Bjorn Reese026d29f2002-01-19 15:40:18 +00004015/**
4016 Print at most @p max characters to string.
4017
4018 @param buffer Output string.
4019 @param max Maximum number of characters to print.
4020 @param format Formatting string.
4021 @param args Arguments.
4022 @return Number of printed characters.
4023 */
4024TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004025trio_vsnprintf
4026TRIO_ARGS4((buffer, max, format, args),
4027 char *buffer,
4028 size_t max,
4029 TRIO_CONST char *format,
4030 va_list args)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004031{
4032 int status;
4033
4034 assert(VALID(buffer));
4035 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00004036
Bjorn Reese026d29f2002-01-19 15:40:18 +00004037 status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08004038 TrioOutStreamStringMax, format, TRIO_VA_LIST_ADDR(args), NULL);
Bjorn Reese026d29f2002-01-19 15:40:18 +00004039 if (max > 0)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004040 *buffer = NIL;
4041 return status;
4042}
Bjorn Reese70a9da52001-04-21 16:57:29 +00004043
Bjorn Reese026d29f2002-01-19 15:40:18 +00004044/**
4045 Print at most @p max characters to string.
4046
4047 @param buffer Output string.
4048 @param max Maximum number of characters to print.
4049 @param format Formatting string.
4050 @param args Arguments.
4051 @return Number of printed characters.
4052 */
4053TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004054trio_snprintfv
4055TRIO_ARGS4((buffer, max, format, args),
4056 char *buffer,
4057 size_t max,
4058 TRIO_CONST char *format,
4059 trio_pointer_t *args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004060{
4061 int status;
4062
4063 assert(VALID(buffer));
4064 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00004065
Bjorn Reese026d29f2002-01-19 15:40:18 +00004066 status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004067 TrioOutStreamStringMax, format, NULL, args);
Bjorn Reese026d29f2002-01-19 15:40:18 +00004068 if (max > 0)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004069 *buffer = NIL;
4070 return status;
4071}
4072
4073/*************************************************************************
4074 * snprintfcat
4075 * Appends the new string to the buffer string overwriting the '\0'
4076 * character at the end of buffer.
4077 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004078TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004079trio_snprintfcat
4080TRIO_VARGS4((buffer, max, format, va_alist),
4081 char *buffer,
4082 size_t max,
4083 TRIO_CONST char *format,
4084 TRIO_VA_DECL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004085{
4086 int status;
4087 va_list args;
4088 size_t buf_len;
4089
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004090 TRIO_VA_START(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004091
4092 assert(VALID(buffer));
4093 assert(VALID(format));
4094
Bjorn Reese026d29f2002-01-19 15:40:18 +00004095 buf_len = trio_length(buffer);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004096 buffer = &buffer[buf_len];
4097
Bjorn Reese026d29f2002-01-19 15:40:18 +00004098 status = TrioFormat(&buffer, max - 1 - buf_len,
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08004099 TrioOutStreamStringMax, format, TRIO_VA_LIST_ADDR(args), NULL);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004100 TRIO_VA_END(args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004101 *buffer = NIL;
4102 return status;
4103}
4104
Bjorn Reese026d29f2002-01-19 15:40:18 +00004105TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004106trio_vsnprintfcat
4107TRIO_ARGS4((buffer, max, format, args),
4108 char *buffer,
4109 size_t max,
4110 TRIO_CONST char *format,
4111 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004112{
4113 int status;
4114 size_t buf_len;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004115
Bjorn Reese70a9da52001-04-21 16:57:29 +00004116 assert(VALID(buffer));
4117 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00004118
Bjorn Reese026d29f2002-01-19 15:40:18 +00004119 buf_len = trio_length(buffer);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004120 buffer = &buffer[buf_len];
Bjorn Reese026d29f2002-01-19 15:40:18 +00004121 status = TrioFormat(&buffer, max - 1 - buf_len,
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08004122 TrioOutStreamStringMax, format, TRIO_VA_LIST_ADDR(args), NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004123 *buffer = NIL;
4124 return status;
4125}
4126
4127/*************************************************************************
4128 * trio_aprintf
4129 */
4130
4131/* Deprecated */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004132TRIO_PUBLIC char *
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004133trio_aprintf
4134TRIO_VARGS2((format, va_alist),
4135 TRIO_CONST char *format,
4136 TRIO_VA_DECL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004137{
4138 va_list args;
Bjorn Reese026d29f2002-01-19 15:40:18 +00004139 trio_string_t *info;
4140 char *result = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004141
4142 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004143
Bjorn Reese026d29f2002-01-19 15:40:18 +00004144 info = trio_xstring_duplicate("");
4145 if (info)
4146 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004147 TRIO_VA_START(args, format);
Bjorn Reese026d29f2002-01-19 15:40:18 +00004148 (void)TrioFormat(info, 0, TrioOutStreamStringDynamic,
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08004149 format, TRIO_VA_LIST_ADDR(args), NULL);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004150 TRIO_VA_END(args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004151
Bjorn Reese026d29f2002-01-19 15:40:18 +00004152 trio_string_terminate(info);
4153 result = trio_string_extract(info);
4154 trio_string_destroy(info);
4155 }
4156 return result;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004157}
4158
4159/* Deprecated */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004160TRIO_PUBLIC char *
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004161trio_vaprintf
4162TRIO_ARGS2((format, args),
4163 TRIO_CONST char *format,
4164 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004165{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004166 trio_string_t *info;
4167 char *result = NULL;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004168
Bjorn Reese70a9da52001-04-21 16:57:29 +00004169 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004170
Bjorn Reese026d29f2002-01-19 15:40:18 +00004171 info = trio_xstring_duplicate("");
4172 if (info)
4173 {
4174 (void)TrioFormat(info, 0, TrioOutStreamStringDynamic,
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08004175 format, TRIO_VA_LIST_ADDR(args), NULL);
Bjorn Reese026d29f2002-01-19 15:40:18 +00004176 trio_string_terminate(info);
4177 result = trio_string_extract(info);
4178 trio_string_destroy(info);
4179 }
4180 return result;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004181}
4182
Bjorn Reese026d29f2002-01-19 15:40:18 +00004183TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004184trio_asprintf
4185TRIO_VARGS3((result, format, va_alist),
4186 char **result,
4187 TRIO_CONST char *format,
4188 TRIO_VA_DECL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004189{
4190 va_list args;
4191 int status;
Bjorn Reese026d29f2002-01-19 15:40:18 +00004192 trio_string_t *info;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004193
4194 assert(VALID(format));
4195
Bjorn Reese026d29f2002-01-19 15:40:18 +00004196 *result = NULL;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004197
Bjorn Reese026d29f2002-01-19 15:40:18 +00004198 info = trio_xstring_duplicate("");
4199 if (info == NULL)
4200 {
4201 status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
4202 }
4203 else
4204 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004205 TRIO_VA_START(args, format);
Bjorn Reese026d29f2002-01-19 15:40:18 +00004206 status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08004207 format, TRIO_VA_LIST_ADDR(args), NULL);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004208 TRIO_VA_END(args);
Bjorn Reese026d29f2002-01-19 15:40:18 +00004209 if (status >= 0)
4210 {
4211 trio_string_terminate(info);
4212 *result = trio_string_extract(info);
4213 }
4214 trio_string_destroy(info);
4215 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004216 return status;
4217}
4218
Bjorn Reese026d29f2002-01-19 15:40:18 +00004219TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004220trio_vasprintf
4221TRIO_ARGS3((result, format, args),
4222 char **result,
4223 TRIO_CONST char *format,
4224 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004225{
4226 int status;
Bjorn Reese026d29f2002-01-19 15:40:18 +00004227 trio_string_t *info;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004228
Bjorn Reese70a9da52001-04-21 16:57:29 +00004229 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00004230
Bjorn Reese026d29f2002-01-19 15:40:18 +00004231 *result = NULL;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004232
Bjorn Reese026d29f2002-01-19 15:40:18 +00004233 info = trio_xstring_duplicate("");
4234 if (info == NULL)
4235 {
4236 status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
4237 }
4238 else
4239 {
4240 status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08004241 format, TRIO_VA_LIST_ADDR(args), NULL);
Bjorn Reese026d29f2002-01-19 15:40:18 +00004242 if (status >= 0)
4243 {
4244 trio_string_terminate(info);
4245 *result = trio_string_extract(info);
4246 }
4247 trio_string_destroy(info);
4248 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004249 return status;
4250}
4251
Bjorn Reese026d29f2002-01-19 15:40:18 +00004252/** @} End of Printf documentation module */
Daniel Veillard92ad2102001-03-27 12:47:33 +00004253
4254/*************************************************************************
4255 *
Bjorn Reese026d29f2002-01-19 15:40:18 +00004256 * CALLBACK
Daniel Veillard92ad2102001-03-27 12:47:33 +00004257 *
4258 ************************************************************************/
4259
Bjorn Reese026d29f2002-01-19 15:40:18 +00004260#if defined(TRIO_DOCUMENTATION)
4261# include "doc/doc_register.h"
4262#endif
4263/**
4264 @addtogroup UserDefined
4265 @{
4266*/
4267
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004268#if TRIO_EXTENSION
4269
Bjorn Reese70a9da52001-04-21 16:57:29 +00004270/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00004271 * trio_register
Bjorn Reese70a9da52001-04-21 16:57:29 +00004272 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004273
4274/**
4275 Register new user-defined specifier.
4276
4277 @param callback
4278 @param name
4279 @return Handle.
4280 */
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004281TRIO_PUBLIC trio_pointer_t
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004282trio_register
4283TRIO_ARGS2((callback, name),
4284 trio_callback_t callback,
4285 TRIO_CONST char *name)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004286{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004287 trio_userdef_t *def;
4288 trio_userdef_t *prev = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004289
4290 if (callback == NULL)
4291 return NULL;
4292
4293 if (name)
4294 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004295 /* Handle built-in namespaces */
4296 if (name[0] == ':')
4297 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00004298 if (trio_equal(name, ":enter"))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004299 {
4300 internalEnterCriticalRegion = callback;
4301 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00004302 else if (trio_equal(name, ":leave"))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004303 {
4304 internalLeaveCriticalRegion = callback;
4305 }
4306 return NULL;
4307 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004308
Bjorn Reese70a9da52001-04-21 16:57:29 +00004309 /* Bail out if namespace is too long */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004310 if (trio_length(name) >= MAX_USER_NAME)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004311 return NULL;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004312
Bjorn Reese70a9da52001-04-21 16:57:29 +00004313 /* Bail out if namespace already is registered */
4314 def = TrioFindNamespace(name, &prev);
4315 if (def)
4316 return NULL;
4317 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004318
Bjorn Reese026d29f2002-01-19 15:40:18 +00004319 def = (trio_userdef_t *)TRIO_MALLOC(sizeof(trio_userdef_t));
Bjorn Reese70a9da52001-04-21 16:57:29 +00004320 if (def)
4321 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004322 if (internalEnterCriticalRegion)
4323 (void)internalEnterCriticalRegion(NULL);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004324
Bjorn Reese70a9da52001-04-21 16:57:29 +00004325 if (name)
4326 {
4327 /* Link into internal list */
4328 if (prev == NULL)
4329 internalUserDef = def;
4330 else
4331 prev->next = def;
4332 }
4333 /* Initialize */
4334 def->callback = callback;
4335 def->name = (name == NULL)
4336 ? NULL
Bjorn Reese026d29f2002-01-19 15:40:18 +00004337 : trio_duplicate(name);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004338 def->next = NULL;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004339
4340 if (internalLeaveCriticalRegion)
4341 (void)internalLeaveCriticalRegion(NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004342 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004343 return (trio_pointer_t)def;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004344}
4345
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004346/**
4347 Unregister an existing user-defined specifier.
4348
4349 @param handle
Bjorn Reese70a9da52001-04-21 16:57:29 +00004350 */
4351void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004352trio_unregister
4353TRIO_ARGS1((handle),
4354 trio_pointer_t handle)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004355{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004356 trio_userdef_t *self = (trio_userdef_t *)handle;
4357 trio_userdef_t *def;
4358 trio_userdef_t *prev = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004359
4360 assert(VALID(self));
4361
4362 if (self->name)
4363 {
4364 def = TrioFindNamespace(self->name, &prev);
4365 if (def)
4366 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004367 if (internalEnterCriticalRegion)
4368 (void)internalEnterCriticalRegion(NULL);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004369
Bjorn Reese70a9da52001-04-21 16:57:29 +00004370 if (prev == NULL)
4371 internalUserDef = NULL;
4372 else
4373 prev->next = def->next;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004374
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004375 if (internalLeaveCriticalRegion)
4376 (void)internalLeaveCriticalRegion(NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004377 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00004378 trio_destroy(self->name);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004379 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004380 TRIO_FREE(self);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004381}
4382
4383/*************************************************************************
4384 * trio_get_format [public]
4385 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004386TRIO_CONST char *
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004387trio_get_format
4388TRIO_ARGS1((ref),
4389 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004390{
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004391#if defined(FORMAT_USER_DEFINED)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004392 assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004393#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004394
Bjorn Reese026d29f2002-01-19 15:40:18 +00004395 return (((trio_reference_t *)ref)->parameter->user_data);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004396}
4397
4398/*************************************************************************
4399 * trio_get_argument [public]
4400 */
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004401trio_pointer_t
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004402trio_get_argument
4403TRIO_ARGS1((ref),
4404 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004405{
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004406#if defined(FORMAT_USER_DEFINED)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004407 assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004408#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004409
Bjorn Reese026d29f2002-01-19 15:40:18 +00004410 return ((trio_reference_t *)ref)->parameter->data.pointer;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004411}
4412
4413/*************************************************************************
4414 * trio_get_width / trio_set_width [public]
4415 */
4416int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004417trio_get_width
4418TRIO_ARGS1((ref),
4419 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004420{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004421 return ((trio_reference_t *)ref)->parameter->width;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004422}
4423
4424void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004425trio_set_width
4426TRIO_ARGS2((ref, width),
4427 trio_pointer_t ref,
4428 int width)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004429{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004430 ((trio_reference_t *)ref)->parameter->width = width;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004431}
4432
4433/*************************************************************************
4434 * trio_get_precision / trio_set_precision [public]
4435 */
4436int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004437trio_get_precision
4438TRIO_ARGS1((ref),
4439 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004440{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004441 return (((trio_reference_t *)ref)->parameter->precision);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004442}
4443
4444void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004445trio_set_precision
4446TRIO_ARGS2((ref, precision),
4447 trio_pointer_t ref,
4448 int precision)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004449{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004450 ((trio_reference_t *)ref)->parameter->precision = precision;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004451}
4452
4453/*************************************************************************
4454 * trio_get_base / trio_set_base [public]
4455 */
4456int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004457trio_get_base
4458TRIO_ARGS1((ref),
4459 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004460{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004461 return (((trio_reference_t *)ref)->parameter->base);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004462}
4463
4464void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004465trio_set_base
4466TRIO_ARGS2((ref, base),
4467 trio_pointer_t ref,
4468 int base)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004469{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004470 ((trio_reference_t *)ref)->parameter->base = base;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004471}
4472
4473/*************************************************************************
4474 * trio_get_long / trio_set_long [public]
4475 */
4476int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004477trio_get_long
4478TRIO_ARGS1((ref),
4479 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004480{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004481 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONG)
4482 ? TRUE
4483 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004484}
4485
4486void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004487trio_set_long
4488TRIO_ARGS2((ref, is_long),
4489 trio_pointer_t ref,
4490 int is_long)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004491{
4492 if (is_long)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004493 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONG;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004494 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004495 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONG;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004496}
4497
4498/*************************************************************************
4499 * trio_get_longlong / trio_set_longlong [public]
4500 */
4501int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004502trio_get_longlong
4503TRIO_ARGS1((ref),
4504 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004505{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004506 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUAD)
4507 ? TRUE
4508 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004509}
4510
4511void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004512trio_set_longlong
4513TRIO_ARGS2((ref, is_longlong),
4514 trio_pointer_t ref,
4515 int is_longlong)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004516{
4517 if (is_longlong)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004518 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUAD;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004519 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004520 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUAD;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004521}
4522
4523/*************************************************************************
4524 * trio_get_longdouble / trio_set_longdouble [public]
4525 */
4526int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004527trio_get_longdouble
4528TRIO_ARGS1((ref),
4529 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004530{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004531 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONGDOUBLE)
4532 ? TRUE
4533 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004534}
4535
4536void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004537trio_set_longdouble
4538TRIO_ARGS2((ref, is_longdouble),
4539 trio_pointer_t ref,
4540 int is_longdouble)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004541{
4542 if (is_longdouble)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004543 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONGDOUBLE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004544 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004545 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONGDOUBLE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004546}
4547
4548/*************************************************************************
4549 * trio_get_short / trio_set_short [public]
4550 */
4551int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004552trio_get_short
4553TRIO_ARGS1((ref),
4554 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004555{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004556 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORT)
4557 ? TRUE
4558 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004559}
4560
4561void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004562trio_set_short
4563TRIO_ARGS2((ref, is_short),
4564 trio_pointer_t ref,
4565 int is_short)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004566{
4567 if (is_short)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004568 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORT;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004569 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004570 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORT;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004571}
4572
4573/*************************************************************************
4574 * trio_get_shortshort / trio_set_shortshort [public]
4575 */
4576int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004577trio_get_shortshort
4578TRIO_ARGS1((ref),
4579 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004580{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004581 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORTSHORT)
4582 ? TRUE
4583 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004584}
4585
4586void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004587trio_set_shortshort
4588TRIO_ARGS2((ref, is_shortshort),
4589 trio_pointer_t ref,
4590 int is_shortshort)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004591{
4592 if (is_shortshort)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004593 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORTSHORT;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004594 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004595 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORTSHORT;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004596}
4597
4598/*************************************************************************
4599 * trio_get_alternative / trio_set_alternative [public]
4600 */
4601int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004602trio_get_alternative
4603TRIO_ARGS1((ref),
4604 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004605{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004606 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_ALTERNATIVE)
4607 ? TRUE
4608 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004609}
4610
4611void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004612trio_set_alternative
4613TRIO_ARGS2((ref, is_alternative),
4614 trio_pointer_t ref,
4615 int is_alternative)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004616{
4617 if (is_alternative)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004618 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_ALTERNATIVE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004619 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004620 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_ALTERNATIVE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004621}
4622
4623/*************************************************************************
4624 * trio_get_alignment / trio_set_alignment [public]
4625 */
4626int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004627trio_get_alignment
4628TRIO_ARGS1((ref),
4629 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004630{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004631 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LEFTADJUST)
4632 ? TRUE
4633 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004634}
4635
4636void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004637trio_set_alignment
4638TRIO_ARGS2((ref, is_leftaligned),
4639 trio_pointer_t ref,
4640 int is_leftaligned)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004641{
4642 if (is_leftaligned)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004643 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LEFTADJUST;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004644 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004645 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LEFTADJUST;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004646}
4647
4648/*************************************************************************
4649 * trio_get_spacing /trio_set_spacing [public]
4650 */
4651int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004652trio_get_spacing
4653TRIO_ARGS1((ref),
4654 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004655{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004656 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SPACE)
4657 ? TRUE
4658 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004659}
4660
4661void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004662trio_set_spacing
4663TRIO_ARGS2((ref, is_space),
4664 trio_pointer_t ref,
4665 int is_space)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004666{
4667 if (is_space)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004668 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SPACE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004669 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004670 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SPACE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004671}
4672
4673/*************************************************************************
4674 * trio_get_sign / trio_set_sign [public]
4675 */
4676int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004677trio_get_sign
4678TRIO_ARGS1((ref),
4679 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004680{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004681 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHOWSIGN)
4682 ? TRUE
4683 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004684}
4685
4686void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004687trio_set_sign
4688TRIO_ARGS2((ref, is_sign),
4689 trio_pointer_t ref,
4690 int is_sign)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004691{
4692 if (is_sign)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004693 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHOWSIGN;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004694 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004695 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHOWSIGN;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004696}
4697
4698/*************************************************************************
4699 * trio_get_padding / trio_set_padding [public]
4700 */
4701int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004702trio_get_padding
4703TRIO_ARGS1((ref),
4704 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004705{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004706 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_NILPADDING)
4707 ? TRUE
4708 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004709}
4710
4711void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004712trio_set_padding
4713TRIO_ARGS2((ref, is_padding),
4714 trio_pointer_t ref,
4715 int is_padding)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004716{
4717 if (is_padding)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004718 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_NILPADDING;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004719 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004720 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_NILPADDING;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004721}
4722
4723/*************************************************************************
4724 * trio_get_quote / trio_set_quote [public]
4725 */
4726int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004727trio_get_quote
4728TRIO_ARGS1((ref),
4729 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004730{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004731 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUOTE)
4732 ? TRUE
4733 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004734}
4735
4736void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004737trio_set_quote
4738TRIO_ARGS2((ref, is_quote),
4739 trio_pointer_t ref,
4740 int is_quote)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004741{
4742 if (is_quote)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004743 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUOTE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004744 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004745 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUOTE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004746}
4747
4748/*************************************************************************
4749 * trio_get_upper / trio_set_upper [public]
4750 */
4751int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004752trio_get_upper
4753TRIO_ARGS1((ref),
4754 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004755{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004756 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_UPPER)
4757 ? TRUE
4758 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004759}
4760
4761void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004762trio_set_upper
4763TRIO_ARGS2((ref, is_upper),
4764 trio_pointer_t ref,
4765 int is_upper)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004766{
4767 if (is_upper)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004768 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_UPPER;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004769 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004770 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_UPPER;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004771}
4772
4773/*************************************************************************
4774 * trio_get_largest / trio_set_largest [public]
4775 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004776#if TRIO_C99
Bjorn Reese70a9da52001-04-21 16:57:29 +00004777int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004778trio_get_largest
4779TRIO_ARGS1((ref),
4780 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004781{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004782 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_INTMAX_T)
4783 ? TRUE
4784 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004785}
4786
4787void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004788trio_set_largest
4789TRIO_ARGS2((ref, is_largest),
4790 trio_pointer_t ref,
4791 int is_largest)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004792{
4793 if (is_largest)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004794 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_INTMAX_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004795 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004796 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_INTMAX_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004797}
4798#endif
4799
4800/*************************************************************************
4801 * trio_get_ptrdiff / trio_set_ptrdiff [public]
4802 */
Bjorn Reese70a9da52001-04-21 16:57:29 +00004803int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004804trio_get_ptrdiff
4805TRIO_ARGS1((ref),
4806 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004807{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004808 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_PTRDIFF_T)
4809 ? TRUE
4810 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004811}
4812
4813void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004814trio_set_ptrdiff
4815TRIO_ARGS2((ref, is_ptrdiff),
4816 trio_pointer_t ref,
4817 int is_ptrdiff)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004818{
4819 if (is_ptrdiff)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004820 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_PTRDIFF_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004821 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004822 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_PTRDIFF_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004823}
Bjorn Reese70a9da52001-04-21 16:57:29 +00004824
4825/*************************************************************************
4826 * trio_get_size / trio_set_size [public]
4827 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004828#if TRIO_C99
Bjorn Reese70a9da52001-04-21 16:57:29 +00004829int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004830trio_get_size
4831TRIO_ARGS1((ref),
4832 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004833{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004834 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SIZE_T)
4835 ? TRUE
4836 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004837}
4838
4839void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004840trio_set_size
4841TRIO_ARGS2((ref, is_size),
4842 trio_pointer_t ref,
4843 int is_size)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004844{
4845 if (is_size)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004846 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SIZE_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004847 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004848 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SIZE_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004849}
4850#endif
4851
4852/*************************************************************************
4853 * trio_print_int [public]
4854 */
4855void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004856trio_print_int
4857TRIO_ARGS2((ref, number),
4858 trio_pointer_t ref,
4859 int number)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004860{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004861 trio_reference_t *self = (trio_reference_t *)ref;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004862
4863 TrioWriteNumber(self->data,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004864 (trio_uintmax_t)number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004865 self->parameter->flags,
4866 self->parameter->width,
4867 self->parameter->precision,
4868 self->parameter->base);
4869}
4870
4871/*************************************************************************
4872 * trio_print_uint [public]
4873 */
4874void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004875trio_print_uint
4876TRIO_ARGS2((ref, number),
4877 trio_pointer_t ref,
4878 unsigned int number)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004879{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004880 trio_reference_t *self = (trio_reference_t *)ref;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004881
4882 TrioWriteNumber(self->data,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004883 (trio_uintmax_t)number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004884 self->parameter->flags | FLAGS_UNSIGNED,
4885 self->parameter->width,
4886 self->parameter->precision,
4887 self->parameter->base);
4888}
4889
4890/*************************************************************************
4891 * trio_print_double [public]
4892 */
4893void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004894trio_print_double
4895TRIO_ARGS2((ref, number),
4896 trio_pointer_t ref,
4897 double number)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004898{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004899 trio_reference_t *self = (trio_reference_t *)ref;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004900
4901 TrioWriteDouble(self->data,
4902 number,
4903 self->parameter->flags,
4904 self->parameter->width,
4905 self->parameter->precision,
4906 self->parameter->base);
4907}
4908
4909/*************************************************************************
4910 * trio_print_string [public]
4911 */
4912void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004913trio_print_string
4914TRIO_ARGS2((ref, string),
4915 trio_pointer_t ref,
4916 char *string)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004917{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004918 trio_reference_t *self = (trio_reference_t *)ref;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004919
4920 TrioWriteString(self->data,
4921 string,
4922 self->parameter->flags,
4923 self->parameter->width,
4924 self->parameter->precision);
4925}
4926
4927/*************************************************************************
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004928 * trio_print_ref [public]
4929 */
4930int
4931trio_print_ref
4932TRIO_VARGS3((ref, format, va_alist),
4933 trio_pointer_t ref,
4934 TRIO_CONST char *format,
4935 TRIO_VA_DECL)
4936{
4937 int status;
4938 va_list arglist;
4939
4940 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004941
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004942 TRIO_VA_START(arglist, format);
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08004943 status = TrioFormatRef((trio_reference_t *)ref, format, TRIO_VA_LIST_ADDR(arglist), NULL);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004944 TRIO_VA_END(arglist);
4945 return status;
4946}
4947
4948/*************************************************************************
4949 * trio_vprint_ref [public]
4950 */
4951int
4952trio_vprint_ref
4953TRIO_ARGS3((ref, format, arglist),
4954 trio_pointer_t ref,
4955 TRIO_CONST char *format,
4956 va_list arglist)
4957{
4958 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004959
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08004960 return TrioFormatRef((trio_reference_t *)ref, format, TRIO_VA_LIST_ADDR(arglist), NULL);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004961}
4962
4963/*************************************************************************
4964 * trio_printv_ref [public]
4965 */
4966int
4967trio_printv_ref
4968TRIO_ARGS3((ref, format, argarray),
4969 trio_pointer_t ref,
4970 TRIO_CONST char *format,
4971 trio_pointer_t *argarray)
4972{
4973 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004974
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004975 return TrioFormatRef((trio_reference_t *)ref, format, NULL, argarray);
4976}
4977
4978#endif /* TRIO_EXTENSION */
4979
4980/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00004981 * trio_print_pointer [public]
4982 */
4983void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004984trio_print_pointer
4985TRIO_ARGS2((ref, pointer),
4986 trio_pointer_t ref,
4987 trio_pointer_t pointer)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004988{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004989 trio_reference_t *self = (trio_reference_t *)ref;
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004990 trio_flags_t flags;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004991 trio_uintmax_t number;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004992
4993 if (NULL == pointer)
4994 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00004995 TRIO_CONST char *string = internalNullString;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004996 while (*string)
4997 self->data->OutStream(self->data, *string++);
4998 }
4999 else
5000 {
5001 /*
5002 * The subtraction of the null pointer is a workaround
5003 * to avoid a compiler warning. The performance overhead
5004 * is negligible (and likely to be removed by an
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005005 * optimizing compiler). The (char *) casting is done
Bjorn Reese70a9da52001-04-21 16:57:29 +00005006 * to please ANSI C++.
5007 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005008 number = (trio_uintmax_t)((char *)pointer - (char *)0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005009 /* Shrink to size of pointer */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005010 number &= (trio_uintmax_t)-1;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005011 flags = self->parameter->flags;
5012 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE |
5013 FLAGS_NILPADDING);
5014 TrioWriteNumber(self->data,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005015 number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00005016 flags,
5017 POINTER_WIDTH,
5018 NO_PRECISION,
5019 BASE_HEX);
5020 }
5021}
5022
Bjorn Reese026d29f2002-01-19 15:40:18 +00005023/** @} End of UserDefined documentation module */
Bjorn Reese70a9da52001-04-21 16:57:29 +00005024
5025/*************************************************************************
5026 *
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005027 * LOCALES
5028 *
5029 ************************************************************************/
5030
5031/*************************************************************************
5032 * trio_locale_set_decimal_point
5033 *
5034 * Decimal point can only be one character. The input argument is a
5035 * string to enable multibyte characters. At most MB_LEN_MAX characters
5036 * will be used.
5037 */
5038TRIO_PUBLIC void
5039trio_locale_set_decimal_point
5040TRIO_ARGS1((decimalPoint),
5041 char *decimalPoint)
5042{
5043#if defined(USE_LOCALE)
5044 if (NULL == internalLocaleValues)
5045 {
5046 TrioSetLocale();
5047 }
5048#endif
5049 internalDecimalPointLength = trio_length(decimalPoint);
5050 if (internalDecimalPointLength == 1)
5051 {
5052 internalDecimalPoint = *decimalPoint;
5053 }
5054 else
5055 {
5056 internalDecimalPoint = NIL;
5057 trio_copy_max(internalDecimalPointString,
5058 sizeof(internalDecimalPointString),
5059 decimalPoint);
5060 }
5061}
5062
5063/*************************************************************************
5064 * trio_locale_set_thousand_separator
5065 *
5066 * See trio_locale_set_decimal_point
5067 */
5068TRIO_PUBLIC void
5069trio_locale_set_thousand_separator
5070TRIO_ARGS1((thousandSeparator),
5071 char *thousandSeparator)
5072{
5073#if defined(USE_LOCALE)
5074 if (NULL == internalLocaleValues)
5075 {
5076 TrioSetLocale();
5077 }
5078#endif
5079 trio_copy_max(internalThousandSeparator,
5080 sizeof(internalThousandSeparator),
5081 thousandSeparator);
5082 internalThousandSeparatorLength = trio_length(internalThousandSeparator);
5083}
5084
5085/*************************************************************************
5086 * trio_locale_set_grouping
5087 *
5088 * Array of bytes. Reversed order.
5089 *
5090 * CHAR_MAX : No further grouping
5091 * 0 : Repeat last group for the remaining digits (not necessary
5092 * as C strings are zero-terminated)
5093 * n : Set current group to n
5094 *
5095 * Same order as the grouping attribute in LC_NUMERIC.
5096 */
5097TRIO_PUBLIC void
5098trio_locale_set_grouping
5099TRIO_ARGS1((grouping),
5100 char *grouping)
5101{
5102#if defined(USE_LOCALE)
5103 if (NULL == internalLocaleValues)
5104 {
5105 TrioSetLocale();
5106 }
5107#endif
5108 trio_copy_max(internalGrouping,
5109 sizeof(internalGrouping),
5110 grouping);
5111}
5112
5113
5114/*************************************************************************
5115 *
Bjorn Reese026d29f2002-01-19 15:40:18 +00005116 * SCANNING
Bjorn Reese70a9da52001-04-21 16:57:29 +00005117 *
5118 ************************************************************************/
5119
Daniel Veillard92ad2102001-03-27 12:47:33 +00005120/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005121 * TrioSkipWhitespaces
Daniel Veillard92ad2102001-03-27 12:47:33 +00005122 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005123TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005124TrioSkipWhitespaces
5125TRIO_ARGS1((self),
5126 trio_class_t *self)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005127{
5128 int ch;
5129
5130 ch = self->current;
5131 while (isspace(ch))
5132 {
5133 self->InStream(self, &ch);
5134 }
5135 return ch;
5136}
5137
5138/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005139 * TrioGetCollation
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005140 */
5141#if TRIO_EXTENSION
Bjorn Reese026d29f2002-01-19 15:40:18 +00005142TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005143TrioGetCollation(TRIO_NOARGS)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005144{
5145 int i;
5146 int j;
5147 int k;
5148 char first[2];
5149 char second[2];
5150
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005151 /* This is computationally expensive */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005152 first[1] = NIL;
5153 second[1] = NIL;
5154 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5155 {
5156 k = 0;
5157 first[0] = (char)i;
5158 for (j = 0; j < MAX_CHARACTER_CLASS; j++)
5159 {
5160 second[0] = (char)j;
Bjorn Reese026d29f2002-01-19 15:40:18 +00005161 if (trio_equal_locale(first, second))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005162 internalCollationArray[i][k++] = (char)j;
5163 }
5164 internalCollationArray[i][k] = NIL;
5165 }
5166}
5167#endif
5168
5169/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005170 * TrioGetCharacterClass
Daniel Veillard92ad2102001-03-27 12:47:33 +00005171 *
5172 * FIXME:
5173 * multibyte
5174 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005175TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005176TrioGetCharacterClass
5177TRIO_ARGS4((format, indexPointer, flagsPointer, characterclass),
5178 TRIO_CONST char *format,
5179 int *indexPointer,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005180 trio_flags_t *flagsPointer,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005181 int *characterclass)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005182{
5183 int index = *indexPointer;
5184 int i;
5185 char ch;
5186 char range_begin;
5187 char range_end;
5188
5189 *flagsPointer &= ~FLAGS_EXCLUDE;
5190
5191 if (format[index] == QUALIFIER_CIRCUMFLEX)
5192 {
5193 *flagsPointer |= FLAGS_EXCLUDE;
5194 index++;
5195 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005196 /*
5197 * If the ungroup character is at the beginning of the scanlist,
Daniel Veillard92ad2102001-03-27 12:47:33 +00005198 * it will be part of the class, and a second ungroup character
5199 * must follow to end the group.
5200 */
5201 if (format[index] == SPECIFIER_UNGROUP)
5202 {
5203 characterclass[(int)SPECIFIER_UNGROUP]++;
5204 index++;
5205 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005206 /*
5207 * Minus is used to specify ranges. To include minus in the class,
Daniel Veillard92ad2102001-03-27 12:47:33 +00005208 * it must be at the beginning of the list
5209 */
5210 if (format[index] == QUALIFIER_MINUS)
5211 {
5212 characterclass[(int)QUALIFIER_MINUS]++;
5213 index++;
5214 }
5215 /* Collect characters */
5216 for (ch = format[index];
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005217 (ch != SPECIFIER_UNGROUP) && (ch != NIL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00005218 ch = format[++index])
5219 {
5220 switch (ch)
5221 {
5222 case QUALIFIER_MINUS: /* Scanlist ranges */
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005223
Bjorn Reese70a9da52001-04-21 16:57:29 +00005224 /*
5225 * Both C99 and UNIX98 describes ranges as implementation-
Daniel Veillard92ad2102001-03-27 12:47:33 +00005226 * defined.
5227 *
5228 * We support the following behaviour (although this may
5229 * change as we become wiser)
5230 * - only increasing ranges, ie. [a-b] but not [b-a]
5231 * - transitive ranges, ie. [a-b-c] == [a-c]
5232 * - trailing minus, ie. [a-] is interpreted as an 'a'
5233 * and a '-'
5234 * - duplicates (although we can easily convert these
5235 * into errors)
5236 */
5237 range_begin = format[index - 1];
5238 range_end = format[++index];
5239 if (range_end == SPECIFIER_UNGROUP)
5240 {
5241 /* Trailing minus is included */
5242 characterclass[(int)ch]++;
5243 ch = range_end;
5244 break; /* for */
5245 }
5246 if (range_end == NIL)
5247 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5248 if (range_begin > range_end)
5249 return TRIO_ERROR_RETURN(TRIO_ERANGE, index);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005250
Daniel Veillard92ad2102001-03-27 12:47:33 +00005251 for (i = (int)range_begin; i <= (int)range_end; i++)
5252 characterclass[i]++;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005253
Daniel Veillard92ad2102001-03-27 12:47:33 +00005254 ch = range_end;
5255 break;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005256
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005257#if TRIO_EXTENSION
5258
5259 case SPECIFIER_GROUP:
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005260
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005261 switch (format[index + 1])
Daniel Veillard92ad2102001-03-27 12:47:33 +00005262 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005263 case QUALIFIER_DOT: /* Collating symbol */
5264 /*
5265 * FIXME: This will be easier to implement when multibyte
5266 * characters have been implemented. Until now, we ignore
5267 * this feature.
5268 */
5269 for (i = index + 2; ; i++)
5270 {
5271 if (format[i] == NIL)
5272 /* Error in syntax */
5273 return -1;
5274 else if (format[i] == QUALIFIER_DOT)
5275 break; /* for */
5276 }
5277 if (format[++i] != SPECIFIER_UNGROUP)
5278 return -1;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005279
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005280 index = i;
5281 break;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005282
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005283 case QUALIFIER_EQUAL: /* Equivalence class expressions */
5284 {
5285 unsigned int j;
5286 unsigned int k;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005287
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005288 if (internalCollationUnconverted)
5289 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005290 /* Lazy evaluation of collation array */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005291 TrioGetCollation();
5292 internalCollationUnconverted = FALSE;
5293 }
5294 for (i = index + 2; ; i++)
5295 {
5296 if (format[i] == NIL)
5297 /* Error in syntax */
5298 return -1;
5299 else if (format[i] == QUALIFIER_EQUAL)
5300 break; /* for */
5301 else
5302 {
5303 /* Mark any equivalent character */
5304 k = (unsigned int)format[i];
5305 for (j = 0; internalCollationArray[k][j] != NIL; j++)
5306 characterclass[(int)internalCollationArray[k][j]]++;
5307 }
5308 }
5309 if (format[++i] != SPECIFIER_UNGROUP)
5310 return -1;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005311
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005312 index = i;
5313 }
5314 break;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005315
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005316 case QUALIFIER_COLON: /* Character class expressions */
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005317
Bjorn Reese026d29f2002-01-19 15:40:18 +00005318 if (trio_equal_max(CLASS_ALNUM, sizeof(CLASS_ALNUM) - 1,
5319 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005320 {
5321 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5322 if (isalnum(i))
5323 characterclass[i]++;
5324 index += sizeof(CLASS_ALNUM) - 1;
5325 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005326 else if (trio_equal_max(CLASS_ALPHA, sizeof(CLASS_ALPHA) - 1,
5327 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005328 {
5329 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5330 if (isalpha(i))
5331 characterclass[i]++;
5332 index += sizeof(CLASS_ALPHA) - 1;
5333 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005334 else if (trio_equal_max(CLASS_CNTRL, sizeof(CLASS_CNTRL) - 1,
5335 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005336 {
5337 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5338 if (iscntrl(i))
5339 characterclass[i]++;
5340 index += sizeof(CLASS_CNTRL) - 1;
5341 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005342 else if (trio_equal_max(CLASS_DIGIT, sizeof(CLASS_DIGIT) - 1,
5343 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005344 {
5345 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5346 if (isdigit(i))
5347 characterclass[i]++;
5348 index += sizeof(CLASS_DIGIT) - 1;
5349 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005350 else if (trio_equal_max(CLASS_GRAPH, sizeof(CLASS_GRAPH) - 1,
5351 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005352 {
5353 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5354 if (isgraph(i))
5355 characterclass[i]++;
5356 index += sizeof(CLASS_GRAPH) - 1;
5357 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005358 else if (trio_equal_max(CLASS_LOWER, sizeof(CLASS_LOWER) - 1,
5359 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005360 {
5361 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5362 if (islower(i))
5363 characterclass[i]++;
5364 index += sizeof(CLASS_LOWER) - 1;
5365 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005366 else if (trio_equal_max(CLASS_PRINT, sizeof(CLASS_PRINT) - 1,
5367 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005368 {
5369 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5370 if (isprint(i))
5371 characterclass[i]++;
5372 index += sizeof(CLASS_PRINT) - 1;
5373 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005374 else if (trio_equal_max(CLASS_PUNCT, sizeof(CLASS_PUNCT) - 1,
5375 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005376 {
5377 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5378 if (ispunct(i))
5379 characterclass[i]++;
5380 index += sizeof(CLASS_PUNCT) - 1;
5381 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005382 else if (trio_equal_max(CLASS_SPACE, sizeof(CLASS_SPACE) - 1,
5383 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005384 {
5385 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5386 if (isspace(i))
5387 characterclass[i]++;
5388 index += sizeof(CLASS_SPACE) - 1;
5389 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005390 else if (trio_equal_max(CLASS_UPPER, sizeof(CLASS_UPPER) - 1,
5391 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005392 {
5393 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5394 if (isupper(i))
5395 characterclass[i]++;
5396 index += sizeof(CLASS_UPPER) - 1;
5397 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005398 else if (trio_equal_max(CLASS_XDIGIT, sizeof(CLASS_XDIGIT) - 1,
5399 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005400 {
5401 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5402 if (isxdigit(i))
5403 characterclass[i]++;
5404 index += sizeof(CLASS_XDIGIT) - 1;
5405 }
5406 else
5407 {
5408 characterclass[(int)ch]++;
5409 }
5410 break;
5411
5412 default:
Daniel Veillard92ad2102001-03-27 12:47:33 +00005413 characterclass[(int)ch]++;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005414 break;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005415 }
5416 break;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005417
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005418#endif /* TRIO_EXTENSION */
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005419
Daniel Veillard92ad2102001-03-27 12:47:33 +00005420 default:
5421 characterclass[(int)ch]++;
5422 break;
5423 }
5424 }
5425 return 0;
5426}
5427
5428/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005429 * TrioReadNumber
Daniel Veillard92ad2102001-03-27 12:47:33 +00005430 *
5431 * We implement our own number conversion in preference of strtol and
5432 * strtoul, because we must handle 'long long' and thousand separators.
5433 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005434TRIO_PRIVATE BOOLEAN_T
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005435TrioReadNumber
5436TRIO_ARGS5((self, target, flags, width, base),
5437 trio_class_t *self,
5438 trio_uintmax_t *target,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005439 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005440 int width,
5441 int base)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005442{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005443 trio_uintmax_t number = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005444 int digit;
5445 int count;
5446 BOOLEAN_T isNegative = FALSE;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005447 BOOLEAN_T gotNumber = FALSE;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005448 int j;
5449
5450 assert(VALID(self));
5451 assert(VALID(self->InStream));
5452 assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
5453
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005454 if (internalDigitsUnconverted)
5455 {
5456 /* Lazy evaluation of digits array */
5457 memset(internalDigitArray, -1, sizeof(internalDigitArray));
5458 for (j = 0; j < (int)sizeof(internalDigitsLower) - 1; j++)
5459 {
5460 internalDigitArray[(int)internalDigitsLower[j]] = j;
5461 internalDigitArray[(int)internalDigitsUpper[j]] = j;
5462 }
5463 internalDigitsUnconverted = FALSE;
5464 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005465
Daniel Veillard92ad2102001-03-27 12:47:33 +00005466 TrioSkipWhitespaces(self);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005467
Daniel Veillard92ad2102001-03-27 12:47:33 +00005468 if (!(flags & FLAGS_UNSIGNED))
5469 {
5470 /* Leading sign */
5471 if (self->current == '+')
5472 {
5473 self->InStream(self, NULL);
5474 }
5475 else if (self->current == '-')
5476 {
5477 self->InStream(self, NULL);
5478 isNegative = TRUE;
5479 }
5480 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005481
Daniel Veillard92ad2102001-03-27 12:47:33 +00005482 count = self->processed;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005483
Daniel Veillard92ad2102001-03-27 12:47:33 +00005484 if (flags & FLAGS_ALTERNATIVE)
5485 {
5486 switch (base)
5487 {
5488 case NO_BASE:
5489 case BASE_OCTAL:
5490 case BASE_HEX:
5491 case BASE_BINARY:
5492 if (self->current == '0')
5493 {
5494 self->InStream(self, NULL);
5495 if (self->current)
5496 {
5497 if ((base == BASE_HEX) &&
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005498 (trio_to_upper(self->current) == 'X'))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005499 {
5500 self->InStream(self, NULL);
5501 }
5502 else if ((base == BASE_BINARY) &&
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005503 (trio_to_upper(self->current) == 'B'))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005504 {
5505 self->InStream(self, NULL);
5506 }
5507 }
5508 }
5509 else
5510 return FALSE;
5511 break;
5512 default:
5513 break;
5514 }
5515 }
5516
5517 while (((width == NO_WIDTH) || (self->processed - count < width)) &&
5518 (! ((self->current == EOF) || isspace(self->current))))
5519 {
5520 if (isascii(self->current))
5521 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00005522 digit = internalDigitArray[self->current];
Daniel Veillard92ad2102001-03-27 12:47:33 +00005523 /* Abort if digit is not allowed in the specified base */
5524 if ((digit == -1) || (digit >= base))
5525 break;
5526 }
5527 else if (flags & FLAGS_QUOTE)
5528 {
5529 /* Compare with thousands separator */
Bjorn Reese70a9da52001-04-21 16:57:29 +00005530 for (j = 0; internalThousandSeparator[j] && self->current; j++)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005531 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00005532 if (internalThousandSeparator[j] != self->current)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005533 break;
5534
5535 self->InStream(self, NULL);
5536 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005537 if (internalThousandSeparator[j])
Daniel Veillard92ad2102001-03-27 12:47:33 +00005538 break; /* Mismatch */
5539 else
5540 continue; /* Match */
5541 }
5542 else
5543 break;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005544
Daniel Veillard92ad2102001-03-27 12:47:33 +00005545 number *= base;
5546 number += digit;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005547 gotNumber = TRUE; /* we need at least one digit */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005548
5549 self->InStream(self, NULL);
5550 }
5551
5552 /* Was anything read at all? */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005553 if (!gotNumber)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005554 return FALSE;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005555
Daniel Veillard92ad2102001-03-27 12:47:33 +00005556 if (target)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005557 *target = (isNegative) ? -((trio_intmax_t)number) : number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005558 return TRUE;
5559}
5560
5561/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005562 * TrioReadChar
Daniel Veillard92ad2102001-03-27 12:47:33 +00005563 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005564TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005565TrioReadChar
5566TRIO_ARGS4((self, target, flags, width),
5567 trio_class_t *self,
5568 char *target,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005569 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005570 int width)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005571{
5572 int i;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005573 char ch;
5574 trio_uintmax_t number;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005575
Daniel Veillard92ad2102001-03-27 12:47:33 +00005576 assert(VALID(self));
5577 assert(VALID(self->InStream));
5578
5579 for (i = 0;
5580 (self->current != EOF) && (i < width);
5581 i++)
5582 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005583 ch = (char)self->current;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005584 self->InStream(self, NULL);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005585 if ((flags & FLAGS_ALTERNATIVE) && (ch == CHAR_BACKSLASH))
5586 {
5587 switch (self->current)
5588 {
5589 case '\\': ch = '\\'; break;
5590 case 'a': ch = '\007'; break;
5591 case 'b': ch = '\b'; break;
5592 case 'f': ch = '\f'; break;
5593 case 'n': ch = '\n'; break;
5594 case 'r': ch = '\r'; break;
5595 case 't': ch = '\t'; break;
5596 case 'v': ch = '\v'; break;
5597 default:
5598 if (isdigit(self->current))
5599 {
5600 /* Read octal number */
5601 if (!TrioReadNumber(self, &number, 0, 3, BASE_OCTAL))
5602 return 0;
5603 ch = (char)number;
5604 }
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005605 else if (trio_to_upper(self->current) == 'X')
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005606 {
5607 /* Read hexadecimal number */
5608 self->InStream(self, NULL);
5609 if (!TrioReadNumber(self, &number, 0, 2, BASE_HEX))
5610 return 0;
5611 ch = (char)number;
5612 }
5613 else
5614 {
5615 ch = (char)self->current;
5616 }
5617 break;
5618 }
5619 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005620
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005621 if (target)
5622 target[i] = ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005623 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005624 return i + 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005625}
5626
5627/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005628 * TrioReadString
Daniel Veillard92ad2102001-03-27 12:47:33 +00005629 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005630TRIO_PRIVATE BOOLEAN_T
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005631TrioReadString
5632TRIO_ARGS4((self, target, flags, width),
5633 trio_class_t *self,
5634 char *target,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005635 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005636 int width)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005637{
5638 int i;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005639
Daniel Veillard92ad2102001-03-27 12:47:33 +00005640 assert(VALID(self));
5641 assert(VALID(self->InStream));
5642
5643 TrioSkipWhitespaces(self);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005644
Bjorn Reese70a9da52001-04-21 16:57:29 +00005645 /*
5646 * Continue until end of string is reached, a whitespace is encountered,
Daniel Veillard92ad2102001-03-27 12:47:33 +00005647 * or width is exceeded
5648 */
5649 for (i = 0;
5650 ((width == NO_WIDTH) || (i < width)) &&
5651 (! ((self->current == EOF) || isspace(self->current)));
5652 i++)
5653 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005654 if (TrioReadChar(self, (target ? &target[i] : 0), flags, 1) == 0)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005655 break; /* for */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005656 }
5657 if (target)
5658 target[i] = NIL;
5659 return TRUE;
5660}
5661
5662/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005663 * TrioReadWideChar
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005664 */
5665#if TRIO_WIDECHAR
Bjorn Reese026d29f2002-01-19 15:40:18 +00005666TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005667TrioReadWideChar
5668TRIO_ARGS4((self, target, flags, width),
5669 trio_class_t *self,
5670 trio_wchar_t *target,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005671 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005672 int width)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005673{
5674 int i;
5675 int j;
5676 int size;
5677 int amount = 0;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005678 trio_wchar_t wch;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005679 char buffer[MB_LEN_MAX + 1];
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005680
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005681 assert(VALID(self));
5682 assert(VALID(self->InStream));
5683
5684 for (i = 0;
5685 (self->current != EOF) && (i < width);
5686 i++)
5687 {
5688 if (isascii(self->current))
5689 {
5690 if (TrioReadChar(self, buffer, flags, 1) == 0)
5691 return 0;
5692 buffer[1] = NIL;
5693 }
5694 else
5695 {
5696 /*
5697 * Collect a multibyte character, by enlarging buffer until
5698 * it contains a fully legal multibyte character, or the
5699 * buffer is full.
5700 */
5701 j = 0;
5702 do
5703 {
5704 buffer[j++] = (char)self->current;
5705 buffer[j] = NIL;
5706 self->InStream(self, NULL);
5707 }
5708 while ((j < (int)sizeof(buffer)) && (mblen(buffer, (size_t)j) != j));
5709 }
5710 if (target)
5711 {
5712 size = mbtowc(&wch, buffer, sizeof(buffer));
5713 if (size > 0)
5714 target[i] = wch;
5715 }
5716 amount += size;
5717 self->InStream(self, NULL);
5718 }
5719 return amount;
5720}
5721#endif /* TRIO_WIDECHAR */
5722
5723/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005724 * TrioReadWideString
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005725 */
5726#if TRIO_WIDECHAR
Bjorn Reese026d29f2002-01-19 15:40:18 +00005727TRIO_PRIVATE BOOLEAN_T
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005728TrioReadWideString
5729TRIO_ARGS4((self, target, flags, width),
5730 trio_class_t *self,
5731 trio_wchar_t *target,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005732 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005733 int width)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005734{
5735 int i;
5736 int size;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005737
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005738 assert(VALID(self));
5739 assert(VALID(self->InStream));
5740
5741 TrioSkipWhitespaces(self);
5742
5743#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005744 (void)mblen(NULL, 0);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005745#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005746
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005747 /*
5748 * Continue until end of string is reached, a whitespace is encountered,
5749 * or width is exceeded
5750 */
5751 for (i = 0;
5752 ((width == NO_WIDTH) || (i < width)) &&
5753 (! ((self->current == EOF) || isspace(self->current)));
5754 )
5755 {
5756 size = TrioReadWideChar(self, &target[i], flags, 1);
5757 if (size == 0)
5758 break; /* for */
5759
5760 i += size;
5761 }
5762 if (target)
Bjorn Reese026d29f2002-01-19 15:40:18 +00005763 target[i] = WCONST('\0');
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005764 return TRUE;
5765}
5766#endif /* TRIO_WIDECHAR */
5767
5768/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005769 * TrioReadGroup
Daniel Veillard92ad2102001-03-27 12:47:33 +00005770 *
5771 * FIXME: characterclass does not work with multibyte characters
5772 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005773TRIO_PRIVATE BOOLEAN_T
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005774TrioReadGroup
5775TRIO_ARGS5((self, target, characterclass, flags, width),
5776 trio_class_t *self,
5777 char *target,
5778 int *characterclass,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005779 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005780 int width)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005781{
Bjorn Reese70a9da52001-04-21 16:57:29 +00005782 int ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005783 int i;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005784
Daniel Veillard92ad2102001-03-27 12:47:33 +00005785 assert(VALID(self));
5786 assert(VALID(self->InStream));
5787
5788 ch = self->current;
5789 for (i = 0;
5790 ((width == NO_WIDTH) || (i < width)) &&
5791 (! ((ch == EOF) ||
5792 (((flags & FLAGS_EXCLUDE) != 0) ^ (characterclass[ch] == 0))));
5793 i++)
5794 {
5795 if (target)
5796 target[i] = (char)ch;
5797 self->InStream(self, &ch);
5798 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005799
Daniel Veillard92ad2102001-03-27 12:47:33 +00005800 if (target)
5801 target[i] = NIL;
5802 return TRUE;
5803}
5804
5805/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005806 * TrioReadDouble
Daniel Veillard92ad2102001-03-27 12:47:33 +00005807 *
5808 * FIXME:
Daniel Veillard92ad2102001-03-27 12:47:33 +00005809 * add long double
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005810 * handle base
Daniel Veillard92ad2102001-03-27 12:47:33 +00005811 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005812TRIO_PRIVATE BOOLEAN_T
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005813TrioReadDouble
5814TRIO_ARGS4((self, target, flags, width),
5815 trio_class_t *self,
5816 trio_pointer_t target,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005817 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005818 int width)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005819{
5820 int ch;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005821 char doubleString[512];
Daniel Veillard92ad2102001-03-27 12:47:33 +00005822 int index = 0;
5823 int start;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005824 int j;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005825 BOOLEAN_T isHex = FALSE;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005826
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005827 doubleString[0] = 0;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005828
Bjorn Reese70a9da52001-04-21 16:57:29 +00005829 if ((width == NO_WIDTH) || (width > (int)sizeof(doubleString) - 1))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005830 width = sizeof(doubleString) - 1;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005831
Daniel Veillard92ad2102001-03-27 12:47:33 +00005832 TrioSkipWhitespaces(self);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005833
Bjorn Reese70a9da52001-04-21 16:57:29 +00005834 /*
Bjorn Reese026d29f2002-01-19 15:40:18 +00005835 * Read entire double number from stream. trio_to_double requires
5836 * a string as input, but InStream can be anything, so we have to
Daniel Veillard92ad2102001-03-27 12:47:33 +00005837 * collect all characters.
5838 */
5839 ch = self->current;
5840 if ((ch == '+') || (ch == '-'))
5841 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005842 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005843 self->InStream(self, &ch);
5844 width--;
5845 }
5846
5847 start = index;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005848 switch (ch)
5849 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00005850 case 'n':
5851 case 'N':
5852 /* Not-a-number */
5853 if (index != 0)
5854 break;
5855 /* FALLTHROUGH */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005856 case 'i':
5857 case 'I':
5858 /* Infinity */
5859 while (isalpha(ch) && (index - start < width))
5860 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005861 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005862 self->InStream(self, &ch);
5863 }
5864 doubleString[index] = NIL;
5865
Daniel Veillard92ad2102001-03-27 12:47:33 +00005866 /* Case insensitive string comparison */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005867 if (trio_equal(&doubleString[start], INFINITE_UPPER) ||
5868 trio_equal(&doubleString[start], LONG_INFINITE_UPPER))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005869 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005870 if (flags & FLAGS_LONGDOUBLE)
5871 {
5872 if ((start == 1) && (doubleString[0] == '-'))
5873 {
5874 *((trio_long_double_t *)target) = trio_ninf();
5875 }
5876 else
5877 {
5878 *((trio_long_double_t *)target) = trio_pinf();
5879 }
5880 }
5881 else
5882 {
5883 if ((start == 1) && (doubleString[0] == '-'))
5884 {
5885 *((double *)target) = trio_ninf();
5886 }
5887 else
5888 {
5889 *((double *)target) = trio_pinf();
5890 }
5891 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005892 return TRUE;
5893 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005894 if (trio_equal(doubleString, NAN_UPPER))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005895 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00005896 /* NaN must not have a preceeding + nor - */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005897 if (flags & FLAGS_LONGDOUBLE)
5898 {
5899 *((trio_long_double_t *)target) = trio_nan();
5900 }
5901 else
5902 {
5903 *((double *)target) = trio_nan();
5904 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005905 return TRUE;
5906 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005907 return FALSE;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005908
5909 case '0':
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005910 doubleString[index++] = (char)ch;
5911 self->InStream(self, &ch);
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005912 if (trio_to_upper(ch) == 'X')
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005913 {
5914 isHex = TRUE;
5915 doubleString[index++] = (char)ch;
5916 self->InStream(self, &ch);
5917 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005918 break;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005919
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005920 default:
5921 break;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005922 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005923
Bjorn Reese70a9da52001-04-21 16:57:29 +00005924 while ((ch != EOF) && (index - start < width))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005925 {
5926 /* Integer part */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005927 if (isHex ? isxdigit(ch) : isdigit(ch))
Bjorn Reese70a9da52001-04-21 16:57:29 +00005928 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005929 doubleString[index++] = (char)ch;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005930 self->InStream(self, &ch);
5931 }
5932 else if (flags & FLAGS_QUOTE)
5933 {
5934 /* Compare with thousands separator */
5935 for (j = 0; internalThousandSeparator[j] && self->current; j++)
5936 {
5937 if (internalThousandSeparator[j] != self->current)
5938 break;
5939
5940 self->InStream(self, &ch);
5941 }
5942 if (internalThousandSeparator[j])
5943 break; /* Mismatch */
5944 else
5945 continue; /* Match */
5946 }
5947 else
5948 break; /* while */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005949 }
5950 if (ch == '.')
5951 {
5952 /* Decimal part */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005953 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005954 self->InStream(self, &ch);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005955 while ((isHex ? isxdigit(ch) : isdigit(ch)) &&
5956 (index - start < width))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005957 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005958 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005959 self->InStream(self, &ch);
5960 }
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005961 if (isHex ? (trio_to_upper(ch) == 'P') : (trio_to_upper(ch) == 'E'))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005962 {
5963 /* Exponent */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005964 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005965 self->InStream(self, &ch);
5966 if ((ch == '+') || (ch == '-'))
5967 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005968 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005969 self->InStream(self, &ch);
5970 }
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005971 while (isdigit(ch) && (index - start < width))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005972 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005973 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005974 self->InStream(self, &ch);
5975 }
5976 }
5977 }
5978
5979 if ((index == start) || (*doubleString == NIL))
5980 return FALSE;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005981
5982 doubleString[index] = 0;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005983
Daniel Veillard92ad2102001-03-27 12:47:33 +00005984 if (flags & FLAGS_LONGDOUBLE)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005985 {
5986 *((trio_long_double_t *)target) = trio_to_long_double(doubleString, NULL);
5987 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005988 else
5989 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005990 *((double *)target) = trio_to_double(doubleString, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00005991 }
5992 return TRUE;
5993}
5994
5995/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005996 * TrioReadPointer
Daniel Veillard92ad2102001-03-27 12:47:33 +00005997 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005998TRIO_PRIVATE BOOLEAN_T
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005999TrioReadPointer
6000TRIO_ARGS3((self, target, flags),
6001 trio_class_t *self,
6002 trio_pointer_t *target,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00006003 trio_flags_t flags)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006004{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006005 trio_uintmax_t number;
Bjorn Reese026d29f2002-01-19 15:40:18 +00006006 char buffer[sizeof(internalNullString)];
Daniel Veillard92ad2102001-03-27 12:47:33 +00006007
6008 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | FLAGS_NILPADDING);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006009
Daniel Veillard92ad2102001-03-27 12:47:33 +00006010 if (TrioReadNumber(self,
6011 &number,
6012 flags,
6013 POINTER_WIDTH,
6014 BASE_HEX))
6015 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00006016 /*
6017 * The strange assignment of number is a workaround for a compiler
6018 * warning
6019 */
Daniel Veillard92ad2102001-03-27 12:47:33 +00006020 if (target)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006021 *target = (char *)0 + number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006022 return TRUE;
6023 }
6024 else if (TrioReadString(self,
6025 (flags & FLAGS_IGNORE)
6026 ? NULL
6027 : buffer,
6028 0,
Bjorn Reese026d29f2002-01-19 15:40:18 +00006029 sizeof(internalNullString) - 1))
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006030 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00006031 if (trio_equal_case(buffer, internalNullString))
Daniel Veillard92ad2102001-03-27 12:47:33 +00006032 {
6033 if (target)
6034 *target = NULL;
6035 return TRUE;
6036 }
6037 }
6038 return FALSE;
6039}
6040
6041/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00006042 * TrioScanProcess
Daniel Veillard92ad2102001-03-27 12:47:33 +00006043 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006044TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006045TrioScanProcess
6046TRIO_ARGS3((data, format, parameters),
6047 trio_class_t *data,
6048 TRIO_CONST char *format,
6049 trio_parameter_t *parameters)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006050{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006051#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006052 int charlen;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006053 int cnt;
Bjorn Reese026d29f2002-01-19 15:40:18 +00006054#endif
6055 int assignment;
6056 int ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006057 int index; /* Index of format string */
6058 int i; /* Index of current parameter */
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00006059 trio_flags_t flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006060 int width;
6061 int base;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006062 trio_pointer_t pointer;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006063
Daniel Veillard92ad2102001-03-27 12:47:33 +00006064 assignment = 0;
6065 i = 0;
6066 index = 0;
6067 data->InStream(data, &ch);
6068
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006069#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006070 (void)mblen(NULL, 0);
Daniel Veillard92ad2102001-03-27 12:47:33 +00006071#endif
6072
6073 while (format[index])
6074 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006075#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006076 if (! isascii(format[index]))
6077 {
6078 charlen = mblen(&format[index], MB_LEN_MAX);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006079 if (charlen != -1)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006080 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006081 /* Compare multibyte characters in format string */
6082 for (cnt = 0; cnt < charlen - 1; cnt++)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006083 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006084 if (ch != format[index + cnt])
6085 {
6086 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
6087 }
6088 data->InStream(data, &ch);
Daniel Veillard92ad2102001-03-27 12:47:33 +00006089 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006090 continue; /* while characters left in formatting string */
Daniel Veillard92ad2102001-03-27 12:47:33 +00006091 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00006092 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006093#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006094
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006095 if ((EOF == ch) && (parameters[i].type != FORMAT_COUNT))
6096 {
6097 return (assignment > 0) ? assignment : EOF;
6098 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006099
Daniel Veillard92ad2102001-03-27 12:47:33 +00006100 if (CHAR_IDENTIFIER == format[index])
6101 {
6102 if (CHAR_IDENTIFIER == format[index + 1])
6103 {
6104 /* Two % in format matches one % in input stream */
6105 if (CHAR_IDENTIFIER == ch)
6106 {
6107 data->InStream(data, &ch);
6108 index += 2;
6109 continue; /* while format chars left */
6110 }
6111 else
6112 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
6113 }
6114
6115 /* Skip the parameter entries */
6116 while (parameters[i].type == FORMAT_PARAMETER)
6117 i++;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006118
Daniel Veillard92ad2102001-03-27 12:47:33 +00006119 flags = parameters[i].flags;
6120 /* Find width */
6121 width = parameters[i].width;
6122 if (flags & FLAGS_WIDTH_PARAMETER)
6123 {
6124 /* Get width from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00006125 width = (int)parameters[width].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006126 }
6127 /* Find base */
6128 base = parameters[i].base;
6129 if (flags & FLAGS_BASE_PARAMETER)
6130 {
6131 /* Get base from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00006132 base = (int)parameters[base].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006133 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006134
Daniel Veillard92ad2102001-03-27 12:47:33 +00006135 switch (parameters[i].type)
6136 {
6137 case FORMAT_INT:
6138 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006139 trio_uintmax_t number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006140
6141 if (0 == base)
6142 base = BASE_DECIMAL;
6143
6144 if (!TrioReadNumber(data,
6145 &number,
6146 flags,
6147 width,
6148 base))
6149 return assignment;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006150
Daniel Veillard92ad2102001-03-27 12:47:33 +00006151 if (!(flags & FLAGS_IGNORE))
6152 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006153 assignment++;
6154
Daniel Veillard92ad2102001-03-27 12:47:33 +00006155 pointer = parameters[i].data.pointer;
6156#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
6157 if (flags & FLAGS_SIZE_T)
6158 *(size_t *)pointer = (size_t)number;
6159 else
6160#endif
6161#if defined(QUALIFIER_PTRDIFF_T)
6162 if (flags & FLAGS_PTRDIFF_T)
6163 *(ptrdiff_t *)pointer = (ptrdiff_t)number;
6164 else
6165#endif
6166#if defined(QUALIFIER_INTMAX_T)
6167 if (flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006168 *(trio_intmax_t *)pointer = (trio_intmax_t)number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006169 else
6170#endif
6171 if (flags & FLAGS_QUAD)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006172 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006173 else if (flags & FLAGS_LONG)
6174 *(long int *)pointer = (long int)number;
6175 else if (flags & FLAGS_SHORT)
6176 *(short int *)pointer = (short int)number;
6177 else
6178 *(int *)pointer = (int)number;
6179 }
6180 }
6181 break; /* FORMAT_INT */
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006182
Daniel Veillard92ad2102001-03-27 12:47:33 +00006183 case FORMAT_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006184#if TRIO_WIDECHAR
6185 if (flags & FLAGS_WIDECHAR)
6186 {
6187 if (!TrioReadWideString(data,
6188 (flags & FLAGS_IGNORE)
6189 ? NULL
6190 : parameters[i].data.wstring,
6191 flags,
6192 width))
6193 return assignment;
6194 }
6195 else
6196#endif
6197 {
6198 if (!TrioReadString(data,
6199 (flags & FLAGS_IGNORE)
6200 ? NULL
6201 : parameters[i].data.string,
6202 flags,
6203 width))
6204 return assignment;
6205 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006206 if (!(flags & FLAGS_IGNORE))
6207 assignment++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006208 break; /* FORMAT_STRING */
Daniel Veillard92ad2102001-03-27 12:47:33 +00006209
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006210 case FORMAT_DOUBLE:
6211 {
6212 trio_pointer_t pointer;
6213
6214 if (flags & FLAGS_IGNORE)
6215 {
6216 pointer = NULL;
6217 }
6218 else
6219 {
6220 pointer = (flags & FLAGS_LONGDOUBLE)
6221 ? (trio_pointer_t)parameters[i].data.longdoublePointer
6222 : (trio_pointer_t)parameters[i].data.doublePointer;
6223 }
6224 if (!TrioReadDouble(data, pointer, flags, width))
6225 {
6226 return assignment;
6227 }
6228 if (!(flags & FLAGS_IGNORE))
6229 {
6230 assignment++;
6231 }
6232 break; /* FORMAT_DOUBLE */
6233 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00006234 case FORMAT_GROUP:
6235 {
6236 int characterclass[MAX_CHARACTER_CLASS + 1];
6237 int rc;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006238
6239 /* Skip over modifiers */
6240 while (format[index] != SPECIFIER_GROUP)
6241 {
6242 index++;
6243 }
6244 /* Skip over group specifier */
6245 index++;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006246
Daniel Veillard92ad2102001-03-27 12:47:33 +00006247 memset(characterclass, 0, sizeof(characterclass));
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006248 rc = TrioGetCharacterClass(format,
6249 &index,
6250 &flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00006251 characterclass);
6252 if (rc < 0)
6253 return rc;
6254
6255 if (!TrioReadGroup(data,
6256 (flags & FLAGS_IGNORE)
6257 ? NULL
6258 : parameters[i].data.string,
6259 characterclass,
6260 flags,
6261 parameters[i].width))
6262 return assignment;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006263 if (!(flags & FLAGS_IGNORE))
6264 assignment++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006265 }
6266 break; /* FORMAT_GROUP */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006267
Daniel Veillard92ad2102001-03-27 12:47:33 +00006268 case FORMAT_COUNT:
6269 pointer = parameters[i].data.pointer;
6270 if (NULL != pointer)
6271 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006272 int count = data->committed;
6273 if (ch != EOF)
6274 count--; /* a character is read, but is not consumed yet */
Daniel Veillard92ad2102001-03-27 12:47:33 +00006275#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
6276 if (flags & FLAGS_SIZE_T)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006277 *(size_t *)pointer = (size_t)count;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006278 else
6279#endif
6280#if defined(QUALIFIER_PTRDIFF_T)
6281 if (flags & FLAGS_PTRDIFF_T)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006282 *(ptrdiff_t *)pointer = (ptrdiff_t)count;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006283 else
6284#endif
6285#if defined(QUALIFIER_INTMAX_T)
6286 if (flags & FLAGS_INTMAX_T)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006287 *(trio_intmax_t *)pointer = (trio_intmax_t)count;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006288 else
6289#endif
6290 if (flags & FLAGS_QUAD)
6291 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006292 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)count;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006293 }
6294 else if (flags & FLAGS_LONG)
6295 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006296 *(long int *)pointer = (long int)count;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006297 }
6298 else if (flags & FLAGS_SHORT)
6299 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006300 *(short int *)pointer = (short int)count;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006301 }
6302 else
6303 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006304 *(int *)pointer = (int)count;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006305 }
6306 }
6307 break; /* FORMAT_COUNT */
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006308
Daniel Veillard92ad2102001-03-27 12:47:33 +00006309 case FORMAT_CHAR:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006310#if TRIO_WIDECHAR
6311 if (flags & FLAGS_WIDECHAR)
6312 {
6313 if (TrioReadWideChar(data,
6314 (flags & FLAGS_IGNORE)
6315 ? NULL
6316 : parameters[i].data.wstring,
6317 flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006318 (width == NO_WIDTH) ? 1 : width) == 0)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006319 return assignment;
6320 }
6321 else
6322#endif
6323 {
6324 if (TrioReadChar(data,
6325 (flags & FLAGS_IGNORE)
6326 ? NULL
6327 : parameters[i].data.string,
6328 flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006329 (width == NO_WIDTH) ? 1 : width) == 0)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006330 return assignment;
6331 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006332 if (!(flags & FLAGS_IGNORE))
6333 assignment++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006334 break; /* FORMAT_CHAR */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006335
Daniel Veillard92ad2102001-03-27 12:47:33 +00006336 case FORMAT_POINTER:
6337 if (!TrioReadPointer(data,
6338 (flags & FLAGS_IGNORE)
6339 ? NULL
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006340 : (trio_pointer_t *)parameters[i].data.pointer,
Daniel Veillard92ad2102001-03-27 12:47:33 +00006341 flags))
6342 return assignment;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006343 if (!(flags & FLAGS_IGNORE))
6344 assignment++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006345 break; /* FORMAT_POINTER */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006346
Daniel Veillard92ad2102001-03-27 12:47:33 +00006347 case FORMAT_PARAMETER:
6348 break; /* FORMAT_PARAMETER */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006349
Daniel Veillard92ad2102001-03-27 12:47:33 +00006350 default:
6351 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
6352 }
6353 ch = data->current;
6354 index = parameters[i].indexAfterSpecifier;
6355 i++;
6356 }
6357 else /* Not an % identifier */
6358 {
6359 if (isspace((int)format[index]))
6360 {
6361 /* Whitespaces may match any amount of whitespaces */
6362 ch = TrioSkipWhitespaces(data);
6363 }
6364 else if (ch == format[index])
6365 {
6366 data->InStream(data, &ch);
6367 }
6368 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00006369 return assignment;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006370
Daniel Veillard92ad2102001-03-27 12:47:33 +00006371 index++;
6372 }
6373 }
6374 return assignment;
6375}
6376
6377/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00006378 * TrioScan
Daniel Veillard92ad2102001-03-27 12:47:33 +00006379 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006380TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006381TrioScan
6382TRIO_ARGS6((source, sourceSize, InStream, format, arglist, argarray),
6383 trio_pointer_t source,
6384 size_t sourceSize,
6385 void (*InStream) TRIO_PROTO((trio_class_t *, int *)),
6386 TRIO_CONST char *format,
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08006387 TRIO_VA_LIST_PTR arglist,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006388 trio_pointer_t *argarray)
Bjorn Reese026d29f2002-01-19 15:40:18 +00006389{
6390 int status;
6391 trio_parameter_t parameters[MAX_PARAMETERS];
6392 trio_class_t data;
6393
6394 assert(VALID(InStream));
6395 assert(VALID(format));
6396
6397 memset(&data, 0, sizeof(data));
6398 data.InStream = InStream;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006399 data.location = (trio_pointer_t)source;
Bjorn Reese026d29f2002-01-19 15:40:18 +00006400 data.max = sourceSize;
6401 data.error = 0;
6402
6403#if defined(USE_LOCALE)
6404 if (NULL == internalLocaleValues)
6405 {
6406 TrioSetLocale();
6407 }
6408#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006409
Bjorn Reese026d29f2002-01-19 15:40:18 +00006410 status = TrioParse(TYPE_SCAN, format, parameters, arglist, argarray);
6411 if (status < 0)
6412 return status;
6413
6414 status = TrioScanProcess(&data, format, parameters);
6415 if (data.error != 0)
6416 {
6417 status = data.error;
6418 }
6419 return status;
6420}
6421
6422/*************************************************************************
6423 * TrioInStreamFile
6424 */
6425TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006426TrioInStreamFile
6427TRIO_ARGS2((self, intPointer),
6428 trio_class_t *self,
6429 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006430{
6431 FILE *file = (FILE *)self->location;
6432
6433 assert(VALID(self));
6434 assert(VALID(file));
6435
6436 self->current = fgetc(file);
Bjorn Reese026d29f2002-01-19 15:40:18 +00006437 if (self->current == EOF)
6438 {
6439 self->error = (ferror(file))
6440 ? TRIO_ERROR_RETURN(TRIO_ERRNO, 0)
6441 : TRIO_ERROR_RETURN(TRIO_EOF, 0);
6442 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006443 else
6444 {
6445 self->processed++;
6446 self->committed++;
6447 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006448
Daniel Veillard92ad2102001-03-27 12:47:33 +00006449 if (VALID(intPointer))
6450 {
6451 *intPointer = self->current;
6452 }
6453}
6454
6455/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00006456 * TrioInStreamFileDescriptor
Daniel Veillard92ad2102001-03-27 12:47:33 +00006457 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006458TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006459TrioInStreamFileDescriptor
6460TRIO_ARGS2((self, intPointer),
6461 trio_class_t *self,
6462 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006463{
6464 int fd = *((int *)self->location);
6465 int size;
6466 unsigned char input;
6467
6468 assert(VALID(self));
6469
6470 size = read(fd, &input, sizeof(char));
Bjorn Reese026d29f2002-01-19 15:40:18 +00006471 if (size == -1)
6472 {
6473 self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0);
6474 self->current = EOF;
6475 }
6476 else
6477 {
6478 self->current = (size == 0) ? EOF : input;
6479 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006480 if (self->current != EOF)
6481 {
6482 self->committed++;
6483 self->processed++;
6484 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006485
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006486 if (VALID(intPointer))
6487 {
6488 *intPointer = self->current;
6489 }
6490}
6491
6492/*************************************************************************
6493 * TrioInStreamCustom
6494 */
6495TRIO_PRIVATE void
6496TrioInStreamCustom
6497TRIO_ARGS2((self, intPointer),
6498 trio_class_t *self,
6499 int *intPointer)
6500{
6501 trio_custom_t *data;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006502
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006503 assert(VALID(self));
6504 assert(VALID(self->location));
6505
6506 data = (trio_custom_t *)self->location;
6507
6508 self->current = (data->stream.in == NULL)
6509 ? NIL
6510 : (data->stream.in)(data->closure);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006511
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006512 if (self->current == NIL)
6513 {
6514 self->current = EOF;
6515 }
6516 else
6517 {
6518 self->processed++;
6519 self->committed++;
6520 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006521
Daniel Veillard92ad2102001-03-27 12:47:33 +00006522 if (VALID(intPointer))
6523 {
6524 *intPointer = self->current;
6525 }
6526}
6527
6528/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00006529 * TrioInStreamString
Daniel Veillard92ad2102001-03-27 12:47:33 +00006530 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006531TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006532TrioInStreamString
6533TRIO_ARGS2((self, intPointer),
6534 trio_class_t *self,
6535 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006536{
6537 unsigned char **buffer;
6538
6539 assert(VALID(self));
Daniel Veillard92ad2102001-03-27 12:47:33 +00006540 assert(VALID(self->location));
6541
6542 buffer = (unsigned char **)self->location;
6543 self->current = (*buffer)[0];
6544 if (self->current == NIL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006545 {
6546 self->current = EOF;
6547 }
6548 else
6549 {
6550 (*buffer)++;
6551 self->processed++;
6552 self->committed++;
6553 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006554
Daniel Veillard92ad2102001-03-27 12:47:33 +00006555 if (VALID(intPointer))
6556 {
6557 *intPointer = self->current;
6558 }
6559}
6560
6561/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00006562 *
6563 * Formatted scanning functions
6564 *
6565 ************************************************************************/
6566
6567#if defined(TRIO_DOCUMENTATION)
6568# include "doc/doc_scanf.h"
6569#endif
6570/** @addtogroup Scanf
6571 @{
6572*/
6573
6574/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00006575 * scanf
Daniel Veillard92ad2102001-03-27 12:47:33 +00006576 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006577
6578/**
6579 Scan characters from standard input stream.
6580
6581 @param format Formatting string.
6582 @param ... Arguments.
6583 @return Number of scanned characters.
6584 */
6585TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006586trio_scanf
6587TRIO_VARGS2((format, va_alist),
6588 TRIO_CONST char *format,
6589 TRIO_VA_DECL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006590{
6591 int status;
6592 va_list args;
6593
6594 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006595
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006596 TRIO_VA_START(args, format);
6597 status = TrioScan((trio_pointer_t)stdin, 0,
6598 TrioInStreamFile,
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08006599 format, TRIO_VA_LIST_ADDR(args), NULL);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006600 TRIO_VA_END(args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006601 return status;
6602}
6603
Bjorn Reese026d29f2002-01-19 15:40:18 +00006604TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006605trio_vscanf
6606TRIO_ARGS2((format, args),
6607 TRIO_CONST char *format,
6608 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006609{
6610 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006611
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006612 return TrioScan((trio_pointer_t)stdin, 0,
6613 TrioInStreamFile,
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08006614 format, TRIO_VA_LIST_ADDR(args), NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006615}
6616
Bjorn Reese026d29f2002-01-19 15:40:18 +00006617TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006618trio_scanfv
6619TRIO_ARGS2((format, args),
6620 TRIO_CONST char *format,
6621 trio_pointer_t *args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006622{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006623 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006624
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006625 return TrioScan((trio_pointer_t)stdin, 0,
6626 TrioInStreamFile,
6627 format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006628}
6629
6630/*************************************************************************
6631 * fscanf
6632 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006633TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006634trio_fscanf
6635TRIO_VARGS3((file, format, va_alist),
6636 FILE *file,
Bjorn Reese026d29f2002-01-19 15:40:18 +00006637 TRIO_CONST char *format,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006638 TRIO_VA_DECL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006639{
6640 int status;
6641 va_list args;
6642
6643 assert(VALID(file));
6644 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006645
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006646 TRIO_VA_START(args, format);
6647 status = TrioScan((trio_pointer_t)file, 0,
6648 TrioInStreamFile,
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08006649 format, TRIO_VA_LIST_ADDR(args), NULL);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006650 TRIO_VA_END(args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006651 return status;
6652}
6653
Bjorn Reese026d29f2002-01-19 15:40:18 +00006654TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006655trio_vfscanf
6656TRIO_ARGS3((file, format, args),
6657 FILE *file,
6658 TRIO_CONST char *format,
6659 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006660{
6661 assert(VALID(file));
6662 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006663
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006664 return TrioScan((trio_pointer_t)file, 0,
6665 TrioInStreamFile,
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08006666 format, TRIO_VA_LIST_ADDR(args), NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006667}
6668
Bjorn Reese026d29f2002-01-19 15:40:18 +00006669TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006670trio_fscanfv
6671TRIO_ARGS3((file, format, args),
6672 FILE *file,
6673 TRIO_CONST char *format,
6674 trio_pointer_t *args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006675{
6676 assert(VALID(file));
6677 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006678
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006679 return TrioScan((trio_pointer_t)file, 0,
6680 TrioInStreamFile,
6681 format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006682}
6683
6684/*************************************************************************
6685 * dscanf
6686 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006687TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006688trio_dscanf
6689TRIO_VARGS3((fd, format, va_alist),
6690 int fd,
Bjorn Reese026d29f2002-01-19 15:40:18 +00006691 TRIO_CONST char *format,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006692 TRIO_VA_DECL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006693{
6694 int status;
6695 va_list args;
6696
6697 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006698
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006699 TRIO_VA_START(args, format);
6700 status = TrioScan((trio_pointer_t)&fd, 0,
6701 TrioInStreamFileDescriptor,
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08006702 format, TRIO_VA_LIST_ADDR(args), NULL);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006703 TRIO_VA_END(args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006704 return status;
6705}
6706
Bjorn Reese026d29f2002-01-19 15:40:18 +00006707TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006708trio_vdscanf
6709TRIO_ARGS3((fd, format, args),
6710 int fd,
6711 TRIO_CONST char *format,
6712 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006713{
6714 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006715
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006716 return TrioScan((trio_pointer_t)&fd, 0,
6717 TrioInStreamFileDescriptor,
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08006718 format, TRIO_VA_LIST_ADDR(args), NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006719}
6720
Bjorn Reese026d29f2002-01-19 15:40:18 +00006721TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006722trio_dscanfv
6723TRIO_ARGS3((fd, format, args),
6724 int fd,
6725 TRIO_CONST char *format,
6726 trio_pointer_t *args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006727{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006728 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006729
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006730 return TrioScan((trio_pointer_t)&fd, 0,
6731 TrioInStreamFileDescriptor,
6732 format, NULL, args);
6733}
6734
6735/*************************************************************************
6736 * cscanf
6737 */
6738TRIO_PUBLIC int
6739trio_cscanf
6740TRIO_VARGS4((stream, closure, format, va_alist),
6741 trio_instream_t stream,
6742 trio_pointer_t closure,
6743 TRIO_CONST char *format,
6744 TRIO_VA_DECL)
6745{
6746 int status;
6747 va_list args;
6748 trio_custom_t data;
6749
6750 assert(VALID(stream));
6751 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006752
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006753 TRIO_VA_START(args, format);
6754 data.stream.in = stream;
6755 data.closure = closure;
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08006756 status = TrioScan(&data, 0, TrioInStreamCustom, format, TRIO_VA_LIST_ADDR(args), NULL);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006757 TRIO_VA_END(args);
6758 return status;
6759}
6760
6761TRIO_PUBLIC int
6762trio_vcscanf
6763TRIO_ARGS4((stream, closure, format, args),
6764 trio_instream_t stream,
6765 trio_pointer_t closure,
6766 TRIO_CONST char *format,
6767 va_list args)
6768{
6769 trio_custom_t data;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006770
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006771 assert(VALID(stream));
6772 assert(VALID(format));
6773
6774 data.stream.in = stream;
6775 data.closure = closure;
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08006776 return TrioScan(&data, 0, TrioInStreamCustom, format, TRIO_VA_LIST_ADDR(args), NULL);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006777}
6778
6779TRIO_PUBLIC int
6780trio_cscanfv
6781TRIO_ARGS4((stream, closure, format, args),
6782 trio_instream_t stream,
6783 trio_pointer_t closure,
6784 TRIO_CONST char *format,
6785 trio_pointer_t *args)
6786{
6787 trio_custom_t data;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006788
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006789 assert(VALID(stream));
6790 assert(VALID(format));
6791
6792 data.stream.in = stream;
6793 data.closure = closure;
6794 return TrioScan(&data, 0, TrioInStreamCustom, format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006795}
6796
6797/*************************************************************************
6798 * sscanf
6799 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006800TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006801trio_sscanf
6802TRIO_VARGS3((buffer, format, va_alist),
6803 TRIO_CONST char *buffer,
Bjorn Reese026d29f2002-01-19 15:40:18 +00006804 TRIO_CONST char *format,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006805 TRIO_VA_DECL)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006806{
6807 int status;
6808 va_list args;
6809
6810 assert(VALID(buffer));
6811 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006812
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006813 TRIO_VA_START(args, format);
6814 status = TrioScan((trio_pointer_t)&buffer, 0,
6815 TrioInStreamString,
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08006816 format, TRIO_VA_LIST_ADDR(args), NULL);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006817 TRIO_VA_END(args);
Daniel Veillard92ad2102001-03-27 12:47:33 +00006818 return status;
6819}
6820
Bjorn Reese026d29f2002-01-19 15:40:18 +00006821TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006822trio_vsscanf
6823TRIO_ARGS3((buffer, format, args),
6824 TRIO_CONST char *buffer,
6825 TRIO_CONST char *format,
6826 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006827{
6828 assert(VALID(buffer));
6829 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006830
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006831 return TrioScan((trio_pointer_t)&buffer, 0,
6832 TrioInStreamString,
Patrick Monnerat0f7a26d2013-12-12 15:04:43 +08006833 format, TRIO_VA_LIST_ADDR(args), NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006834}
6835
Bjorn Reese026d29f2002-01-19 15:40:18 +00006836TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006837trio_sscanfv
6838TRIO_ARGS3((buffer, format, args),
6839 TRIO_CONST char *buffer,
6840 TRIO_CONST char *format,
6841 trio_pointer_t *args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006842{
6843 assert(VALID(buffer));
6844 assert(VALID(format));
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006845
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006846 return TrioScan((trio_pointer_t)&buffer, 0,
6847 TrioInStreamString,
6848 format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006849}
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006850
Bjorn Reese026d29f2002-01-19 15:40:18 +00006851/** @} End of Scanf documentation module */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006852
6853/*************************************************************************
6854 * trio_strerror
6855 */
6856TRIO_PUBLIC TRIO_CONST char *
6857trio_strerror
6858TRIO_ARGS1((errorcode),
6859 int errorcode)
6860{
6861 /* Textual versions of the error codes */
6862 switch (TRIO_ERROR_CODE(errorcode))
6863 {
6864 case TRIO_EOF:
6865 return "End of file";
6866 case TRIO_EINVAL:
6867 return "Invalid argument";
6868 case TRIO_ETOOMANY:
6869 return "Too many arguments";
6870 case TRIO_EDBLREF:
6871 return "Double reference";
6872 case TRIO_EGAP:
6873 return "Reference gap";
6874 case TRIO_ENOMEM:
6875 return "Out of memory";
6876 case TRIO_ERANGE:
6877 return "Invalid range";
6878 case TRIO_ECUSTOM:
6879 return "Custom error";
6880 default:
6881 return "Unknown";
6882 }
6883}